基于OpenTelemetry实现可观测性-Part 5 传播与Baggage

本文深入探讨了如何使用OpenTelemetry实现跨服务的可观测性,重点在于传播(Propagation)和Baggage的概念。传播使得追踪ID能在分布式应用中传递,而Baggage则允许附加数据在请求中流动。通过示例展示了在Go中如何处理这两个关键特性,以实现在微服务架构中的链路追踪和数据共享。

8af1363e3c07c9efa78f4bad79dc3b3c.jpeg

泽注:这是一个系列,共分成6部分,这是第5部分。翻译自:https://trstringer.com/otel-part5-propagation/

我们开发的应用程序各式各样的,有些是单体的,有些是微服务的。单体应用添加遥测相当容易,因为所有的数据都在同一进程中。但是,微服务就有挑战了。很多时候,它只是连接分布式应用之间不同服务的网络。即使这样,这个挑战也无法阻止我们建立有效的链路追踪,如下图:

61b0999c8fcc1cdd7fbd340e7bbef81a.png
传播

即使是微服务应用,我们也希望看到一个类似的追踪,追踪用户的路径从开始到结束,即使是跨越多个服务的边界。这就是我们所说的分布式跟踪。但是我们怎样才能实现这一点呢?我们怎样才能追踪跨越多个进程的链路,这些进程还可能运行在非常不同的基础设施上?

传播(Propagation)

OpenTelemetry 对这一挑战的回答是传播。这就是我们如何将追踪 ID(和父跨度 ID)传输到被调用的服务,以便它们可以将跨度添加到分布式调用链中。可视化后如下:

70dcebb5fd018833aad8d2a9cc9ca9f9.png
Propagation

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

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

// ...

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

在服务器实例化过程中,我们可以在处理器级别设置:

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))

背包(Baggage)

在上图中,您会注意到“service 1”生成了一些名为“attr1”的数据。这是与“service 1”相关的数据,这可能是我们想要添加到“service 2”和/或“service 3”中的跨度的属性。但是这些服务可能无法访问这些特定数据。我们使用 OpenTelemetry 解决这个问题的方法是使用 baggage。Baggage 本质上允许我们通过请求传递数据以供其他服务使用。

在Go中,我们增加baggage的方法如下:

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请求中将带有baggage req.addr

在消费服务中(在图中,这可能是service 2service 3),对从baggage中解析请求:

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

// ...

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

该代码从请求baggage中取出数据,并将其它作为跨度属性写入到当前跨度。

案例

我们已经谈到了传播和baggage,但现在让我们看看OpenTelemetry是如何发送这些数据的。在我的示例购物车应用中,如果我发起一个请求,并从价格或用户服务中转储header信息,那么我将看到以下两个头信息:

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

traceparent头显示了trace ID(在本例中是 "9861e8c7b097206fed82e0f6b379aae0")和父跨度ID("4aa019606aed70b6")。还有一个baggage头,包括在源服务(购物车)中添加的req.addr baggage成员。我们可以看到这个baggage在用户服务中被引用:

8d9dc8518f27ac4d386a348cecd1a6b1.png
baggage

总结

OpenTelemetry对 "分布式跟踪 "的 "分布式 "部分有很好的支持,通过传播和baggage的使用。这真的让你有能力做出有意义的追踪,并收集有用的数据!

<think>我们遇到了一个配置错误:`io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException: otel.propagators b3 not recognized`。这个错误通常发生在OpenTelemetry的自动配置过程中,当我们指定了一个不被支持的propagator(传播器)时。 ### 问题分析 1. **错误信息含义**:`b3 not recognized` 表示自动配置系统无法识别名为"b3"的传播器。 2. **传播器的作用**:传播器用于在分布式系统中传递上下文信息(如TraceID, SpanID)。常见的传播器包括: - `b3`:Zipkin使用的传播格式 - `jaeger`:Jaeger使用的传播格式 - `tracecontext`:W3C Trace Context标准 - `baggage`:W3C Baggage标准 3. **配置方式**:通常通过环境变量`OTEL_PROPAGATORS`或系统属性`otel.propagators`来配置。 ### 解决方案 #### 步骤1:确认OpenTelemetry版本 `b3`传播器在较新的OpenTelemetry Java版本中默认包含。请检查你的依赖版本: - 对于1.0.0及以上版本,`b3`是默认支持的[^1]。 - 如果使用旧版本(如0.x),可能需要升级。 #### 步骤2:检查配置值 确保配置的传播器名称正确。正确的配置方式: ```properties # 环境变量方式 OTEL_PROPAGATORS=b3 # 或Java系统属性方式 -Dotel.propagators=b3 ``` #### 步骤3:指定全限定类名(如果自动配置不支持) 如果自动配置无法识别`b3`,可以显式指定传播器的全限定类名: ```java import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.extension.trace.propagation.B3Propagator; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.trace.SdkTracerProvider; // 手动配置传播OpenTelemetrySdk.builder() .setTracerProvider(SdkTracerProvider.builder().build()) .setPropagators( ContextPropagators.create( TextMapPropagator.composite( B3Propagator.injectingSingleHeader(), // 使用B3单头传播 W3CTraceContextPropagator.getInstance() ) ) ) .buildAndRegisterGlobal(); ``` #### 步骤4:添加必要依赖(如果使用旧版本) 对于Maven项目,确保包含B3传播器的依赖: ```xml <dependency> <groupId>io.opentelemetry.extension.trace</groupId> <artifactId>opentelemetry-extension-trace-propagators</artifactId> <version>1.0.0</version> <!-- OpenTelemetry核心版本一致 --> </dependency> ``` ### 常见问题排查 1. **拼写错误**:检查`otel.propagators`的值是否拼写正确(例如`b3`而不是`B3`或`b3m`)。 2. **多值配置**:如果需要多个传播器,用逗号分隔(无空格): ```properties otel.propagators=b3,tracecontext,baggage ``` 3. **依赖缺失**:如果使用自动配置且版本>=1.0.0,通常不需要额外依赖。但旧版本或特殊需求可能需要添加`opentelemetry-extension-trace-propagators`。 ### 配置验证 在代码中打印实际生效的传播器: ```java Propagators propagators = OpenTelemetry.getGlobalPropagators(); System.out.println("Active propagators: " + propagators.getTextMapPropagator()); ``` > 通过显式配置传播器,可避免自动配置的识别问题[^1]。升级到最新稳定版是解决兼容性问题的最佳实践。 §§相关问题§§ 1. 如何配置 OpenTelemetry 使用多个传播器? 2. OpenTelemetry 自动配置支持哪些环境变量? 3. 如何升级 OpenTelemetry Java 到最新版本? 4. W3C Trace Context 和 B3 传播格式有什么区别?</think>### 解决 OpenTelemetry 配置错误:未识别的 `otel.propagators` 值 `b3` #### 错误原因分析 该错误表明 OpenTelemetry 的自动配置模块无法识别 `b3` 传播器配置: ```java io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException: otel.propagators b3 not recognized ``` 根本原因可能是: 1. **依赖缺失**:未包含 B3 传播器的实现库 2. **版本不兼容**:使用的 OpenTelemetry SDK 版本不支持 `b3` 传播器 3. **配置格式错误**:传播器名称拼写错误或配置格式不正确 #### 解决方案 ##### 步骤 1:添加 B3 传播器依赖 在构建文件中添加 B3 传播器的实现库: **Maven 配置**: ```xml <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-trace-propagators</artifactId> <version>1.30.1</version> <!-- SDK版本保持一致 --> </dependency> ``` **Gradle 配置**: ```groovy implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators:1.30.1' ``` ##### 步骤 2:检查 SDK 版本兼容性 确保 SDK 版本 ≥ 1.0.0(B3 传播器在早期版本中可能未包含): ```java // 在pom.xml中检查版本 <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> <version>1.30.1</version> <!-- 推荐使用1.0.0+版本 --> </dependency> ``` ##### 步骤 3:正确配置传播器 **环境变量方式**: ```bash export OTEL_PROPAGATORS=b3 ``` **Java 系统属性方式**: ```java System.setProperty("otel.propagators", "b3"); ``` **代码显式配置**: ```java import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.extension.trace.propagation.B3Propagator; OpenTelemetrySdk.builder() .setPropagators( ContextPropagators.create( TextMapPropagator.composite( B3Propagator.injectingSingleHeader(), // 添加B3传播器 W3CTraceContextPropagator.getInstance() ) ) ) .buildAndRegisterGlobal(); ``` #### 验证配置是否生效 ```java // 检查注册的传播器 Propagator propagator = OpenTelemetry.getGlobalPropagators().getTextMapPropagator(); System.out.println("Active propagators: " + propagator); // 应输出:CompositeTextMapPropagator[b3single, tracecontext] ``` #### 常见问题排查 1. **依赖冲突**: ```bash mvn dependency:tree | grep opentelemetry ``` 确保所有 OpenTelemetry 组件版本一致 2. **配置覆盖问题**: - 检查是否有多个配置源(环境变量、系统属性、配置文件) - 确保没有在代码中覆盖自动配置 3. **传播器名称验证**: ```java // 可用的传播器列表 System.out.println(DefaultConfigProperties.get().getList("otel.propagators")); // 输出示例:[tracecontext, baggage, b3, b3multi] ``` > 通过显式配置传播器,可避免自动配置的识别问题[^1]。升级到最新稳定版是解决兼容性问题的最佳实践。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值