如何将 traceId 从 gRPC 的上下文传递到另一个线程/线程池?

Posted

技术标签:

【中文标题】如何将 traceId 从 gRPC 的上下文传递到另一个线程/线程池?【英文标题】:How to pass on a traceId from gRPC's context to another thread/threadPool? 【发布时间】:2018-04-24 04:26:22 【问题描述】:

我正在使用 grpc-java 并有 3 个服务,A、B 和 C。我调用服务 A,然后服务 A 调用 B 和 C。我在调用 B 和 C 时使用 Hystrix。C 反过来产生另一个线程调用另一个服务。

我有传递 traceId 的 ClientInterceptors 和 ServerInterceptors。只要它是 gRPC 工作线程,我就可以在 Context 和日志中看到 traceId,但是当调用移动到另一个线程(Rxioscheduler 线程或 Hystrix 线程)时会丢失它们。如何在不同线程的请求之间以及不同的执行器服务和线程池之间传递 traceId?

【问题讨论】:

【参考方案1】:

虽然可以以细粒度的方式传播(如executor.execute(Context.current().wrap(runnable))),但您应该尝试将Context 传播集成到跨线程工作传输中。对于许多应用程序,只要创建它就像wrapping the "main" executor 一样简单:

executor = Context.currentContextExecutor(executor);
// executor now auto-propagates

在您的应用程序开始时这样做一次,然后您就不再担心传播了。

但应用程序会有所不同。例如,直接创建Threads 的应用程序可能应该创建一个ThreadFactory,将调用线程的Context 传播到Thread

class PropagatingThreadFactory implements ThreadFactory 
  private final ThreadFactory delegate;

  public PropagatingThreadFactory(ThreadFactory d) delegate = d;

  @Override public Thread newThread(Runnable r) 
    return delegate.newThread(Context.current().wrap(r));
  

【讨论】:

当我没有在我的应用程序中显式创建执行器时,如何传播上下文? gRPC 为回调传播上下文,与是否使用 gRPC 通道/服务器中内置的默认执行器无关。对于您自己的基于执行器的逻辑,您可以包装执行器,即使您没有创建它。如果您也不能这样做,那么在最坏的情况下,您可以在将其传递给 Executor 时始终 wrap each individual Runnable。 我在客户端拦截器中访问 gRPC 上下文时遇到问题。我在服务器拦截器中设置了一些标头,并尝试在客户端拦截器中访问相同的标头,但由于 ThreadLocal,我无法访问。我还应该与执行人打交道还是尝试其他方法?我对此很陌生,因此试图了解流程。 @AkashShinde,请在***.com/questions/70151106/… 中说明您在做什么,我们将在那里讨论。

以上是关于如何将 traceId 从 gRPC 的上下文传递到另一个线程/线程池?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Hystrix Observables 中传递 traceIds?

OpenTelemetry Python - 如何将新跨度实例化为给定 traceid 的子跨度

在 golang 中将元数据传递到上下文时出错

gRPC系列:什么是gRPC API,它如何工作?

如何将上下文从活动传递到服务

同一个请求分配一个traceId的两种方式