【可观测性工程】Traces 栈与采样:Jaeger、Tempo、Zipkin、SkyWalking

💡 原文中文,约5800字,阅读约需14分钟。
📝

内容提要

本文深入对比Jaeger、Tempo、SkyWalking等分布式追踪后端,分析其存储模型与架构取舍。核心强调采样策略(头部vs尾部)比后端选型更重要,并详解W3C TraceContext传播、OpenTelemetry tail_sampling配置及存储量估算。文章提供选型建议与工程坑点,指出组合采样策略是生产标准答案。

🔎

延伸解读

采样策略为何比后端选型更关键

文章指出,Trace 写入量是 Metrics 的几十到几百倍,全量存储不可规模化。头部采样虽省资源但不可逆,错误请求可能被丢弃;尾部采样能保留高价值 trace,但需缓冲和等待窗口。生产环境通常采用组合策略,如 errors OR slow OR 1% baseline,这比单纯选择 Jaeger 或 Tempo 更能控制成本与数据质量。

存储模型决定查询能力与成本

Jaeger 基于 Elasticsearch 全索引,支持毫秒级 tag 搜索,但存储成本高;Tempo 只索引 trace_id 和时间,通过 TraceQL 并行扫描对象存储,成本低但属性搜索弱。选型需权衡:强属性搜索选 Jaeger+ES,超大规模(>10B spans/day)选 Tempo,国内 APM 场景选 SkyWalking。

传播协议与工程坑点不容忽视

W3C TraceContext 是标准首选,但需注意 HTTP/2 头小写、网关可能剥离 trace headers,以及 Kafka/RabbitMQ 不自动传播。常见坑点包括 NTP 时钟偏移导致 skew 警告、循环内创建 span 引发 OOM、ES 动态 mapping 导致集群事故等,落地时需逐一排查。

Q&A

Jaeger、Tempo、SkyWalking 在存储模型上有什么区别?

Jaeger 默认使用 Elasticsearch,每个 span 作为一个文档并建立倒排索引,支持毫秒级 tag 搜索,但存储成本高;Tempo 只索引 trace_id、时间和少量 resource 属性,span attribute 不建倒排索引,数据以 Parquet 格式存储在对象存储中,通过 TraceQL 并行扫描 block 实现秒级查询,存储成本较低;SkyWalking 是 APM 平台,使用 Segment 模型和 OAP 分析层,存储支持 ES、BanyanDB、TiDB 等,提供服务拓扑、端点依赖等开箱即用功能。

为什么说采样策略比后端选型更重要?

因为 trace 写入量通常是 metrics 的几十到几百倍,全量存储不可规模化。例如在 10000 req/s、每请求 10 spans 的假设下,每天会产生 86.4 亿 spans,存储和查询成本极高。采样策略直接决定数据量和成本,而后端选型更多影响查询能力和存储成本。合理的采样策略(如组合采样)可以在保证高价值 trace 不丢失的前提下控制数据量,因此比后端选型更关键。

头部采样和尾部采样各有什么优缺点?

头部采样在入口根据 trace_id 哈希决策,通过 trace_flags 传播采样位,优点是零缓冲、各节点本地决策,缺点是不可逆,错误请求可能落在未采样分区。尾部采样由 Collector 缓冲完整 trace 后根据状态码或延迟等策略保留,优点是高价值 trace 不丢失,缺点是消耗内存、增加延迟,需要设置等待窗口。

如何配置 OpenTelemetry Collector 的 tail_sampling 处理器?

在 OTel Collector 配置中,通过 processors.tail_sampling 设置 decision_wait、num_traces、expected_new_traces_per_sec 和 policies。例如:decision_wait: 10s,num_traces: 100000,expected_new_traces_per_sec: 1000,policies 可包含 status_code(ERROR)、latency(阈值)和 probabilistic(采样百分比)等。生产环境常用组合策略:errors OR slow OR 1% baseline。注意 decision_wait 必须大于服务 p99 尾延迟,否则 span 未到齐会误判。

W3C TraceContext 和 B3 传播协议有什么区别?

W3C TraceContext 使用 traceparent 和 tracestate 头,是标准首选;B3 使用 X-B3-TraceId、X-B3-SpanId、X-B3-Sampled 等头,是 Zipkin 遗留协议。Jaeger 老客户端使用 uber-trace-id。在 OTel 中可通过 OTEL_PROPAGATORS 环境变量设置传播器,如 tracecontext,baggage,按需添加 b3。

在 Jaeger、Tempo、SkyWalking 之间如何选型?

如果使用 LGTM 全家桶(Loki、Grafana、Tempo、Mimir),推荐 Tempo;如果需要强 attribute 搜索,推荐 Jaeger + Elasticsearch;如果是国内 APM 开箱即用场景,推荐 SkyWalking;如果每天超过 100 亿 spans,推荐 Tempo;如果使用 OTel 多后端,可用 Collector 转发到任意后端。

使用分布式追踪系统时常见的工程坑点有哪些?

常见坑点包括:traceparent 在网关丢失;NTP 时钟不同步导致 clock skew 警告;循环内创建 span 导致 ingester OOM;ES 按天 index 分片过大;tail_sampling 的 num_traces 过小导致决策队列丢数据;头部 100% 采样加尾部重复保留导致存储翻倍;service.name 不一致导致拓扑断裂。

🏷️

标签

➡️

继续阅读