18

Dubbo日志链路追踪TraceId选型

 3 years ago
source link: https://my.oschina.net/zlt2000/blog/4650869
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

yyeI7z6.png!mobile

一、目的

开发排查系统问题用得最多的手段就是查看系统日志,但是在分布式环境下使用日志定位问题还是比较麻烦,需要借助 全链路追踪ID 把上下文串联起来,本文主要分享基于 Spring Boot + Dubbo 框架下 日志链路追踪ID 的实现方案选型思路。

目前大多数分布式追踪系统的思想模型都来自 Google's Dapper 论文

zI7JzmU.png!mobile

全链路追踪的核心思想:

  • 为每条请求都单独分配一个唯一的 traceId 用来标识一条请求链路,该 traceId 会贯穿整个请求处理过程的所有服务
  • 每个服务/线程都拥有自己的 spanId 标识,代表请求的其中一段处理步骤
  • 一个请求包含一个 traceId 和一个或多个 spanId

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

RNVn2mV.png!mobile

二、方案选型

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 才能生效

    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 跨线程丢失问题

F3Anm2M.png!mobile

由于 MDC 内部使用的是 ThreadLocal 所以只有本线程才有效,子线程和下游的服务 MDC 里的值会丢失;

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

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

需要使用 TtlRunnableTtlCallable 来修饰传入线程池的 RunnableCallable

2.3.3. 跨进程传递

解决 traceId 跨进程丢失问题

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

MDC

2.3.4. 总结

  • 优点:业务无入侵,最小依赖,扩展灵活,适配性强。

  • 缺点:需要自行实现,有大量的开发工作量。

三、方案总结

方案 开发工作量 可维护性 入侵性 性能 apm-toolkit 无 低 业务无入侵 中 sleuth 中 中 业务无入侵 中 自研 高 高 业务无入侵 高

扫码关注有惊喜!

UfaUZfe.png!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK