第6章 Sleuth--鏈路追蹤

勇哥V587發表於2020-11-06

第6章 Sleuth–鏈路追蹤

6.1 鏈路追蹤介紹

在大型系統的微服務化構建中,一個系統被拆分成了許多模組。這些模組負責不同的功能,組合成 系統,最終可以提供豐富的功能。在這種架構中,一次請求往往需要涉及到多個服務。網際網路應用構建 在不同的軟體模組集上,這些軟體模組,有可能是由不同的團隊開發、可能使用不同的程式語言來實 現、有可能布在了幾千臺伺服器,橫跨多個不同的資料中心,也就意味著這種架構形式也會存在一些問題:

  • 如何快速發現問題?
  • 如何判斷故障影響範圍?
  • 如何梳理服務依賴以及依賴的合理性?
  • 如何分析鏈路效能問題以及實時容量規劃?

在這裡插入圖片描述

分散式鏈路追蹤(Distributed Tracing),就是將一次分散式請求還原成呼叫鏈路,進行日誌記錄, 效能監控並將一次分散式請求的呼叫情況集中展示。比如各個服務節點上的耗時、請求具體到達哪 臺機器 上、每個服務節點的請求狀態等等。

常見的鏈路追蹤技術有下面這些:

  • cat 由大眾點評開源,基於Java開發的實時應用監控平臺,包括實時應用監控,業務監控 。 整合 方案是通過程式碼埋點的方式來實現監控,比如: 攔截器,過濾器等。 對程式碼的侵入性很大,整合成 本較高。風險較大。
  • zipkin 由Twitter公司開源,開放原始碼分散式的跟蹤系統,用於收集服務的定時資料,以解決微 服務架構中的延遲問題,包括:資料的收集、儲存、查詢和展現。該產品結合spring-cloud-sleuth 使用較為簡單, 整合很方便, 但是功能較簡單。
  • pinpoint Pinpoint是韓國人開源的基於位元組碼注入的呼叫鏈分析,以及應用監控分析工具。特點 是支援多種外掛,UI功能強大,接入端無程式碼侵入。
  • skywalking SkyWalking是本土開源的基於位元組碼注入的呼叫鏈分析,以及應用監控分析工具。特點是支援多 種外掛,UI功能較強,接入端無程式碼侵入。目前已加入Apache孵化器。
  • Sleuth SpringCloud 提供的分散式系統中鏈路追蹤解決方案

注意:SpringCloud alibaba技術棧中並沒有提供自己的鏈路追蹤技術的,我們可以採用Sleuth + Zinkin來做鏈路追蹤解決方案

6.2 Sleuth入門

6.2.1 Sleuth介紹

SpringCloud Sleuth主要功能就是在分散式系統中提供追蹤解決方案。它大量借用了Google Dapper的設計, 先來了解一下Sleuth中的術語和相關概念。

  • Trace 由一組TraceId相同的Span串聯形成一個樹狀結構。為了實現請求跟蹤,當請求到達分散式系統的 入口端點時,只需要服務跟蹤框架為該請求建立一個唯一的標識(即TraceId),同時在分散式系 統內部流轉的時候,框架始終保持傳遞該唯一值,直到整個請求的返回。那麼我們就可以使用該唯 一標識將所有的請求串聯起來,形成一條完整的請求鏈路。
  • Span代表了一組基本的工作單元。為了統計各處理單元的延遲,當請求到達各個服務元件的時 候,也通過一個唯一標識(SpanId)來標記它的開始、具體過程和結束。通過SpanId的開始和結 束時間戳,就能統計該span的呼叫時間,除此之外,我們還可以獲取如事件的名稱。請求資訊等 後設資料。
  • Annotation 用它記錄一段時間內的事件,內部使用的重要註釋:
    cs(Client Send)客戶端發出請求,開始一個請求的生命
    sr(Server Received)服務端接受到請求開始進行處理, sr-cs = 網路延遲(服務呼叫的時間)
    ss(Server Send)服務端處理完畢準備傳送到客戶端,ss - sr = 伺服器上的請求處理時間cr (Client Reveived)客戶端接受到服務端的響應,請求結束。 cr - sr = 請求的總時間

在這裡插入圖片描述

6.2.2 Sleuth入門

微服務名稱, traceId, spanid,是否將鏈路的追蹤結果輸出到第三方平臺

[api-gateway,3977125f73391553,3977125f73391553,false]
[service-order,3977125f73391553,57547b5bf71f8242,false]
[service-product,3977125f73391553,449f5b3f3ef8d5c5,false]

接下來通過之前的專案案例整合Sleuth,完成入門案例的編寫。 修改父工程引入Sleuth依賴:
在這裡插入圖片描述
啟動微服務,呼叫之後,我們可以在控制檯觀察到sleuth的日誌輸出:
在這裡插入圖片描述
其中 5399d5cb061971bdTraceId5399d5cb061971bdSpanId,依次呼叫有一個全域性的 TraceId,將呼叫鏈路串起來。仔細分析每個微服務的日誌,不難看出請求的具體過程。

檢視日誌檔案並不是一個很好的方法,當微服務越來越多日誌檔案也會越來越多,通過Zipkin可以 將日誌聚合,並進行視覺化展示和全文檢索。

6.3 Zipkin的整合

6.3.1 ZipKin介紹

ZipkinTwitter 的一個開源專案,它基於Google Dapper實現,它致力於收集服務的定時資料, 以解決微服務架構中的延遲問題,包括資料的收集儲存查詢展現

我們可以使用它來收集各個伺服器上請求鏈路的跟蹤資料,並通過它提供的REST API介面來輔助我 們查詢跟蹤資料以實現對分散式系統的監控程式,從而及時地發現系統中出現的延遲升高問題並找出系 統效能瓶頸的根源。

除了面向開發的 API 介面之外,它也提供了方便的UI元件來幫助我們直觀的搜尋跟蹤資訊和分析請求 鏈路明細,比如:可以查詢某段時間內各使用者請求的處理時間等。
Zipkin 提供了可插拔資料儲存方式:In-MemoryMySqlCassandra 以及 Elasticsearch

在這裡插入圖片描述
上圖展示了 Zipkin 的基礎架構,它主要由 4 個核心元件構成:

  • Collector收集器元件,它主要用於處理從外部系統傳送過來的跟蹤資訊,將這些資訊轉換為 Zipkin內部處理的 Span 格式,以支援後續的儲存、分析、展示等功能。
  • Storage儲存元件,它主要對處理收集器接收到的跟蹤資訊,預設會將這些資訊儲存在記憶體中, 我們也可 以修改此儲存策略,通過使用其他儲存元件將跟蹤資訊儲存到資料庫中。
  • RESTful APIAPI 元件,它主要用來提供外部訪問介面。比如給客戶端展示跟蹤資訊,或是外接 系統訪問以實現監控等。
  • Web UIUI 元件, 基於API元件實現的上層應用。通過UI元件使用者可以方便而有直觀地查詢和分 析跟蹤資訊。

Zipkin分為兩端,一個是 Zipkin服務端,一個是 Zipkin客戶端客戶端也就是微服務的應用客戶端會 配置服務端的 URL 地址一旦發生服務間的呼叫的時候,會被配置在微服務裡面的 Sleuth 的監聽器監 聽,並生成相應的 Trace 和 Span 資訊傳送給服務端

6.3.2 ZipKin服務端安裝

第1步: 下載ZipKin的jar包

https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin- server&v=LATEST&c=exec

訪問上面的網址,即可得到一個jar包,這就是ZipKin服務端的jar包 第2步: 通過命令列,輸入下面的命令啟動ZipKin Server

java -jar zipkin-server-2.12.9-exec.jar

第3步:通過瀏覽器訪問 http://localhost:9411訪問

在這裡插入圖片描述

6.3.3 Zipkin客戶端整合

ZipKin客戶端和Sleuth的整合非常簡單,只需要在微服務中新增其依賴和配置即可。
第1步:在每個微服務上新增依賴
在這裡插入圖片描述
第2步:新增配置

在這裡插入圖片描述
第3步: 訪問微服務

http://localhost:7000/order-serv/order/prod/1

第4步: 訪問zipkin的UI介面,觀察效果

在這裡插入圖片描述
第5步:點選其中一條記錄,可觀察一次訪問的詳細線路。

在這裡插入圖片描述

6.4 ZipKin資料持久化

Zipkin Server預設會將追蹤資料資訊儲存到記憶體,但這種方式不適合生產環境。Zipkin支援將追蹤 資料持久化到mysql資料庫或elasticsearch中

6.4.1 使用mysql實現資料持久化

第1步: 建立mysql資料環境

CREATE TABLE IF NOT EXISTS zipkin_spans 
( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', 
`trace_id` BIGINT NOT NULL,
 `id` BIGINT NOT NULL, 
 `name` VARCHAR(255) NOT NULL,
  `parent_id` BIGINT, 
  `debug` BIT(1), 
  `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
  `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds'; ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames'; ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';
  CREATE TABLE IF NOT EXISTS zipkin_annotations ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',`endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null') ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
  ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job'; CREATE TABLE IF NOT EXISTS zipkin_dependencies ( `day` DATE NOT NULL, `parent` VARCHAR(255) NOT NULL, `child` VARCHAR(255) NOT NULL, `call_count` BIGINT ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

第2步: 在啟動ZipKin Server的時候,指定資料儲存的mysql的資訊

java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql – MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root - -MYSQL_PASS=root

6.4.2 使用elasticsearch實現資料持久化

第1步: 下載elasticsearch 下載地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-8-4

第2步: 啟動elasticsearch
在這裡插入圖片描述
第3步: 在啟動ZipKin Server的時候,指定資料儲存的elasticsearch的資訊

java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=elasticsearch --ES- HOST=localhost:9200

相關文章