分佈式鏈路追蹤系統原來是這麼一回事




本篇主要內容

這篇主要是理論 + 實踐相結合。實踐部分涉及到如何把鏈路追蹤組件 Sleuth + Zipkin 加到個人 Spring Cloud 《佳必過》開源項目上。java

本篇知識點:git

  • 鏈路追蹤基本原理
  • 如何在項目中輕鬆加入鏈路追蹤中間件
  • 如何使用鏈路追蹤排查問題

1、爲何要用鏈路追蹤?

1.1 因:拆分服務單元

微服務架構實際上是一個分佈式的架構,按照業務劃分紅了多個服務單元。github

因爲服務單元的數量是不少的,有可能幾千個,並且業務也會更復雜,若是出現了錯誤和異常,很難去定位。web

1.2 因:邏輯複雜

好比一個請求須要調用多個服務才能完成整個業務閉環,而內部服務的代碼邏輯和業務邏輯比較複雜,假如某個服務出現了問題,是難以快速肯定那個服務出問題的。spring

1.3 果:快速定位

而若是咱們加上了分佈式鏈路追蹤,去跟蹤一個請求有哪些服務參與其中,參與的順序是怎樣的,這樣咱們就知道了每一個請求的詳細通過,即便出了問題也能快速定位。docker

2、鏈路追蹤的核心

鏈路追蹤組件有 Twitter 的可視化鏈路追蹤組件 Zipkin、Google 的 Dapper、阿里的 Eagleeye 等,而 Sleuth 是 Spring Cloud 的組件。Spring Cloud Sleuth 借鑑了 Dapper 的術語。shell

本文主要講解 Sleuth + Zipkin 結合使用來更好地實現鏈路追蹤。數據庫

爲何可以進行整條鏈路的追蹤?其實就是一個 Trace ID 將 一連串的 Span 信息連起來了。根據 Span 記錄的信息再進行整合就能夠獲取整條鏈路的信息。下面是鏈路追蹤的核心概念:api

2.1 Span(跨度)

  • 大白話:遠程調用和 Span  一對一瀏覽器

  • 基本的工做單元,每次發送一個遠程調用服務就會產生一個 Span。

  • Span 是一個 64 位的惟一 ID。

  • 經過計算 Span 的開始和結束時間,就能夠統計每一個服務調用所花費的時間。

2.2 Trace(跟蹤)

  • 大白話:一個 Trace 對應多個 Span,一對多

  • 它由一系列 Span 組成,樹狀結構。

  • 64 位惟一 ID。

  • 每次客戶端訪問微服務系統的 API 接口,可能中間會調用多個微服務,每次調用都會產生一個新的 Span,而多個 Span 組成了 Trace

2.3 Annotation(註解)

鏈路追蹤系統定義了一些核心註解,用來定義一個請求的開始和結束,注意是微服務之間的請求,而不是瀏覽器或手機等設備。註解包括:

  • cs - Client Sent:客戶端發送一個請求,描述了這個請求調用的 Span 的開始時間。注意:這裏的客戶端指的是微服務的調用者,不是咱們理解的瀏覽器或手機等客戶端。
  • sr - Server Received:服務端得到請求並準備開始處理它,若是將其 sr 減去 cs 時間戳,便可獲得網絡傳輸時間。
  • ss - Server Sent:服務端發送響應,會記錄請求處理完成的時間, ss 時間戳減去 sr 時間戳,便可獲得服務器請求的時間。
  • cr - Client Received:客戶端接收響應,Span 的結束時間,若是 cr 的時間戳減去 cs 時間戳,便可獲得一次微服務調用所消耗的時間,也就是一個 Span 的消耗的總時間。

2.4 鏈路追蹤原理

假定三個微服務調用的鏈路以下圖所示:Service 1 調用 Service 2Service 2 調用 Service 3 和 Service 4。

微服務調用鏈路圖

那麼鏈路追蹤會在每一個服務調用的時候加上 Trace ID 和 Span ID。以下圖所示:

鏈路追蹤原理圖

大白話解釋:

  • 你們注意上面的顏色,相同顏色的表明是同一個 Span ID,說明是鏈路追蹤中的一個節點。

  • 第一步:客戶端調用 Service 1,生成一個 RequestTrace IDSpan ID 爲空,那個時候請求尚未到 Service 1

  • 第二步:請求到達 Service 1,記錄了 Trace ID = X,Span ID 等於 A。

  • 第三步:Service 1 發送請求給 Service 2,Span ID 等於 B,被稱做 Client Sent,即客戶端發送一個請求。

  • 第四步:請求到達 Service 2,Span ID 等於 B,Trace ID 不會改變,被稱做 Server Received,即服務端得到請求並準備開始處理它。

  • 第五步:Service 2 開始處理這個請求,處理完以後,Trace ID 不變,Span ID = C。

  • 第六步:Service 2 開始發送這個請求給 Service 3,Trace ID 不變,Span ID = D,被稱做 Client Sent,即客戶端發送一個請求。

  • 第七步:Service 3 接收到這個請求,Span ID = D,被稱做 Server Received。

  • 第八步:Service 3 開始處理這個請求,處理完以後,Span ID = E。

  • 第九步:Service 3 開始發送響應給 Service 2,Span ID = D,被稱做 Server Sent,即服務端發送響應。

  • 第十步:Service 3 收到 Service 2 的響應,Span ID = D,被稱做 Client Received,即客戶端接收響應。

  • 第十一步:Service 2 開始返回 響應給 Service 1,Span ID = B,和第三步的 Span ID 相同,被稱做 Client Received,即客戶端接收響應。

  • 第十二步:Service 1 處理完響應,Span ID = A,和第二步的 Span ID 相同。

  • 第十三步:Service 1 開始向客戶端返回響應,Span ID = A、

  • Service 3 向 Service 4 發送請求和 Service 3 相似,對應的 Span ID 是 F 和 G。能夠參照上面前面的第六步到第十步。

把以上的相同顏色的步驟簡化爲下面的鏈路追蹤圖:

鏈路追蹤父子節點圖
  • 第一個節點:Span ID = A,Parent ID = null, Service 1 接收到請求。
  • 第二個節點:Span ID = B,Parent ID= A, Service 1 發送請求到 Service 2 返回響應給 Service 1 的過程。
  • 第三個節點:Span ID = C,Parent ID= B, Service 2 的 中間處理過程。
  • 第四個節點:Span ID = D,Parent ID= C, Service 2 發送請求到 Service 3 返回響應給 Service 2 的過程。
  • 第五個節點:Span ID = E,Parent ID= D, Service 3 的中間處理過程。
  • 第六個節點:Span ID = F,Parent ID= C, Service 3 發送請求到 Service 4 返回響應給 Service 3 的過程。
  • 第七個節點:Span ID = G,Parent ID= F,Service 4 的中間處理過程。

經過 Parent ID 便可找到父節點,整個鏈路就能夠進行跟蹤追溯了。

3、Spring Cloud 整合 Sleuth

你們能夠參照個人 GitHub 開源項目 PassJava(佳必過)。

3.1 引入 Spring Cloud 依賴

在 passjava-common 中引入 Spring Cloud 依賴

由於咱們使用的鏈路追蹤組件 Sleuth 是 Spring Cloud 的組件,因此咱們須要引入 Spring Cloud 依賴。

<dependencyManagement>
    <dependencies>
        <!--  Spring Cloud 依賴  -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.2 引入Sleuth依賴

引入鏈路追蹤組件 Sleuth 很是簡單,在 pom.xml 文件中引入 Sleuth 依賴便可。

在 passjava-common 中引入 Sleuth 依賴:

<!-- 鏈路追蹤組件 -->
<dependency>
 <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

3.3 經過日誌觀察鏈路追蹤

咱們先不整合 zipkin 鏈路追蹤可視化組件,而是經過日誌的方式來查看鏈路追蹤信息。

文件路徑:\PassJava-Platform\passjava-question\src\main\resources\application.properties
添加配置:
logging.level.org.springframework.cloud.openfeign=debug
logging.level.org.springframework.cloud.sleuth=debug

3.4 啓動微服務

啓動如下微服務:

  • passjava-gateway 服務(網關)

  • passjava-question 服務(題目中心微服務)

  • renren 服務(Admin 後臺管理服務)

    啓動成功後以下圖所示:

啓動微服務

3.5 測試跟蹤請求

打開 Admin 後臺,訪問題目中心->題目配置頁面,能夠看到發送了下面的請求:

http://localhost:8060/api/question/v1/admin/question/list?t=1605170539929&page=1&limit=10&key=
佳必過項目的後臺界面

打開控制檯,能夠看到打印出了追蹤日誌。

鏈路追蹤日誌

說明:

  • 當沒有配置 Sleuth 鏈路追蹤的時候,INFO 信息裏面是 [passjava-question,,,],後面跟着三個空字符串。
  • 當配置了 Sleuth 鏈路追蹤的時候,追蹤到的信息是 [passjava-question,504a5360ca906016,e55ff064b3941956,false] ,第一個是 Trace ID,第二個是 Span ID。

4、Zipkin 鏈路追蹤原理

上面咱們經過簡單的引入 Sleuth 組件,就能夠獲取到調用鏈路,但只能經過控制檯的輸出信息來看,不太方便。

Zipkin 油然而生,一個圖形化的工具。Zipkin 是 Twitter 開源的分佈式跟蹤系統,主要用來用來收集系統的時序數據,進而能夠跟蹤系統的調用問題。

並且引入了 Zipkin 組件後,就不須要引入 Sleuth 組件了,由於 Zipkin 組件已經幫咱們引入了。

Zipkin 的官網:https://zipkin.io

4.1 Zipkin 基礎架構

Zipkin 基礎架構

Zipkin 包含四大組件:

  • Collection(收集器組件),主要負責收集外部系統跟蹤信息。
  • Storage(存儲組件),主要負責將收集到的跟蹤信息進行存儲,默認存放在內存中,支持存儲到 MySQL 和 ElasticSearch。
  • API(查詢組件),提供接口查詢跟蹤信息,給 UI 組件用的。
  • UI (可視化 Web UI 組件),能夠基於服務、時間、註解來可視化查看跟蹤信息。注意:Web UI 不須要身份驗證。

4.2 Zipkin 跟蹤流程

Zipkin 跟蹤流程

流程解釋:

  • 第一步:用戶代碼發起 HTTP Get 請求,請求路徑:/foo。
  • 第二步:請求到到跟蹤工具後,請求被攔截,會被記錄兩項信息:標籤和時間戳。以及HTTP Headers 裏面會增長跟蹤頭信息。
  • 第三步:將封裝好的請求傳給 HTTP 客戶端,請求中包含 X-B3-TraceID 和 X-B3-SpanId 請求頭信息。
  • 第四步:由HTTP 客戶端發送請求。
  • 第五步:Http 客戶端返回響應 200 OK 後,跟蹤工具記錄耗時時間。
  • 第六步:跟蹤工具發送 200 OK 給用戶端。
  • 第七步:異步報告 Span 信息給 Zipkin 收集器。

5、整合 Zipkin 可視化組件

5.1 啓動虛擬機並鏈接

vagrant up
啓動虛擬機

接着就能夠用 Xshell 工具鏈接虛擬機了。下面是在命令行裏面執行相關操做。

5.2 docker 安裝 zipkin 服務

  • 使用如下命令開始拉取 zipkin 鏡像並啓動 zipkin 容器。
docker run -d -p 9411:9411 openzipkin/zipkin
  • 命令執行完後,會執行下載操做和啓動操做。
docker 安裝 zipkin 服務
  • 使用 docker ps 命令能夠看到 zipkin 容器已經啓動成功了。以下圖所示:
zipkin 容器啓動成功
  • 在瀏覽器窗口打開 zipkin UI

訪問服務地址:http://192.168.56.10:9411/zipkin。

5.3 引入 Zipkin 依賴

在公共模塊引入 zipkin 依賴

<!-- 鏈路追蹤組件 Zipkin -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

由於 zipkin 包裏面已經引入了 sleuth 組件,因此能夠把以前引入的 sleuth 組件刪掉。

5.4 添加 Zipkin 配置

在須要追蹤的微服務模塊下添加 zipkin 配置。

# zipkin 的服務器地址
spring.zipkin.base-url=http://192.168.56.10:9411/
# 關閉服務發現,不然 Spring Cloud 會把 zipkin 的 URL 看成服務名稱。
spring.zipkin.discovery-client-enabled=false
# 設置使用 http 的方式傳輸數據,也能夠用 RabbitMQ 或 Kafka。
spring.zipkin.sender.type=web
# 設置採樣率爲 100 %,默認爲 0.1(10%)
spring.sleuth.sampler.probability=1

5.5 測試 Zipkin 是否工做

這裏我在 passjava-member 微服務中寫了一個 API:

passjava-member 服務的 API:getMemberStudyTimeListTest,

訪問路徑爲/studytime/list/test/{id}。

passjava-member 服務遠程調用 passjava-study 服務。

對應的 API:getMemberStudyTimeListTest。

我用 postman 工具測試 passjava-member 服務的 API:

測試 Passjava-member 服務的 API

打開 Zipkin 工具,搜索 passjava-member 的鏈路追蹤日誌,能夠看到有一條記錄,相關說明以下圖所示:

zipkin 示例

從圖中能夠看到 passjava-member 微服務調用了 passjava-study 微服務,如圖中左半部分所示。

並且 passjava-study 微服務詳細的調用時間都記錄得很是清楚,如圖中右半部分所示。

時間計算:

  • 請求傳輸時間:Server Start - Client Start = 2.577s-2.339s = 0.238s
  • 服務端處理時間:Server Finish - Server Start = 2.863s - 2.577s = 0.286s
  • 請求總耗時:Client Finish - Client Start = 2.861s - 2.339s = 0.522s
  • Passjava-member 服務總耗時:3.156 s
  • Passjava-study 服務總耗時:0.521s
  • 由此能夠看出 passjava-member 服務 花費了很長時間,性能不好

另外還能夠用圖表的方式查看跟蹤信息,這裏不作展開了。

圖表的方式查看

6、Zipkin 數據持久化

6.1 Zipkin 支持的數據庫

Zipkin 存儲數據默認是放在內存中的,若是 Zipkin 重啓,那麼監控數據也會丟失。若是是生成環境,數據丟失會帶來很大問題,因此須要將 Zipkin 的監控數據持久化。而 Zipkin 支持將數據存儲到如下數據庫:

  • 內存(默認,不建議使用)
  • MySQL(數據量大的話, 查詢較爲緩慢,不建議使用)
  • Elasticsearch(建議使用)
  • Cassandra(國內使用 Cassandra 的公司較少,相關文檔也很少)

6.2 使用 Elasticsearch 做爲儲存介質

  • 經過 docker 的方式配置 elasticsearch 做爲 zipkin 數據的存儲介質。
docker run --env STORAGE_TYPE=elasticsearch --env ES_HOSTS=192.168.56.10:9200 openzipkin/zipkin-dependencies
  • ES 做爲存儲介質的配置參數:
ES 做爲存儲介質的配置參數

7、總結

本篇講解了鏈路追蹤的核心原理,以及 Sleuth + Zipkin 的組件的原理,以及將這兩款組件加到了個人開源項目《佳必過》裏面了。

開源項目地址:https://github.com/Jackson0714/PassJava-Platform


       
   
刨根問底,Kafka 消息中間件到底會不會丟消息
炸了!一口氣問了我18個JVM問題!
深度揭祕垃圾回收底層,此次讓你完全弄懂她

以爲不錯,點個在看~

本文分享自微信公衆號 - 武培軒(wupeixuan404)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索