共计 2945 个字符,预计需要花费 8 分钟才能阅读完成。
一、目标
开发排查零碎问题用得最多的伎俩就是查看系统日志,然而在分布式环境下应用日志定位问题还是比拟麻烦,须要借助 全链路追踪 ID
把上下文串联起来,本文次要分享基于 Spring Boot
+ Dubbo
框架下 日志链路追踪 ID
的实现计划选型思路。
目前大多数分布式追踪零碎的思维模型都来自 Google’s Dapper 论文
全链路追踪的核心思想:
- 为每条申请都独自调配一个惟一的
traceId
用来标识一条申请链路,该traceId
会贯通整个申请处理过程的所有服务 - 每个服务 / 线程都领有本人的
spanId
标识,代表申请的其中一段解决步骤 - 一个申请蕴含一个
traceId
和一个或多个spanId
日志全链路追踪 就是在每条系统日志里都增加显示
traceId
和spanId
信息
二、计划选型
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
服务端
- 必须增加 sk 的
2.2. 计划二 (sleuth)
Sleuth
是 Spring 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
应用 Logback
的 MDC
机制,在日志模板中退出 traceId
标识,取值形式为 %X{traceId}
- 零碎入口(api 网关)创立
traceId
的值 - 应用
MDC
保留traceId
- 批改
logback
配置文件模板格局增加标识%X{traceId}
MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种不便在多线程条件下记录日志的性能。
2.3.2. 跨线程传递
解决 traceId
跨线程失落问题
因为 MDC
外部应用的是 ThreadLocal
所以只有本线程才无效,子线程和上游的服务 MDC
里的值会失落;
须要解决 Spring
的各种线程池与异步办法的父子线程间传递。
解决思路 :重写一个 MDCAdapter
应用阿里的 TransmittableThreadLocal
替换原来的 ThreadLocal
对象,解决各种线程池(ExecutorService
/ ForkJoinPool
/ TimerTask
)父子过程传值问题。
须要应用
TtlRunnable
和TtlCallable
来润饰传入线程池的Runnable
和Callable
2.3.3. 跨过程传递
解决 traceId
跨过程失落问题
dubbo 服务 应用 org.apache.dubbo.rpc.Filter
创立一个过滤器进行 traceId
传递
- 服务消费者:负责传递链路追踪 ID
- 服务提供者:负责接管 ID 并保留到
MDC
中
2.3.4. 总结
- 长处 :业务无入侵,最小依赖,扩大灵便,适配性强。
- 毛病 :须要自行实现,有大量的开发工作量。
三、计划总结
计划 | 开发工作量 | 可维护性 | 入侵性 | 性能 |
---|---|---|---|---|
apm-toolkit | 无 | 低 | 业务无入侵 | 中 |
sleuth | 中 | 中 | 业务无入侵 | 中 |
自研 | 高 | 高 | 业务无入侵 | 高 |
扫码关注有惊喜!