跳到正文
Kale的数字花园
目录 文章
/3 分钟/6 阅读/0 评论

Sleuth MDC分布式链路追踪

在分布式系统下,存在多链路的微服务调用,在排查问题时需要去追踪各个服务的调用链过程是比较麻烦的,所以需要引入一个分布式链路追踪的机制 https://mp.weixin.qq.com/s/cyGEDNYMDAKwQgNEFQV4cw 其中调

背景

在分布式系统下,存在多链路的微服务调用,在排查问题时需要去追踪各个服务的调用链过程是比较麻烦的,所以需要引入一个分布式链路追踪的机制

引用: https://segmentfault.com/a/1190000041480530
https://mp.weixin.qq.com/s/cyGEDNYMDAKwQgNEFQV4cw

基础知识

  • service: 服务名,它默认就取spring.application.name。
  • span : 直接翻译就是跨度,比如service1调用service2,这一个来回可以算一个span。每个span都由一个唯一的spanId标识。
  • trace: 直接翻译就是追踪的意思。它由一系列的span组成。通常在第一个服务接收到请求时开启一个trace,生成一个唯一的traceId,后续的所有追踪都可以沿用这同一个traceId,这样就可以来唯一的标识这一整个调用链路。

其中调用的开始的spanId == traceId 也称为 root span

原理

一般来说都是引入 Sleuth + MDC的使用来进行链路追踪

Spring Cloud Sleuth的追踪信息中的traceId、spanId会自动的添加到Slf4j的MDC中。所以如果你使用的日志框架是走的SLF4j规范的,则可以在日志中使用traceId、spanId变量。

spring 默认日志框架是 logback,这里就以 logback-spring.xml 为例,在 pattern 中添加变量 %X{traceId}、%X{spanId} 就能读到 MDC 中设置的 traceId、spanId 值。

X-B3-******* 已被移除**

要注意的是,网上一些示例用的是 %X{X-B3-TraceId}、%X{X-B3-SpanId} 来代替上面的值。经亲自踩坑,发现在 spring cloud sleuth 3.0.0 版本发布后,也可对应 spring cloud 2020.0.0 之后,X-B3- 这种写法已经被移除了。可能在其他地方还能见到,但在 MDC 中已经找不到了。

LOG**_LEVEL_**PATTERN

还有人要说了,我在引入了 sleuth之后,并没有创建 logback-spring.xml,也没有配置 traceId、spanId 这类值。或者创建了 logback-spring.xml,但 pattern 中没配置 traceId、spanId 的变量,为什么日志中也会打印出来呢,就像这样:

2022-02-20 23:01:28.662  INFO [a-service,d0a7a4be9e9f3ab4,cb4cb09a83e0c553] 20570 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'

原因在于,当项目内没创建 logback-spring.xml 时,默认 pattern 中会包含 LOG_LEVEL_PATTERN 变量,类似于下面这个 logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %clr(${LOG_LEVEL_PATTERN:-%5p}) %magenta(${PID:- }) --- [%15.15t] %cyan(%-40.40logger{39}) : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>

        </filter>

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>

            <charset>utf8</charset>

        </encoder>

    </appender>

    <root level="INFO">
        <appender-ref ref="console"/>
    </root>

</configuration>

而在 sleuth 框架里面有一个拓展处理类,会将 LOG_LEVEL_PATTERN 变量替换成 %5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}] 值。因此就算没设置 %X{traceId}等值,依然会显示。
TraceEnvironmentPostProcessor.java

 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Map<String, Object> map = new HashMap();
        if (Boolean.parseBoolean(environment.getProperty("spring.sleuth.enabled", "true"))) {
            map.put("logging.pattern.level", "%5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}]");
        }

        this.addOrReplace(environment.getPropertySources(), map);
    }

另一种方式

https://blog.csdn.net/lujia_loney/article/details/91417898

不引入Sleuth , 使用AOP 在每个请求进来时生成Trace,然后放入MDC 中,然后可以放入请求头

什么是MDC

MDC(Mapped Diagnostic Contexts) ,翻译过来就是:映射的诊断上下文 。意思是:在日志中 (映射的) 请求ID(requestId),可以作为我们定位 (诊断) 问题的关键字 (上下文)

有了MDC工具,只要在接口或切面植入 put 和 remove 代码,就可以在定位问题时,根据映射的唯一 requestID 快速过滤出某次请求的所有日志。另外,当客户端请求到来时,可以将客户端id,ip,请求参数等信息保存在MDC中,同时在logback.xml中配置,那么会自动在每个日志条目中包含这些信息。

MDC类基本原理其实非常简单,其内部持有一个ThreadLocal实例,用于保存context数据,MDC提供了put/get/clear等几个核心接口,用于操作ThreadLocal中的数据;ThreadLocal中的K-V,可以在logback.xml中声明,即在layout中通过声明 %X{Key} 来打印MDC中保存的此key对应的value在日志中。

相关阅读

7 分钟

Creeks 系统分布式链路追踪分析

项目使用 **Spring Cloud Sleuth** 做分布式链路追踪,**完全依赖自动配置,零手写代码**。所有 26 个微服务都在 中引入了 ,但**没有集成 Zipkin 做集中式可视化,也没有在业务代码中显式使用 Tracer/

面试#分布式链路追踪7 阅读 · 0 评论

评论需要登录。生产环境使用 GitHub 登录,本地可前往 登录页 使用开发登录。

还没有评论,来抢沙发。