微服务分布式架构中,如何实现日志链路跟踪?

本文主要讲解了spring cloud微服务使用Feign作为微服务间的通讯框架的情况下,如何使用统一的日志ID来追踪一次请求日志,高效排查日志。核心解决了以下问题:

1.代码无入侵

2.线程池(主/子线程)日志ID一致

3.日志ID传递到下游服务

(以下只提供了核心代码截图,详细代码可通过github、gitee仓库查看,文末附代码目录)

一、单体服务统一日志ID处理

MDC(Mapped Diagnostic Context,映射调试上下文)是log4j和logback提供的一种方便在多线程条件下记录日志的功能。MDC可以看成是一个与当前线程绑定的Map,可以往其中添加键值对。

1.创建一个MDC工具类MdcUtil

微服务分布式架构中,如何实现日志链路跟踪?_第1张图片

2.利用Filter在请求入口设置日志ID(如果是下游服务,可以从header获取到日志ID,否则生成新的日志ID)

微服务分布式架构中,如何实现日志链路跟踪?_第2张图片

3.使用logback的MDC机制日志模板中加入日志ID标识,取值方式为%X{trace-id}

微服务分布式架构中,如何实现日志链路跟踪?_第3张图片

4.使用postman请求API

微服务分布式架构中,如何实现日志链路跟踪?_第4张图片

【日志打印效果】16582427033635607为日志ID

22:58:23.365 [16582427033635607] [http-nio-6001-exec-3]  INFO LogResponseBodyAdvice.beforeBodyWrite[32] - {"code":0,"message":"成功","data":"2022-07-19 22:58:23"}
22:58:23.368 [16582427033635607] [http-nio-6001-exec-3]  INFO RequestFilter.doFilterInternal[52] - GET 192.168.31.158 /api/time header:{"x-platform":"app"},param:{"a":"1"},body:{"b":"bb"},4ms

二、日志ID传递给线程池中的子线程

1.自定义线程池实现JDK的ThreadPoolExecutor,在提交任务的时候把日志ID绑定到Runnable一起提交,后续执行Runnable的run方法的时候可以通过成员变量的方式获取日志ID

微服务分布式架构中,如何实现日志链路跟踪?_第5张图片

三、微服务链路日志ID传递(基于Feign)

1.利用Feign提供的拦截器RequestInterceptor,在Feign请求发起前往RequestTemplate设置header就OK了

微服务分布式架构中,如何实现日志链路跟踪?_第6张图片

2.由于加入了Hystrix做熔断处理,需要解决Hystrix线程池(主/子线程)的日志ID传递,重写HystrixConcurrencyStrategy构建线程池的逻辑

微服务分布式架构中,如何实现日志链路跟踪?_第7张图片

【当前服务的日志】16582448303481157为日志ID

​23:33:50.365 [16582448303481157] [hystrix-template-user-10]  INFO FeignIPClient.execute[42] - 13ms GET http://192.168.31.158:8002/user/getById?id=1
23:33:50.370 [16582448303481157] [http-nio-6001-exec-3]  INFO FeignCostTimeAspect.feignCostTime[30] - request feign:UserFeign.getById,mills:19,args:[1],result:{"code":0,"message":"成功","data":{"id":1,"name":"adasd","status":2,"statusDesc":"冻结"}}
23:33:50.373 [16582448303481157] [http-nio-6001-exec-3]  INFO LogResponseBodyAdvice.beforeBodyWrite[32] - {"code":0,"message":"成功","data":{"id":1,"name":"adasd","status":2,"statusDesc":"冻结"}}
23:33:50.377 [16582448303481157] [http-nio-6001-exec-3]  INFO RequestFilter.doFilterInternal[52] - GET 192.168.31.158 /api/getUserById header:{"x-platform":"app"},param:{"id":"1"},body:{},29ms

【user服务的日志】16582448303481157为日志ID

23:33:50.363 [16582448303481157] [http-nio-8002-exec-3]  INFO LogResponseBodyAdvice.beforeBodyWrite[32] - {"code":0,"message":"成功","data":{"id":1,"name":"adasd","status":2,"statusDesc":"冻结"}}
23:33:50.366 [16582448303481157] [http-nio-8002-exec-3]  INFO RequestFilter.doFilterInternal[52] - GET 192.168.31.158 /user/getById header:{"x-platform":"app"},param:{"id":"1"},body:{},6ms

怎么样?如果你觉得有用的话,还不快快搞起!!!

附:涉及的代码目录

github:GitHub - 897665787/springcloud-template

gitee:springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

springcloud-template
└── template-framework
     └── filter
          └── MdcFilter -- 对客户端请求添加MDC
          └── MdcUtil -- MDC工具
     └── interceptor
          └── FeignHeaderInterceptor -- Feign调用过程中传递header值
          └── Transfer -- http请求线程与Hystrix线程 传输对象
          └── TransferHystrixConcurrencyStrategy -- Hystrix并发策略
     └── threadpool
          └── CustomThreadPoolExecutor -- 自定义线程池
     └── logback-conf-base.xml -- 基础日志配置

如果想了解如何高效收集请求/响应日志,可阅读我的文章

微服务分布式架构中,如何高效收集请求/响应日志_吾日三省Java的博客-CSDN博客

你可能感兴趣的:(java,架构,微服务,分布式)