使用 OpenTelemetry 构建可观测性 05 - 传播和行李(Propagation & Baggage)

OpenTelemetry 传播与行李机制详解:通过 Propagation 传递 TraceID 和 SpanID 实现分布式链路追踪,使用 Baggage 在微服务间传递自定义上下文数据。

作者 Thomas Stringer

我们开发的应用程序可能具有不同的形态和架构:有些是单体应用,有些是微服务。为单体应用程序添加遥测数据相对来说简单,因为所有数据都在同一进程中。然而对于微服务应用程序,情况可能会更具挑战性。

OpenTelemetry 中的传播(Propagation)和行李(Baggage)解决的是同一个核心问题:一次请求跨多个服务时,如何让每个服务知道自己属于同一条分布式链路,并在必要时携带额外上下文。

本文重点说明:

  • Propagation 如何传递 TraceID 和父 SpanID。
  • Baggage 如何在跨服务请求中传递自定义键值信息。
  • Go 示例中如何配置 propagator、HTTP handler 和客户端请求。
  • 如何通过请求头观察 TraceparentBaggage

通常,分布式微服务应用程序的不同服务之间仅通过网络连接。然而,当我们想要创建有效的链路追踪数据,就要考虑到下面的问题:

OpenTelemetry 瀑布图

即使是微服务应用程序,我们也希望观察到从开始到结束的用户路径,这意味着跨越多个服务的边界。这就是我们所说的分布式链路追踪。不过我们如何实现这一点呢?我们如何使链路追踪信息贯穿可能是分布在多个进程,并且是不同的基础架构上呢?

传播( propagation )

在 OpenTelemetry 中,解决这个挑战的方案是通过传播来实现。这意味着以某种方式将链路追踪 ID(和父跨度 ID)传递给被调用服务,以便它们可以将该信息添加到分布式链路追踪路径中的一个跨度上。下面是一个示意图:

OpenTelemetry propagation 传播

这里我们有三个服务,通过使用传播,我们能够将跟踪 ID 和父跨度 ID 作为头信息传递。在 Go 中,传播可以通过全局设置来处理:

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/propagation"
)

// ...

otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(
        propagation.TraceContext{},
        propagation.Baggage{}),
)

在示例代码中,我们可以在控制器层(Handler,通常用于处理HTTP请求并生成相应的响应,承担的作用包括路由和请求分发,请求处理逻辑,响应生成)进行设置:

http.Handle(
    fmt.Sprintf("/%s/", rootPath),
    otelhttp.NewHandler(
        http.HandlerFunc(userCart),
        "http_user_cart",
        otelhttp.WithTracerProvider(otel.GetTracerProvider()),
        otelhttp.WithPropagators(otel.GetTextMapPropagator()),
    ))

当从一个服务发送 HTTP 请求到另一个服务时,可通过 otelhttp 库的辅助函数来创建和管理分布式追踪的跨度对象:

import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"

// ...

resp, err := otelhttp.Get(ctx, fmt.Sprintf("%s/%s", userServiceEndpoint, userName))

传播的目标是让多个服务生成的 span 属于同一条 trace。如果没有传播,每个服务可能都会生成自己的局部 trace,排障时就无法看到完整调用路径。对于 HTTP 场景,trace 上下文通常通过请求头传递;对于其他 RPC 或消息系统,也需要使用对应 carrier 承载上下文。

行李(Baggage)

从上图中可以看出 service 1 生成了一些数据 attr1 。这些与 service 1 相关的数据可能要添加到 service 2 或 service 3 所在跨度对象的属性中。由于这些服务可能无法直接访问此数据,在 OpenTelemetry 中是通过行李来解决这个问题。行李本质上是携带额外信息的键值对,通过请求传递数据给不同服务和组件。

在 Go 中,我们可以通过以下方式添加行李信息:

    reqAddrBaggage, err := baggage.NewMember("req.addr", r.RemoteAddr)
    if err != nil {
        // Handle error...
    }

    reqBaggage, err := baggage.New(reqAddrBaggage)
    if err != nil {
        // Handle error...
    }
    ctx = baggage.ContextWithBaggage(ctx, reqBaggage)

这样设置后我们的 HTTP 请求将包括 req.addr 行李 。

后续消费端的服务(在图中,这可能是 service 2 或 service 3 ),就可以从请求上下文中解析行李:

import "go.opentelemetry.io/otel/baggage"

// ...

reqBaggage := baggage.FromContext(ctx)
span.SetAttributes(attribute.String(
    "req.addr",
    reqBaggage.Member("req.addr").Value()),
)

此代码解析行李信息,并将其作为当前跨度的属性添加进去。

Propagation 和 Baggage 的区别可以这样理解:

概念 传递什么 主要用途
Propagation TraceID、SpanID、采样等链路上下文 把多个服务的 span 串成一条 trace
Baggage 自定义键值对 把跨服务需要的业务或请求上下文传递下去

Baggage 很有用,但不应该滥用。它会随请求传播,字段过多会增加请求体积,也可能带来敏感信息泄露风险。实践中只放排障和跨服务处理确实需要的少量信息。

示例

经过之前对传播和行李的讨论,现在让我们看看 OpenTelemetry 如何发送这些数据。在示例的购物车应用程序中,如果我发出请求并从价格服务或用户服务中查看请求头,将会看到以下两行信息:

Baggage: req.addr=10.244.0.11%3A60086
Traceparent: 00-9861e8c7b097206fed82e0f6b379aae0-4aa019606aed70b6-01

请求头 Traceparent 是链路追踪 ID(本例中是“9861e8c7b097206fed82e0f6b379aae0”)和父跨度 ID (“4aa019606aed70b6”)。还有一个 Baggage ,其中包括在请求发起的源服务(购物车服务),它被添加到 req.addr 行李中。下图可以看到 req.addr 行李在用户服务中被引用:

OpenTelemetry Baggage

排查链路断开的思路

如果在后端看到 trace 断开,可以从传播链路排查:

  1. 服务端 handler 是否使用了 OTel instrumentation,例如示例中的 otelhttp.NewHandler
  2. 客户端发请求时是否使用了 OTel HTTP client 或手动注入上下文。
  3. 全局 propagator 是否同时配置了 TraceContext 和 Baggage。
  4. 中间代理、网关或消息系统是否保留并转发了 trace 请求头。
  5. 下游服务是否从请求上下文中继续创建子 span,而不是重新创建独立 trace。

总结

在 OpenTelemetry 中通过使用传播和行李,很好的解决了“分布式链路追踪”中“分布式”的问题。这样可以帮助您获取更有价值的链路追踪数据!

FAQ:Propagation 和 Baggage 常见问题

Q1:Propagation 和 Baggage 是一回事吗?

不是。Propagation 负责传递链路上下文,让不同服务的 span 能归到同一条 trace;Baggage 负责传递自定义键值信息,供下游服务读取和使用。

Q2:为什么有 Trace 数据,但跨服务链路断开?

常见原因是客户端没有注入上下文、服务端没有提取上下文、代理或网关丢弃了请求头,或者下游服务重新创建了新的 trace。

Q3:Baggage 里可以放用户信息吗?

要谨慎。Baggage 会跨服务传播,不适合放敏感信息或大量字段。只应放必要、可控、对排障或处理有明确价值的上下文。

本文翻译自:https://trstringer.com/otel-part5-propagation/

扩展阅读:

联系我们交流

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云