乐趣区

关于java:Dubbo日志链路追踪TraceId选型

一、目标

开发排查零碎问题用得最多的伎俩就是查看系统日志,然而在分布式环境下应用日志定位问题还是比拟麻烦,须要借助 全链路追踪 ID 把上下文串联起来,本文次要分享基于 Spring Boot + Dubbo 框架下 日志链路追踪 ID 的实现计划选型思路。

 

目前大多数分布式追踪零碎的思维模型都来自 Google’s Dapper 论文

全链路追踪的核心思想:

  • 为每条申请都独自调配一个惟一的 traceId 用来标识一条申请链路,该 traceId 会贯通整个申请处理过程的所有服务
  • 每个服务 / 线程都领有本人的 spanId 标识,代表申请的其中一段解决步骤
  • 一个申请蕴含一个 traceId 和一个或多个 spanId

日志全链路追踪 就是在每条系统日志里都增加显示 traceIdspanId 信息

 

二、计划选型

2.1. 计划一 (apm-toolkit)

这是 SkyWalking 的一个日志插件,通过这个插件能够在日志中输入
traceId

2.1.1. 应用形式

配置依赖 ,在 pom 文件中增加以下内容

<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.1.0</version>
</dependency>

 

配置日志模板 ,批改 logback-spring.xml 文件中 Appender 元素的 encoder 为以下内容

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{35} - %msg%n</pattern>
    </layout>
</encoder>

ps: pattern 中的内容按需批改,其中的 %tid 就是相当于 traceId,默认 TID:N/A,当有申请调用时会生成并显示 traceId

 

2.1.2. 总结

  • 长处 :无需编码,业务无入侵,可与 SkyWalking 的图形化界面中应用该 ID 疾速定位各种接口的调用关系。
  • 毛病 :强耦合 SkyWalking 能力失效

    • 必须增加 sk 的 javaagent
    • 必须部署 SkyWalking 服务端

 

2.2. 计划二 (sleuth)

SleuthSpring Cloud 的组件之一,它为 Spring Cloud 实现了一种分布式追踪解决方案,兼容 Zipkin,HTrace 与其余日志追踪零碎

2.2.1. 应用形式

配置父依赖 ,在 pom 文件中增加以下内容治理版本号

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth</artifactId>
            <version>2.2.4.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
</dependencyManagement>

 

配置依赖 ,在 pom 文件中增加以下内容

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

 

适配 dubbo,要让 sleuth 反对 dubbo 框架,须要减少以下两个步骤:

首先增加 dubbo 的插件依赖

<dependency>
    <groupId>io.zipkin.brave</groupId>
    <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
    <version>5.12.6</version>
</dependency>

配置 dubbo 过滤器

dubbo:
  provider:
    filter: tracing
  consumer:
    filter: tracing

 

配置日志模板 ,批改 logback-spring.xml 文件中 Appender 元素的 encoder 为以下内容

<encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{X-B3-TraceId},%X{X-B3-SpanId}] [%thread] %-5level %logger{35} - %msg%n</pattern>
    <charset>utf-8</charset>
</encoder>

ps: pattern 中的内容按需批改,其中的 %X{X-B3-TraceId} 为 traceId,%X{X-B3-SpanId} 为 spanId

 

2.2.2. 总结

  • 长处 :业务无入侵,有丰盛的插件进行扩大包含定时工作、MQ 等。
  • 毛病 brave-instrumentation-dubbo-rpc 不反对 dubbo 2.7.x 须要自行开发插件。

 

2.3. 计划三 (自研)

2.3.1. 无入侵减少 traceId

应用 LogbackMDC 机制,在日志模板中退出 traceId 标识,取值形式为 %X{traceId}

  1. 零碎入口(api 网关)创立 traceId 的值
  2. 应用 MDC 保留 traceId
  3. 批改 logback 配置文件模板格局增加标识 %X{traceId}

MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种不便在多线程条件下记录日志的性能。

 

2.3.2. 跨线程传递

解决 traceId 跨线程失落问题

因为 MDC 外部应用的是 ThreadLocal 所以只有本线程才无效,子线程和上游的服务 MDC 里的值会失落;

须要解决 Spring 的各种线程池与异步办法的父子线程间传递。

解决思路 :重写一个 MDCAdapter 应用阿里的 TransmittableThreadLocal 替换原来的 ThreadLocal 对象,解决各种线程池(ExecutorService / ForkJoinPool / TimerTask)父子过程传值问题。

须要应用 TtlRunnableTtlCallable 来润饰传入线程池的 RunnableCallable

 

2.3.3. 跨过程传递

解决 traceId 跨过程失落问题

dubbo 服务 应用 org.apache.dubbo.rpc.Filter 创立一个过滤器进行 traceId 传递

  • 服务消费者:负责传递链路追踪 ID
  • 服务提供者:负责接管 ID 并保留到 MDC

 

2.3.4. 总结

  • 长处 :业务无入侵,最小依赖,扩大灵便,适配性强。
  • 毛病 :须要自行实现,有大量的开发工作量。

 

三、计划总结

计划 开发工作量 可维护性 入侵性 性能
apm-toolkit 业务无入侵
sleuth 业务无入侵
自研 业务无入侵

 

扫码关注有惊喜!

退出移动版