记一次使用MDC实现分布式traceId记录追踪

背景:

一天线上出一个bug,三方商品详情获取失败,于是进行线上日志排查,排查定位到报错方法在一个三方商品服务中,但是这个方法被很多地方调用,所以找不到调用的入口在哪,想要溯源简直是太难。这个时候项目Leader说之前有项目使用了sluenth结合zipkin记录traceId但是这里用这样的技术有点杀鸡用牛刀,于是他说你试试MDC看能不能实现这样的功能,当时想赶快排查完问题,之后再去搞搞这个MDC。

处理后续问题:

空闲下来查询资料了解MDC是什么,了解完了之后决定自己动手捣鼓,当时在AOP中直接拦截了所有的Controller在MDC中放入一个全局traceId,只要是此次请求访问线程内都能取到此traceId,并且能结合日志配置文件将此traceId输出到日志文件。虽然感觉还不错,但是还是只能用于单个服务,对于分布式服务这样还是不行,现在大多数服务之间的调用都是使用的feign,于是想的是将traceId放入feign的请求头中实现traceId的传递,然后在被调用的服务的拦截器或者aop中取到此traceId,然后再放入MDC中,这样就实现了traceId的多服务传递。在实践的过程遇到个问题如何判断traceId的生成是在哪里,于是马上想到如果从请求头中没有获取到traceId就一定是分布式链路调用的入口,此时生成一个全局唯一的traceId,可以用雪花算法也可以用UUID生成,我用的是UUID,毕竟雪花算法在并发特别大的情况下有可能id生成会重复。此时一个粗糙的MDC实现分布式traceId记录追踪并打印到日志中已经完成,但最后还发现一个问题,在子线程或线程池中此traceId获取不到,结合相关资料,这里我猜想是MDC是使用ThreadLocal实现的但是ThreadLocal不能实现父子线程的副本传递,所以子线程中获取不到父线程中的traceId。项目中大部分用的都是线程池,我们只需要自己重写一个线程池,在创建线程池时获取到当前线程的MDC上下文,然后将MDC上下文赋值给自定义线程池的成员变量,然后调用新线程的前后做相应的赋值,清空处理就可以实现子线程的traceId获取。

感悟:弄懂一个技术点不要只是知道,一定要自己敲一遍代码,有自己的足迹才值得回忆。     

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值