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

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

作者:享学课堂 2020-05-26 11:59:30

开发

架构

分布式 在现有的系统中,由于大量的其他用户/其他线程的日志也一起输出穿行其中导致很难筛选出指定请求的全部相关日志。那我们如何来处理呢?

 背景

开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用ELK来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,我们来看下面的图:

 

上图一个用户请求一个url,整个链路如图,每个处理层都会产生日志,那我们如何把这些日志串在一些,形成一个请求全路径日志。

在现有的系统中,由于大量的其他用户/其他线程的日志也一起输出穿行其中导致很难筛选出指定请求的全部相关日志。那我们如何来处理呢?

解决思路

我们可以把每个请求弄一个唯一标识,然后我们可以在日志打印的时候代上每个请求都使用一个唯一标识,而且那个唯一标识需要传递给下游服务,下游服务打印日志的时候也带上这个唯一标识,这样就很好的追踪全部的链路显示在日志中。

那技术实现方案是什么呢?我们应该尽可能的对代码无入侵,使用Logback的MDC机制日志模板中加入traceId标识,取值方式为%X{traceId}。

什么是MDC

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

MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。

方案实现

由于MDC内部使用的是ThreadLocal所以只有本线程才有效,子线程和下游的服务MDC里的值会丢失;所以方案主要的难点是解决值的传递问题,主要包括以几下部分:

  • API网关中的MDC数据如何传递给下游服务
  • 服务如何接收数据,并且调用其他远程服务时如何继续传递
  • 异步的情况下(线程池)如何传给子线程

修改日志模板

logback配置文件日志格式添加该标识

 

网关添加过滤器

此过滤器就是来解决网关如何把MDC的数据传递给下游服务:

生成traceId并通过header传递给下游服务

 

上面代码有个MDC是属于org.slf4j.MDC中的,下面就是常量的值:

  1. /** 
  2. * 日志链路追踪id信息头 
  3. */ 
  4. String TRACE_ID_HEADER = "x-traceId-header"
  5. /** 
  6. * 日志链路追踪id日志标志 
  7. */ 
  8. String LOG_TRACE_ID = "traceId"

下游服务增加spring拦截器

接收并保存traceId的值:

 

下游服务增加feign拦截器

继续把当前服务的traceId值传递给下游服务:

 

解决父子线程传递问题

主要针对业务会使用线程池(异步、并行处理),并且spring自己也有@Async注解来使用线程池,要解决这个问题需要以下两个步骤:

重写logback的LogbackMDCAdapter

由于logback的MDC实现内部使用的是ThreadLocal不能传递子线程,所以需要重写替换为阿里的TransmittableThreadLocal。

TransmittableThreadLocal 是Alibaba开源的、用于解决 “在使用线程池等会缓存线程的组件情况下传递ThreadLocal” 问题的 InheritableThreadLocal 扩展。若希望 TransmittableThreadLocal 在线程池与主线程间传递,需配合TtlRunnable和TtlCallable使用。

 

  • 其他代码与ch.qos.logback.classic.util.LogbackMDCAdapter一样,只需改为调用copyOnInheritThreadLocal变量。

TtlMDCAdapterInitializer类用于程序启动时加载自己的mdcAdapter实现:

 

扩展线程池实现

增加TtlRunnable和TtlCallable扩展:

 

场景测试

测试代码如下:

  1. log.info("测试"
  2. @Async 
  3. public  void test(){ 
  4. log.info("测试1"
  5. userService.findByUserName("gu"); 

api网关打印的日志

 

ELK聚合日志通过traceId查询整条链路日志

当系统出现异常时,可直接通过该异常日志的traceId的值,在日志中心查询该请求的所有日志信息,类似下图:

 

总结

到此分布式的日志跟踪就已经完成了,这样就很好的可以排查整个微服务的日志链路,谢谢!!!

作者:享学课堂

链接:https://www.jianshu.com/p/a3ebc9249b69

来源:简书

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/285992.html<

(0)
管理的头像管理
上一篇2025-05-15 03:44
下一篇 2025-05-15 03:46

相关推荐

  • 高防服务器的防御原理是什么,如何选择高防服务器?

    高防服务器的防御原理,简单说就是通过流量清洗、防火墙规则和黑洞路由等机制,在攻击流量到达业务服务器之前将其过滤或阻断,从而保障正常访问,流量清洗机制是核心防线高防服务器对抗DDoS攻击,靠的不是单一技术,而是一套组合动作,最常见的攻击类型是流量型攻击,比如UDP洪水、SYN洪水、ICMP放大等,核心思路是耗尽带……

    2026-07-26
    0
  • BGP线路到底是什么意思呢,有什么优势?

    BGP线路是一种通过边界网关协议实现多运营商网络互联的接入方式,能自动选择最优路径,极大提升跨网访问速度和稳定性,是解决国内南北网络瓶颈的核心方案,什么是BGP线路BGP,全称Border Gateway Protocol,边界网关协议,是互联网核心路由协议之一,它负责在自治系统之间交换网络可达性信息,BGP线……

    2026-07-26
    0
  • 增值电信业务经营许可证对IDC有多重要,如何办理?

    增值电信业务经营许可证是IDC服务商合法运营的核心凭证,它直接决定了机房能否接入骨干网、客户能否放心托管业务,以及服务商自身能否长期稳定发展,许可证是IDC进入市场的硬门槛互联网数据中心业务属于增值电信业务中的B1类,依据工信部《电信业务经营许可管理办法》,任何从事服务器托管、虚拟主机、云服务等业务的企业,必须……

    2026-07-26
    0
  • 站群服务器一个IP放几个网站合适?,怎么选

    站群服务器一个IP放3-5个网站是大多数情况下的最佳平衡点,但具体数量需根据网站权重、内容质量及IP资源成本灵活调整,这个结论基于搜索引擎对同IP站点的关联判定逻辑,以及站群运营的长期实践,如果你刚接触站群,可能会纠结于IP分配,但核心原则是:不要让搜索引擎轻易识别出这些网站属于同一实体,站群IP分配的底层逻辑……

    2026-07-26
    0
  • DDoS攻击和CC攻击有什么区别,怎么防御?

    DDoS攻击和CC攻击最核心的区别在于攻击目标不同:DDoS攻击主要消耗网络带宽和基础设施资源,而CC攻击专门针对应用层逻辑,耗尽服务器CPU和数据库连接数,两者从原理到防御手段完全不同,攻防视角下的本质差异攻击目标:一个砸门,一个撬锁DDoS攻击(分布式拒绝服务)瞄准的是网络层和传输层,通过大量伪造数据包或畸……

    2026-07-26
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注