【发布时间】:2020-12-16 15:48:46
【问题描述】:
我最近从 Spring Cloud Greenwich.SR2 迁移到了 Hoxton.SR9,并且正在使用 Spring Sleuth 来跟踪传入的 REST 调用到我的 Spring Boot 应用程序,这些调用会触发最终到达 RabbitMQ 的消息。
显然,Spring Sleuth 在这两个版本之间的主要区别之一是,现在只发送一个 b3 标头,而不是发送 3 个单独的消息标头用于跟踪、跨度和 parentSpan,格式为 {trace}-{span}-{sample}-{parentSpan}最后两个组件可选。
让我感到困惑的是,到达 RabbitMQ 的消息上的 b3 标头似乎从来没有 parentSpan 组件。例如顺序是这样的:
- 在应用 REST 控制器内:traceId=T、spanId=S1、parentSpanId=S0
- 从应用内发送事件之前:traceId=T、spanId=S2、parentSpanId=S1
- RabbitMQ 队列上的消息头:b3=T-S2-1
换句话说,消息头有正确的踪迹,但共享应用程序中发送事件上下文的跨度并且有no parentSpan。
这是预期的吗?我确信在以前版本的 Sleuth 中,我会在消息头中看到一个新的 spanId,并且 parentSpan 等于发送事件上下文中的 span。
我是否误解了正在发生的事情,或者(如果我的期望是明智的)有没有办法改变这种默认行为。
我有以下明确的侦探属性设置:
spring.sleuth.enabled=true
spring.messaging.enabled=true
spring.supportsJoin=false
(注意:我尝试使用默认的 supportJoin,但它似乎对缺少 parentSpanId 没有任何影响)。
调试信息
这是我通过调试器能够确定的:
- 我们将
GenericMessage传递给AbstractMessageChannel.send()。 - 最终消息被传递到
TracingChannelInterceptor.preSend() -
TracingChannelInterceptor配置了一个DeferredInjector,其中setter是MessageHeaderPropagation的一个实例,injectorFactory有一个producerInjectorFunction=SINGLE_NO_PARENT。 -
TracingChannelInterceptor.preSend()方法调用DeferredInjector.inject(span.context(), headers),这会导致 SINGLE_NO_PARENT 注入器将b3形式的{traceId}-{spanId}-1标头添加到传出消息中。
因此缺少 parentSpanId 似乎源于 TracingChannelInterceptor.injector 是一个 DeferredInjector,其生产者注入器是 SINGLE_NO_PARENT。
自定义配置
注册以下 bean 以覆盖默认传播设置会将行为更改为:
- 在应用 REST 控制器内:traceId=T、spanId=S1、parentSpanId=S0
- 从应用内发送事件之前:traceId=T、spanId=S2、parentSpanId=S1
- RabbitMQ 队列上的消息头:b3=T-S2-1-S1
但我想知道为什么有必要这样做?
@Configuration
public class B3Configuration {
@Bean
Propagation.Factory customPropagationFactory() {
return B3Propagation.newFactoryBuilder()
.injectFormat(B3Propagation.Format.SINGLE)
.injectFormat(Span.Kind.CLIENT, B3Propagation.Format.SINGLE)
.injectFormat(Span.Kind.CONSUMER, B3Propagation.Format.SINGLE)
.injectFormat(Span.Kind.PRODUCER, B3Propagation.Format.SINGLE)
.build();
}
}
【问题讨论】:
-
您是否碰巧有一个重现该问题的示例项目?
-
嗨 Jonatan - 我现在没有任何东西,但如果有帮助的话,可能会整理一些简单的东西。这是一个非常普通的 Spring Boot 设置,带有 Spring Boot 2.3.7 和 Spring Cloud Hoxton.SR9。
-
我现在远离我的源代码,但我确实尝试在我的 Spring Boot 应用程序中调试它,它达到了使用 Format.SINGLE_NO_PARENT 而不是 FORMAT.SINGLE 的地步传出 Spring 消息上的拦截器的上下文。抱歉,我现在不能更具体。
-
@JonatanIvanov 我在原始问题中添加了一些调试信息,希望对您有所帮助 - 如果您需要更多信息,请告诉我。
-
@JonatanIvanov 似乎可以通过注册问题文本中包含的 bean 来解决“问题”(如果是问题)。但我很惊讶我必须这样做才能让它以这种方式工作。
标签: spring-boot spring-cloud-sleuth