
上一篇【第28篇】生产者消费者协同——DataCarrier线程模型全解析下一篇【第30篇】SkyWalking追踪模型深度解析——三层架构的独特设计1. 引言一切都始于一篇论文2010年Google发表了一篇名叫《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》的论文。这篇论文对分布式追踪领域的影响相当于《独立宣言》对美国的影响——它定义了后来所有分布式追踪系统的基础概念和架构范式。今天你可能用SkyWalking、Zipkin或Jaeger但它们的基因都可以追溯到这篇论文。不懂Dapper就理解不了为什么Trace长这样、Span为什么这么命名、采样率为什么不能是100%。本文带你精读Dapper论文的核心思想建立一个扎实的理论基础。2. Dapper论文核心思想2.1 为什么需要分布式追踪论文开篇就说了一个简单的事实Google的一个搜索请求可能涉及数百个微服务、数千台机器。当用户说搜索好慢时你找谁------------------------------------------------------------------ | Google搜索请求的简化调用链 | ------------------------------------------------------------------ | | | user: golang tutorial | | │ | | ▼ | | [Frontend Server] | | │ | | ├──→ [Spell Checker] ──── golang → Go language | | │ | | ├──→ [Web Search] | | │ ├──→ [Index Server] | | │ │ ├──→ [Index Shard 1] | | │ │ ├──→ [Index Shard 2] | | │ │ └──→ [Index Shard 3] | | │ └──→ [Ad Server] | | │ └──→ [Ad Database] ← 这里超时了 | | │ | | ├──→ [Image Search] | | └──→ [News Search] | | | | 问题: 哪个服务慢了 | | 如果没有追踪系统你可能要查几十台机器的日志。 | ------------------------------------------------------------------Dapper的目标就两个词性能分析和故障定位。2.2 三大核心概念Dapper定义了分布式追踪的三个基本概念------------------------------------------------------------------ | Dapper核心概念Trace Tree | ------------------------------------------------------------------ | | | Trace (追踪) | | ┌──────────────────────────────────────────────────────────┐ | | │ Trace ID: 7b2a8f1d9e3c │ | | │ 所有Span共享同一个Trace ID构成一条完整调用链 │ | | │ │ | | │ Tree Structure: │ | | │ │ | | │ [A]──────────────── Root Span (最外层) │ | | │ │ Span ID 1 │ | | │ │ Parent Span ID None │ | | │ │ │ | | │ ├── [B]────────────── Child Span │ | | │ │ │ Span ID 2 │ | | │ │ │ Parent Span ID 1 │ | | │ │ │ │ | | │ │ ├── [C]──────── Child Span │ | | │ │ │ Span ID 3 │ | | │ │ │ Parent Span ID 2 │ | | │ │ │ │ | | │ │ └── [D]──────── Child Span │ | | │ │ Span ID 4 │ | | │ │ Parent Span ID 2 │ | | │ │ │ | | │ └── [E]────────────── Child Span │ | | │ Span ID 5 │ | | │ Parent Span ID 1 │ | | └──────────────────────────────────────────────────────────┘ | ------------------------------------------------------------------三大概念的定义概念定义类比Trace一次分布式调用的完整路径由Span树组成一本小说的目录Span一次RPC调用的起止时间、名称和元数据小说中的一个章节AnnotationSpan上的时间点标记客户端发送/服务端接收等章节中插入的注解2.3 Span的树形结构Dapper论文中的Span模型是树形结构——每个Span都有一个父Span。这种设计有天然的优点------------------------------------------------------------------ | Span树 vs Span列表 vs Span DAG | ------------------------------------------------------------------ | | | ① 树形结构 (Dapper选择) | | ┌──────────────────────────────────────────────────┐ │ | │ [A] │ │ | │ / \ │ │ | │ [B] [E] │ │ | │ / \ │ │ | │ [C] [D] │ │ | │ │ │ | │ 优点: 天然的父子关系因果清晰 │ │ | │ 缺点: 不能表达多对多关系 │ │ | └──────────────────────────────────────────────────┘ │ | | | ② DAG结构 (有向无环图) | | ┌──────────────────────────────────────────────────┐ │ | │ [A] │ │ | │ / \ │ │ | │ [B] → [C] ← B也调C, D也调C │ │ | │ \ / │ │ | │ [D] │ │ | │ │ │ | │ 优点: 更灵活表达力更强 │ │ | │ 缺点: 复杂度上升存储和查询都更难 │ │ | └──────────────────────────────────────────────────┘ │ ------------------------------------------------------------------Dapper选择树形结构是一个务实的简化——在绝大多数场景下RPC调用天然是树形的一次调用产生一次响应DAG结构的额外复杂性不值得。3. 抽样策略的权衡3.1 为什么不100%采样“如果我想看到所有请求的Trace为什么不全部采样”——这是新人最常见的问题。论文给出了几个硬核数据Google的数据中心每秒产生数十亿个Span如果全部采样和存储需要的存储空间是PB级别采样率从100%降到0.1%Trace质量几乎没有下降对于性能分析而言------------------------------------------------------------------ | 采样率 vs 存储成本 vs 分析价值 | ------------------------------------------------------------------ | | | 采样率 │ 存储需求 │ 分析价值 │ 适用场景| ------------------------------------------------------------------ | 100% │ 极高(PB级) │ 完美(但浪费) │ 调试 | | 10% │ 高(TB级) │ 统计准确 │ 性能分析| | 1% │ 中(GB级) │ 统计仍可靠 │ 日常监控| | 0.1% │ 低(MB级) │ 长尾可见Top问题可见 │ 容量规划| | 0.01% │ 极低(KB级) │ 仅见极端问题 │ 几乎不用| | | | Dapper的实践: 1/1024 ≈ 0.1% 采样率 | | SkyWalking的实践: 默认100%采样因为Agent端做了数据聚合 | ------------------------------------------------------------------3.2 自适应采样策略Dapper使用了自适应采样——不是随机抽样而是根据以下因素动态调整# Dapper采样策略的伪代码defshould_sample(span):# 1. 高优先级强制采样ifspan.has_error():returnTrue# 出错的请求100%采样ifspan.latencyp99_latency:returnTrue# 异常慢的请求100%采样# 2. 低延迟请求的低固定采样ifspan.latency10:# 小于10ms的请求returnrandom()0.001# 0.1%采样# 3. 正常请求的固定采样returnrandom()0.01# 1%采样这种策略的精妙之处在于正常工作流采样率低异常工作流采样率高——用最小的存储成本换取最大的问题发现能力。3.3 采样一致性问题RPC系统中有一个特殊的采样一致性问题------------------------------------------------------------------ ------------------------------------------------------------------ | 采样一致性问题 | ------------------------------------------------------------------ | | | 正常情况采样一致: | | ┌──────────────────────────────────────────────────┐ │ | │ Service-A (已采样) ──RPC──→ Service-B (已采样) │ │ | │ ✓ 整个Trace完整 │ │ | └──────────────────────────────────────────────────┘ │ | | | 异常情况采样不一致: | | ┌──────────────────────────────────────────────────┐ │ | │ Service-A (已采样) ──RPC──→ Service-B (未采样) │ │ | │ ✗ Trace断裂 │ │ | │ → A有TraceB没有 │ │ | │ → 你看到一个断掉的调用链 │ │ | └──────────────────────────────────────────────────┘ │ | | | Dapper的解决: Header传播采样标记 | | ┌──────────────────────────────────────────────────┐ │ | │ X-Dapper-Sampled: true/false │ │ | │ 下游服务读取这个Header一致性地决定是否采样 │ │ | └──────────────────────────────────────────────────┘ │ ------------------------------------------------------------------4. Dapper对后来者的影响4.1 共同继承Dapper的三大系统------------------------------------------------------------------ ------------------------------------------------------------------ | Dapper基因在三大APM系统中的传承 | ------------------------------------------------------------------ | | | ┌─────────────────────┐ │ | │ Google Dapper │ │ | │ (2010年论文) │ │ | └──────────┬──────────┘ │ | │ │ | ┌───────────────┼───────────────┐ │ | │ │ │ │ | ▼ ▼ ▼ │ | ┌────────────┐ ┌────────────┐ ┌────────────┐ │ | │ Zipkin │ │ Jaeger │ │ SkyWalking │ │ | │ (Twitter) │ │ (Uber) │ │ (Apache) │ │ | └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ | │ │ │ │ | ▼ ▼ ▼ │ | ┌──────────────────────────────────────────┐ │ | │ 共同特征: │ │ | │ • Trace/Span 概念模型 │ │ | │ • 树形调用结构 │ │ | │ • HTTP/gRPC Header 传播 │ │ | │ • 采样策略 │ │ | │ • 时间线可视化 │ │ | └──────────────────────────────────────────┘ │ ------------------------------------------------------------------4.2 各系统的差异化演进特性Dapper (论文)ZipkinJaegerSkyWalking数据收集应用内嵌SDK应用内嵌SDKOpenTracing SDKJava Agent字节码增强Span模型单层Span单层Span单层Span三层模型(Trace/TraceSegment/Span)传输协议Google内部HTTP/ThriftUDP/ThriftgRPC存储后端BigtableCassandra/ES/MySQLCassandra/ESES/MySQL/H2/BanyanDB侵入性需改代码需改代码需改代码零侵入(Agent)5. SkyWalking对Dapper模型的差异化设计5.1 Dapper的隐式的Span关系 vs SkyWalking的显式的ReferenceDapper通过Span之间的parent-child关系隐式建立调用链。SkyWalking则引入了Reference——显式记录Span之间的因果关系------------------------------------------------------------------ ------------------------------------------------------------------ | Dapper方式 (隐式): | | ┌──────────────────────────────────────────────────┐ │ | │ Span { │ │ | │ spanId: B, │ │ | │ parentSpanId: A ← 靠这个知道父亲是谁 │ │ | │ } │ │ | └──────────────────────────────────────────────────┘ │ | | | SkyWalking方式 (显式): | | ┌──────────────────────────────────────────────────┐ │ | │ Span { │ │ | │ spanId: 1, │ │ | │ refs: [ │ │ | │ { │ │ | │ parentSpanId: 0, ← 明确声明引用关系 │ │ | │ parentTraceSegmentId: xxx, │ │ | │ refType: CrossProcess ← 跨进程还是跨线程 │ │ | │ } │ │ | │ ] │ │ | │ } │ │ | └──────────────────────────────────────────────────┘ │ ------------------------------------------------------------------5.2 Dapper不处理的场景SkyWalking处理了Dapper论文中假设了一个纯RPC环境。但现实世界中同一个JVM进程内的方法调用也需要追踪不是RPC异步线程间的调用。消息队列MQ的发送和消费。数据库访问的追踪。缓存操作的追踪。SkyWalking的Agent通过字节码增强能捕获这些Dapper模型之外的信息这也是为什么SkyWalking要做三层模型Trace→TraceSegment→Span——下一篇文章会详细展开。5.3 设计理念的对比------------------------------------------------------------------ ------------------------------------------------------------------ | Dapper: 论文展示的理想模型 │ | ┌──────────────────────────────────────────────────┐ │ | │ • 关注分布式RPC的追踪 │ │ | │ • 需要业务代码显式集成 │ │ | │ • 采样策略是核心设计 │ │ | │ • 面向Google内部基础设施 │ │ | └──────────────────────────────────────────────────┘ │ | | | SkyWalking: 工程实践的务实方案 │ | ┌──────────────────────────────────────────────────┐ │ | │ • 关注任意调用的全链路追踪RPC/DB/MQ/Cache/...│ │ | │ • 零代码侵入Agent字节码增强 │ │ | │ • 性能极小影响是第一优先级 │ │ | │ • 面向开源社区的通用场景 │ │ | └──────────────────────────────────────────────────┘ │ ------------------------------------------------------------------6. Dapper论文的关键数据论文中引用了一些有意思的工程数据指标数值采样率1/1024 ≈ 0.1%平均Trace大小约10.5个Span最长Trace超过1000个Span数据收集延迟中位数15秒性能开销0.1%采样后对应用的影响存储开销0.01%的磁盘IO预算0.1%的采样率就能在Google的规模下提供足够的洞察力——这说明在超大规模分布式系统中全采样既不现实也没必要。7. 总结Dapper论文是分布式追踪领域的宪法Trace/Span/Annotation三大基础概念沿用至今树形模型简单但强大的调用链表示方式采样策略1/1024的采样率自适应优先采集异常被动影响催生了Zipkin、Jaeger、SkyWalking等系统SkyWalking站在Dapper的肩膀上做了三件Dapper没做的事字节码增强不需要改业务代码三层模型更细腻地表达进程内调用全链路覆盖不仅追踪RPC还追踪DB、Cache、MQ下一篇文章我们将深入SkyWalking的三层追踪模型看它如何用一个额外的TraceSegment层解决Dapper模型的不足。上一篇【第28篇】生产者消费者协同——DataCarrier线程模型全解析下一篇【第30篇】SkyWalking追踪模型深度解析——三层架构的独特设计