一、目的

开发排查系统问题用得最多的手段就是查看系统日志,但是在分布式环境下使用日志定位问题还是比较麻烦,需要借助 全链路追踪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 业务无入侵
自研 业务无入侵

扫码关注有惊喜!

Dubbo日志链路追踪TraceId选型的更多相关文章

  1. SpringBoot之微服务日志链路追踪

    SpringBoot之微服务日志链路追踪 简介 在微服务里,业务出现问题或者程序出的任何问题,都少不了查看日志,一般我们使用 ELK 相关的日志收集工具,服务多的情况下,业务问题也是有些难以排查,只能 ...

  2. 全链路追踪traceId,ThreadLocal与ExecutorService

    关于全链路追踪traceId遇到线程池的问题,做过架构的估计都遇到过,现在以写个demo,总体思想就是获取父线程traceId,给子线程,子线程用完移除掉. mac上的chrome时不时崩溃,写了一大 ...

  3. 全链路追踪技术选型:pinpoint vs skywalking

    目前分布式链路追踪系统基本都是根据谷歌的<Dapper大规模分布式系统的跟踪系统>这篇论文发展而来,主流的有zipkin,pinpoint,skywalking,cat,jaeger等. ...

  4. 应用SpringAOP及Tlog工具完成日志链路追踪、收集、持久化

    一.痛点 目前我司各系统的日志管理比较原始,使用logback打日志到log文件,虽然有服务管理平台,但记录的日志也仅仅是前置机调用后台系统的出入参,当遇到问题时查日志较为麻烦. 登录VPN-打开服务 ...

  5. dubbo traceId透传实现日志链路追踪(基于Filter和RpcContext实现)

    一.要解决什么问题: 使用elk的过程中发现如下问题: 1.无法准确定位一个请求经过了哪些服务 2.多个请求线程的日志交替打印,不利于查看按时间顺序查看一个请求的日志. 二.期望效果 能够查看一个请求 ...

  6. Dubbo 全链路追踪日志的实现

    微服务架构的项目,一次请求可能会调用多个微服务,这样就会产生多个微服务的请求日志,当我们想要查看整个请求链路的日志时,就会变得困难,所幸的是我们有一些集中日志收集工具,比如很热门的ELK,我们需要把这 ...

  7. 从 1.5 开始搭建一个微服务框架——日志追踪 traceId

    你好,我是悟空. 前言 最近在搭一个基础版的项目框架,基于 SpringCloud 微服务框架. 如果把 SpringCloud 这个框架当做 1,那么现在已经有的基础组件比如 swagger/log ...

  8. 基于SLF4J的MDC机制和Dubbo的Filter机制,实现分布式系统的日志全链路追踪

    原文链接:基于SLF4J的MDC机制和Dubbo的Filter机制,实现分布式系统的日志全链路追踪 一.日志系统 1.日志框架 在每个系统应用中,我们都会使用日志系统,主要是为了记录必要的信息和方便排 ...

  9. 原理分析dubbo分布式应用中使用zipkin做链路追踪

    zipkin是什么 Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper的论文设计而来,由 Twitter 公司开 ...

  10. 原理分析dubbo分布式应用中使用zipkin做链路追踪(转)

    作者:@nele本文为作者原创,转载请注明出处:https://www.cnblogs.com/nele/p/10171794.html 目录 zipkin是什么为什么使用Zipkinzipkin架构 ...

随机推荐

  1. Flutter(四):Flutter 语言 Dart基础使用

    一.变量和常量 变量 var a = 1; var str = 'abc'; 常量 const PI = 3.14; 不可变对象 final PI = 3.14; final TIME = new D ...

  2. powerpoint 无法打开文件

    PowerPoint 无法打开文件 出现的问题 今天下载老师放在学习通的ppt,居然不能打开,记录一下 点击修复后出现: 这并不是文件损坏了,而是powerpoint出于安全的考虑,为了保护我们的计算 ...

  3. JS注释 JS变量

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  4. 绑定style

    ² 对象语法 <div:style="{color: redColor, fontSize: '20px'}">对象写法</div> data: { red ...

  5. 剑指Offer-54.字符流中第一个不重复的字符(C++/Java)

    题目: 请实现一个函数用来找出字符流中第一个只出现一次的字符.例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g".当从该字符流中读出前 ...

  6. 机器学习决策树ID3算法,python实现代码

    机器学习决策树ID3算法,python实现代码 看到techflow介绍ID3算法,中间有代码示例.代码尝试执行力下,发现有错误. https://www.cnblogs.com/techflow/p ...

  7. Redis的特点什么是?

    a.支持多种数据结构,如 string(字符串). list(双向链表).dict(hash表).set(集合).zset(排序set).hyperloglog(基数估算) b.支持持久化操作,可以进 ...

  8. java8 多条件的filter过滤

    java8 多条件的filter过滤 package com.example.core.mydemo.java; import java.io.Serializable; import java.ti ...

  9. Operational Property Graphs到底是个啥?

    Operational Property Graphs,中文通常译为"操作属性图". 作为23ai中被官方highlight出的新特性之一,我们先看下官方的原文描述: Operat ...

  10. 高通Andriod开机流程与镜像说明

    # 高通Andriod开机流程与镜像说明 Android镜像说明 Android设备刷机时都需要ROM包,ROM包下面有很多的.img和其他的相关镜像文件,其中这里面包含了Android很多的分区,A ...