背景
原本单个系统的交互中,当客户端需要查找问题时,可以拿着服务端生成的request_id来咨询。
实现方式:
- 定义日志切面,环绕指定基类
- 生成uuid,放置到日志的mdc
- 返回给到客户端
在这种实现下,单个系统的问题排查没问题。但是一旦涉及多个系统的交互,一旦出问题,每个环境都要定位一遍请求,设置到问题的流转,人员的流转。
问题
如何提供一个统一的方式,输入一个request_id即可输出整个链路的请求日志?
方案
提供SDK,跨服务之间在请求头传递request_id。
逻辑:没有request_id就生成id,有的话直接获取,request_id绑定threadLocal。
引出新的问题:
子线程中无法直接获取request_id,threadLocal与线程绑定。
|
|
解决:
使用InheritableThreadLocal可以解决子线程继承数据的问题,但是项目中往往会使用线程池,而线程池中的线程是复用的,这时候InheritableThreadLocal就会导致数据错乱问题,因为InheritableThreadLocal只在线程创建初次复制数据。
再次解决:
使用TransmittableThreadLocal,由阿里开源的方案。将数据上下文传递的粒度从线程创建级别调整到任务执行前后,执行前设置,执行后清除。
总结
- 跨服务之间通过请求头传递request_id。
- 由于request_id绑定在线程,在多线程环境下,子线程无法继承父线程的threadLocal。
- 通过加强版的threadLocal——TransmittableThreadLocal解决线程池中线程的上下文传递和清理