Dubbo日誌鏈路追蹤TraceId選型

dapan發表於2021-09-09

原創 zlt2000 陶陶技術筆記 昨天

收錄於話題

#微服務

14個

點選上方“陶陶技術筆記”關注我

回覆“資料”獲取作者整理的大量學習資料!

鏈路追蹤ID

一、目的

開發排查系統問題用得最多的手段就是檢視系統日誌,但是在分散式環境下使用日誌定位問題還是比較麻煩,需要藉助 全鏈路追蹤ID  把上下文串聯起來,本文主要分享基於 Spring Boot + Dubbo 框架下 日誌鏈路追蹤ID 的實現方案選型思路。

 

目前大多數分散式追蹤系統的思想模型都來自 Google's Dapper 論文

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 服務端

 

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}

  1. 系統入口(api閘道器)建立 traceId 的值

  2. 使用 MDC 儲存 traceId

  3. 修改 logback 配置檔案模板格式新增標識 %X{traceId}

MDC(Mapped Diagnostic Context,對映除錯上下文)是 log4j 和 logback 提供的一種方便在多執行緒條件下記錄日誌的功能。

 

2.3.2. 跨執行緒傳遞

解決 traceId 跨執行緒丟失問題

file

由於 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業務無入侵
自研業務無入侵

文章推薦Dubbo想要個閘道器怎麼辦?試試整合Spring Cloud GatewaySpring Security基於Oauth2的SSO單點登入怎樣做?一個註解搞定微服務業務監控和行為分析怎麼做?試試日誌埋點Spring Cloud Gateway的動態路由怎樣做?整合Nacos實現很簡單Spring Cloud非同步場景分散式事務怎樣做?試試RocketMQSpring Cloud同步場景分散式事務怎樣做?試試Seata

我就知道你“在看”

陶陶技術筆記 發起了一個讀者討論關於 TraceId 的實現方式大家還有其他思路嗎?歡迎留言討論

相關文章