Skip to content

可观测性:分布式链路追踪

📖 简介

分布式链路跟踪(Distributed Tracing)是可观测性(Observability) 的核心组成部分之一,用于在复杂的分布式系统(如微服务、Serverless、Service Mesh 等架构)中追踪一个用户请求从入口到出口所经过的所有服务调用路径,从而帮助开发者和运维人员快速定位性能瓶颈、错误根源和依赖关系。

🤔 为什么需要分布式链路跟踪?

在单体应用时代,一次请求只在一个进程中处理,日志集中、调试简单。
但在微服务架构下:

  • 一个请求可能经过 10+ 个服务(如:API Gateway → Auth认证服务 → Order订单服务 → Payment支付服务 → Inventory库存服务 → Notification通知服务)
  • 每个服务部署在不同主机、容器或区域
  • 错误可能由某个中间服务的超时、异常或网络问题引起

此时,仅靠日志难以还原完整调用链。分布式链路跟踪通过“上下文传播”将分散的调用片段串联成完整的轨迹

核心概念

分布式链路追踪通过为每个请求生成唯一的 Trace ID,并在该请求穿越各个服务时传播此 ID,从而将整个调用链上的所有操作串联起来。每个服务在处理请求时会记录一个或多个 Span(表示一次操作或子操作),这些 Span 按照父子关系组织成一棵树,构成完整的 Trace

  • Trace(追踪):代表一次端到端完整的用户请求,由多个 Span 组成。例如:“用户下单”是一个 Trace。
  • Span(跨度):表示 Trace 中的一个工作单元,如一次 RPC 调用、数据库查询、函数执行。每个 Span 有开始/结束时间、操作名、标签等。
  • Trace ID:全局唯一 ID,标识整个请求链路。所有相关 Span 共享同一个 Trace ID。
  • Span ID:当前 Span 的唯一 ID。
  • Parent Span ID:父 Span 的 ID,用于构建调用树结构。根 Span 的 Parent ID 为空
  • 上下文传播(Context Propagation):确保 Trace ID 和 Span ID 在服务间正确传递(通常通过 HTTP Header、消息头等)。

⚙️ 工作原理简述

  1. 请求入口(如网关)生成全局唯一的 Trace ID 和第一个 Span
  2. 调用下游服务时,将 Trace ID、当前 Span ID 作为 Parent Span ID,通过协议(如 HTTP Header traceparent)传递。
  3. 下游服务接收到请求后,创建自己的 Span,并记录与父 Span 的关系。
  4. 所有 Span 数据被上报到中央追踪系统(如 Jaeger、Zipkin)。
  5. 系统根据 Trace ID 聚合所有 Span,重建调用树,并可视化展示(甘特图形式)。

例如,一个简单的调用链可能如下所示:

bash
trace_id: a1b2              # 整个下单请求的唯一标识
├─ 用户服务:接收下单请求       # trace_id: a1b2, span_id: a1, parent_span_id: None 
  └─ 调用订单服务:创建订单    # trace_id: a1b2, span_id: b1, parent_span_id: a1
     ├─ 订单服务:查询用户信息 # trace_id: a1b2, span_id: c1, parent_span_id: b1
     └─ 订单服务:调用支付服务 # trace_id: a1b2, span_id: c2, parent_span_id: b1
└─ 用户服务:返回下单结果       # trace_id: a1b2, span_id: b2, parent_span_id: a1

Trace ID: a1b2c3d4...

├── Span A (user-service: receive order)
   ├── Span B (order-service: create order)
   ├── Span C (user-service: get user info)
   └── Span D (payment-service: process payment) ← 耗时 800ms
   └── Span E (user-service: return response)
  • 同一个请求链路中,所有span的 trace_id 都相同;
  • 每个span有独立的 span_id,通过 parent_span_id 关联上下游,形成完整的调用树;
  • 每个span记录自己的操作耗时,能快速定位链路中的性能瓶颈(比如c2耗时过长,说明支付服务慢)。

⭐ 最佳实践

  1. 全链路注入上下文 (Trace Context)

    在请求入口(如 API 网关)生成全局唯一的 trace_id,并通过以下方式传播:

    • HTTP: 使用 traceparent(W3C 标准)Header
    • gRPC: 通过 Metadata 传递
    • 消息队列(Kafka/RabbitMQ):在消息头中携带上下文

    通过这个方式可以在所有下游服务中透传,便于跨服务日志追踪。

  2. 结构化日志格式(如 JSON)

    json
    {
       "timestamp": "2026-01-17T15:30:00Z", // 使用 ISO 8601 格式并带时区
       "level": "INFO",
       "service": "order-service",
       "trace_id": "abc123xyz",
       "span_id": "span456def",
       "message": "Order created successfully",
       "user_id": "u1001"
    }
  3. 日志采样与分级

    • 生产环境避免记录过多 DEBUG 日志。
    • 对高频日志可采用采样策略,防止日志系统过载。
  4. 安全与合规

    • 敏感信息(如密码、身份证号)应脱敏。
    • 日志保留策略需符合 GDPR 等法规。

主流分布式链路追踪系统对比

方案特点协议支持可视化适用场景
JaegerCNCF 毕业项目,高性能,支持自适应采样OpenTracing / OpenTelemetry内置 UI,支持依赖图、甘特图微服务、K8s、大规模部署
Zipkin轻量,由 Twitter 开源,生态成熟Brave (Java), Zipkin API简洁 UI,支持服务依赖图中小型系统,快速集成
OpenTelemetry Collector + Backend厂商中立,统一标准,未来主流OpenTelemetry Protocol (OTLP)需搭配 Jaeger/Tempo/Grafana新项目首选,长期兼容性好
Grafana Tempo与 Grafana 深度集成,存储成本低OTLP, Jaeger, ZipkinGrafana 内嵌 Trace 查看云原生、已使用 Grafana 的团队