2、链路追踪基础:分布式追踪的核心概念与标准

好,咱们今天聊聊链路追踪的基础。说实话,我刚开始接触分布式系统时,最头疼的就是问题排查。一个请求发出去,经过七八个服务,到底卡在哪了?日志翻半天,头都大了。后来我才明白,这就是典型的「缺乏可观测性」——你根本不知道系统内部发生了什么。

链路追踪,说白了就是给每个请求发一张「通行证」,记录它走过的每一步。这张通行证上写着:你从哪来、到哪去、在每个服务里待了多久、有没有出问题。有了它,你就能把一次请求的完整路径还原出来。

2.1 核心概念:Trace、Span、SpanContext

这三个概念,是链路追踪的基石。我当年刚学的时候,觉得它们很抽象。后来在项目中亲手搭过一次,才真正理解。

2.1.1 Trace(追踪)

Trace 代表一次完整的请求链路。比如你在电商网站下单,这个操作会触发:前端 -> 网关 -> 订单服务 -> 库存服务 -> 支付服务 -> 通知服务。这一整条链路上的所有操作,都属于同一个 Trace。

每个 Trace 有一个全局唯一的 ID,叫 TraceID。我习惯用 UUID 或者 Snowflake 算法生成,保证分布式环境下不重复。

关键点:Trace 是树形结构,不是线性列表。一个 Trace 里可以有多个分支,比如并行调用多个服务。

2.1.2 Span(跨度)

Span 是 Trace 里的最小工作单元。每个 Span 代表一个服务内部的一次操作,比如「查询数据库」、「调用下游接口」、「执行一段业务逻辑」。

每个 Span 也有自己的 ID(SpanID),并且会记录它的父 Span ID(ParentSpanID)。这样就能把 Span 串起来,形成一棵调用树。

我记得有一次排查线上问题,发现某个接口响应特别慢。打开链路追踪一看,有个 Span 的耗时占了 80%。点进去发现是 Redis 查询超时了。嗯,这就是 Span 的价值——帮你精准定位瓶颈。

一个 Span 通常包含以下信息:

  • SpanID:当前 Span 的唯一标识
  • ParentSpanID:父 Span 的 ID,根 Span 没有父 ID
  • TraceID:所属 Trace 的 ID
  • OperationName:操作名称,比如 "query_user_info"
  • StartTime / EndTime:开始和结束时间
  • Tags:键值对,记录额外信息,比如 HTTP 状态码、数据库语句
  • Logs:事件日志,比如异常堆栈

2.1.3 SpanContext(跨度上下文)

SpanContext 是 Span 的「身份证」。它包含了 TraceID、SpanID 以及一些需要跨服务传递的 Baggage(行李)数据。

为什么需要 SpanContext?因为服务之间调用时,必须把当前 Trace 的信息传递过去,下游服务才能知道「我是哪个 Trace 的一部分」。传递方式通常是通过 HTTP 头(比如 uber-trace-id)或者消息队列的元数据。

避坑指南:我曾经遇到过一个坑——Baggage 数据传得太多,导致 HTTP 头过大,影响了性能。后来我严格控制 Baggage 的大小,只传必要的业务上下文,比如用户 ID、请求来源。

2.2 分布式追踪标准:OpenTracing 与 OpenTelemetry

早期链路追踪工具各搞各的,比如 Jaeger 有自己的 API,Zipkin 也有自己的。这就导致一个问题:你用了 Jaeger,想换成 SkyWalking,得改代码。说白了,就是缺乏统一标准。

后来社区开始推动标准化,出现了两个重要的项目:OpenTracing 和 OpenTelemetry。

2.2.1 OpenTracing

OpenTracing 是一个 API 规范,定义了如何创建 Span、如何传递 SpanContext、如何记录日志。它不关心底层实现,只提供接口。

举个例子,用 OpenTracing 的 API 创建一个 Span:

// 创建一个 tracer
Tracer tracer = new JaegerTracer.Builder("my-service").build();

// 创建一个 Span
Span span = tracer.buildSpan("query_database")
    .withTag("db.type", "mysql")
    .start();

// 执行操作
try {
    // 你的业务逻辑
} catch (Exception e) {
    span.log("error: " + e.getMessage());
} finally {
    span.finish();
}

你想想看,如果所有工具都遵循 OpenTracing,那么切换实现时只需要改一行配置,代码几乎不用动。这就是标准化的好处。

不过 OpenTracing 也有局限——它只定义了追踪的 API,没有涵盖指标和日志。而且它已经停止更新了,被 OpenTelemetry 取代。

2.2.2 OpenTelemetry

OpenTelemetry(简称 OTel)是 OpenTracing 和 OpenCensus 合并后的产物。它不只是做追踪,还涵盖了指标和日志,目标是成为可观测性的统一标准。

我个人觉得,OTel 最大的优势是「一次埋点,到处使用」。你只需要用 OTel 的 SDK 埋好点,数据可以导出到 Jaeger、Zipkin、Prometheus、Datadog 等任意后端。

用 OTel 创建一个 Span 的代码也很简洁:

// 获取 tracer
Tracer tracer = GlobalOpenTelemetry.getTracer("my-service");

// 创建 Span
Span span = tracer.spanBuilder("query_database")
    .setAttribute("db.type", "mysql")
    .startSpan();

try (Scope scope = span.makeCurrent()) {
    // 你的业务逻辑
} catch (Exception e) {
    span.recordException(e);
} finally {
    span.end();
}

你看,和 OpenTracing 的写法很像,但 OTel 更强大——它内置了上下文传播、采样策略、导出器配置等。

2.2.3 两者的对比

特性 OpenTracing OpenTelemetry
状态 已停止更新 活跃开发中
覆盖范围 仅追踪 追踪 + 指标 + 日志
上下文传播 手动实现 内置支持
采样策略 需自行集成 内置多种策略
后端兼容性 Jaeger、Zipkin 等 Jaeger、Zipkin、Prometheus、Datadog 等

注意:如果你现在要新建项目,我建议直接上 OpenTelemetry。OpenTracing 虽然还能用,但社区已经不维护了,未来可能会遇到兼容性问题。

2.3 核心逻辑:Trace 与 Span 的关系

为了让你更直观地理解 Trace 和 Span 的关系,我画了一张图。这张图展示了一次下单请求的完整链路:

Trace 与 Span 关系图(下单请求示例) Trace ID: abc-123-def-456 Span: 网关 SpanID: s1 | 耗时: 5ms HTTP Span: 订单服务 SpanID: s2 | 耗时: 120ms RPC Span: 库存服务 SpanID: s3 | 耗时: 80ms 子Span: 查数据库 SpanID: s2-1 | 耗时: 60ms 子Span: 调用库存 SpanID: s2-2 | 耗时: 85ms 入口 Span 中间 Span 叶子 Span 子 Span

从这张图你能看到:

  • 一个 Trace 包含多个 Span,Span 之间通过 ParentSpanID 形成树形结构
  • 每个 Span 可以有自己的子 Span,比如订单服务内部有「查数据库」和「调用库存」两个子操作
  • 叶子 Span(库存服务)没有子 Span,它是最底层的调用

嗯,这里要注意:Span 的父子关系不一定是严格的「请求-响应」顺序。比如并行调用时,多个子 Span 可以同时存在,它们的 ParentSpanID 指向同一个父 Span。

2.4 实际项目中的经验

我在做风控系统时,链路追踪帮了大忙。有一次发现某个风控规则执行特别慢,影响了整个下单流程。通过追踪,我发现是规则引擎里调了一个外部黑名单接口,那个接口偶尔会超时。

怎么解决的?我做了两件事:

  1. 加超时熔断:给外部调用设置超时时间,超时后走降级逻辑
  2. 加采样策略:全量追踪太耗资源,我改成「错误链路全量采样 + 正常链路 1% 采样」

说白了,链路追踪不只是用来排查问题的,它还能帮你做性能优化和容量规划。你想想看,如果你知道每个接口的 P99 延迟,是不是就能更精准地做限流和扩容?

个人建议:刚开始做链路追踪时,不要追求「全量覆盖」。先给核心链路(比如下单、支付)埋点,跑通了再逐步扩展。我见过不少团队一上来就想把所有服务都接入,结果埋点不规范,数据质量差,最后不了了之。

好了,这一章的内容就到这里。链路追踪的基础概念和标准,说白了就是三件事:Trace 标识一次请求、Span 记录每一步、SpanContext 传递上下文。标准方面,OpenTelemetry 是未来的方向,建议直接上手。


专注资料整理