ThreadLocal在链路追踪中的应用(引子)

最近在公司负责系统的链路追踪问题。公司的部分服务已经有了一个基本的实现,大概的原理是,当一个请求到达系统的最前端模块(一般是API网关)时,通过AOP切面进行拦截,用uuid或者snowflake等技术,生成一个唯一id(为简化书写,后文称之为cid,即correlationId),并将cid设置到request的header中,再放行这个request。而由于各个服务,在收到请求时,都会将请求信息输出到日志文件。如此,一个服务在收到请求,和对请求做出响应时,cid都会伴随着request对象,被输出到日志文件中。
那么当一个服务收到请求后,在这个服务的内部处理流程中,如何携带这个cid呢?答案就是利用ThreadLocal,在一个服务收到一个调用请求时,取出request的header中的cid,放到ThreadLocal中,在后序处理流程中,输出日志时从ThreadLocal中取出这个cid,拼接到日志信息中即可。

但是有一个问题,如果在服务内部的处理流程中,涉及到异步代码,要怎么办呢?因为主线程和异步子线程是不同的线程环境,我们一开始设置的ThreadLocal是和主线程绑定的,如果不做处理,则在异步代码中就会丢失到cid信息。一种最基础的解决方案是,将原来使用的ThreadLocal,换成InheritableThreadLocal,顾名思义,这个对象是“可继承”的ThreadLocal。它的表现是,在主线程开启异步子线程时,能够将主线程的ThreadLocal传递给子线程。大概的原理是,在主线程中创建子线程时,将主线程的ThreadLocal进行拷贝,然后设置到子线程的threadLocalMap对象上去,完成上下文的传递。
看似解决了问题。但由于InheritableThreadLocal是在异步子线程初始化时进行的设置,而线程只会初始化一次,就会导致子线程中的ThreadLocal一直是同一个。这在普通的应用场景下不会有什么问题。但现在的开发中,一般会用池化的技术来管理多个线程,即会用到线程池。在线程池中,核心线程一般来说是不会死的,他们会被反反复复使用。用InheritableThreadLocal的问题在于,threadLocal只在子线程初始化的时候进行了传递,当这个子线程完成了第一个任务,随后处理其他请求时,这个子线程中的threadLocal却还一直是第一个请求时设置的那个threadLocal。就会导致出错。
简单来说就是,InheritableThreadLocal只能在线程初始化中设置一次,而在池中的线程,需要在每次处理不同的请求时,都重新设置threadLocal。
所以InheritableThreadLocal在线程池的场景下不适用。
对于InheritableThreadLocal的问题,有许多解决方案,比如阿里开源的TransmittableThreadLocal。

而日志的门面框架slf4j,提供了MDC机制。开发者可以在logback或log4j的xml配置文件中,对日志输出格式的配置中加上%X{cid},然后在代码中调用MDC.put("cid","123456"),则在logger输出的日志信息中,会自动使用123456去替换掉%X{cid},达到动态对日志添加关联信息的目的。

MDC机制内部也是用了ThreadLocal,早期的MDC机制采用的正是InheritableThreadLocal,就是考虑到关联信息需要在父子线程之间进行传递的场景。然而在后期的版本中,出于性能考虑,换回了ThreadLocal。
那么如果我们想利用slf4j的MDC机制,又期望MDC机制中使用TransmittableThreadLocal,方便的完成父子线程的上下文传递。怎么做呢?
好在万能的单身交友网站Github上,有开发者提供了针对logback和log4j,使用TransmittableThreadLocal的代理jar包。我们可以通过 虚拟机参数-javaagent 为我们的应用程序添加代理,使得MDC机制使用TransmittableThreadLocal实现。

这样对于一个请求,在整个链路中,都能有一个唯一id将其标识。在后续可以对日志进行中心化管理,排查bug时通过一个id就能定位问题。
不过这只是链路追踪的开始。
目前市面上流行的APM链路追踪工具,都是采用了类似代理的方式,使用探针技术,对服务的日志注入跟踪id,并将日志搜集起来,分析整理后再通过页面UI进行展示。
最近在研究的是pinpoint和skywalking,这两者都是基于字节码增强的,无需改动原有代码,相比更具代码侵入性的zipkin等,部署起来更为方便。

猜你喜欢

转载自blog.csdn.net/vcj1009784814/article/details/106108046