在instrumentation-spring-rabbit中,为什么brave要去掉消息的headers?
In instrumentation-spring-rabbit, why does brave remove the headers of the message?
在instrumentation-spring-rabbit
模块中,brave正在提取和删除 headers,为什么?
我探索了其他仪器(spring-web
、httpclient
、okhttp3
、grpc
等)勇敢地从不删除 headers - 它持有跟踪 keys/extras - 来自原始消息。
删除 headers 有一个副作用,即重试 拦截器 - already added by spring-rabbit - 正在第二次尝试处理消息,但是因为brave
在第一次重试的时候去掉了headers,以后的重试就找不到了。
消息跟踪在两个主要方面不同于典型的 RPC 跟踪。因为它是不同的,所以与 RPC 比较并不是找出前进道路的最佳方式。我将在这里简要提及几件事,这些事情主要在我就该主题所做的 slide deck 中。
- 在消息传递中,消费者和消息处理器之间通常没有线程上下文传递。这与 RPC 不同,RPC 通常至少在请求端进行切换。
- 当我们有一个线程上下文时,我们应该用它来建立parent信息(在rabbit处理中就是这样)。然而,通常情况并非如此。因此,当我们不知道消息处理抽象时,我们经常 re-serialize headers 在消息上。
在您的示例中,您谈论的是 spring-rabbit,它在处理块期间使用线程上下文适当地设置 "current span"。由于我们不想将 thread-based 上下文与消息中的内容混淆,我们清除了 headers.
"retry"案确实使这一点受到质疑。在那种情况下 parent 应该是什么,如何知道它?相关检测的问题之一是我们实际上没有看到使用消息的代码。
具体来说,rabbitmq 轮询工具不存在,所以我们放一个 "fake consumer span" 来追溯这个问题。如果消息是 re-played.. 也许第二个消费者跨度是有效的。坦率地说,我们没有考虑到这一点。
无论如何,我的观点是我们不应该过分关注消息跟踪和 RPC 之间的区别,因为那里会有一些故意的区别。让我们关注差距本身,可能会在 gitter 上这样做,我认为这会导致 github 问题。
无论如何,我希望上下文能回答您的问题,即使它不会改变代码当前正在执行的操作这一事实。
@Andrain 感谢您的回答和支持,这真的很有帮助。
作为解决方法,我们需要将重试拦截器移到链中。
@Bean
@Order
BeanPostProcessor reorderingSimpleRabbitListenerContainerFactory() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (SimpleRabbitListenerContainerFactory.class.isAssignableFrom(bean.getClass())) {
final Class<RetryOperationsInterceptor> retryInterceptor = RetryOperationsInterceptor.class;
Advice[] adviceChain = ((SimpleRabbitListenerContainerFactory) bean).getAdviceChain();
Arrays.sort(adviceChain, (o1, o2) -> {
if (o1.getClass().isAssignableFrom(retryInterceptor)) {
return 1;
}
if (o2.getClass().isAssignableFrom(retryInterceptor)) {
return -1;
}
return 0; // it is stable sort, so no worry
});
}
return bean;
}
};
}
在instrumentation-spring-rabbit
模块中,brave正在提取和删除 headers,为什么?
我探索了其他仪器(spring-web
、httpclient
、okhttp3
、grpc
等)勇敢地从不删除 headers - 它持有跟踪 keys/extras - 来自原始消息。
删除 headers 有一个副作用,即重试 拦截器 - already added by spring-rabbit - 正在第二次尝试处理消息,但是因为brave
在第一次重试的时候去掉了headers,以后的重试就找不到了。
消息跟踪在两个主要方面不同于典型的 RPC 跟踪。因为它是不同的,所以与 RPC 比较并不是找出前进道路的最佳方式。我将在这里简要提及几件事,这些事情主要在我就该主题所做的 slide deck 中。
- 在消息传递中,消费者和消息处理器之间通常没有线程上下文传递。这与 RPC 不同,RPC 通常至少在请求端进行切换。
- 当我们有一个线程上下文时,我们应该用它来建立parent信息(在rabbit处理中就是这样)。然而,通常情况并非如此。因此,当我们不知道消息处理抽象时,我们经常 re-serialize headers 在消息上。
在您的示例中,您谈论的是 spring-rabbit,它在处理块期间使用线程上下文适当地设置 "current span"。由于我们不想将 thread-based 上下文与消息中的内容混淆,我们清除了 headers.
"retry"案确实使这一点受到质疑。在那种情况下 parent 应该是什么,如何知道它?相关检测的问题之一是我们实际上没有看到使用消息的代码。
具体来说,rabbitmq 轮询工具不存在,所以我们放一个 "fake consumer span" 来追溯这个问题。如果消息是 re-played.. 也许第二个消费者跨度是有效的。坦率地说,我们没有考虑到这一点。
无论如何,我的观点是我们不应该过分关注消息跟踪和 RPC 之间的区别,因为那里会有一些故意的区别。让我们关注差距本身,可能会在 gitter 上这样做,我认为这会导致 github 问题。
无论如何,我希望上下文能回答您的问题,即使它不会改变代码当前正在执行的操作这一事实。
@Andrain 感谢您的回答和支持,这真的很有帮助。
作为解决方法,我们需要将重试拦截器移到链中。
@Bean
@Order
BeanPostProcessor reorderingSimpleRabbitListenerContainerFactory() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (SimpleRabbitListenerContainerFactory.class.isAssignableFrom(bean.getClass())) {
final Class<RetryOperationsInterceptor> retryInterceptor = RetryOperationsInterceptor.class;
Advice[] adviceChain = ((SimpleRabbitListenerContainerFactory) bean).getAdviceChain();
Arrays.sort(adviceChain, (o1, o2) -> {
if (o1.getClass().isAssignableFrom(retryInterceptor)) {
return 1;
}
if (o2.getClass().isAssignableFrom(retryInterceptor)) {
return -1;
}
return 0; // it is stable sort, so no worry
});
}
return bean;
}
};
}