分散式鏈路追蹤技術

尹瑞星發表於2022-03-15

概述

在微服務架構的系統中,請求在各服務之間流轉,呼叫鏈錯綜複雜,一旦出現了問題和異常,很難追查定位,這個時候就需要鏈路追蹤來幫忙了。鏈路追蹤系統能追蹤並記錄請求在系統中的呼叫順序,呼叫時間等一系列關鍵資訊,從而幫助我們定位異常服務和發現效能瓶頸。

img

微服務的監控主要包含一下三個方面:

  • 通過收集日誌,對系統和各個服務的執行狀態進行監控
  • 通過收集量度(Metrics),對系統和各個服務的效能進行監控
  • 通過分散式追蹤,追蹤服務請求是如何在各個分佈的元件中進行處理的細節

對於是日誌和量度的收集和監控,大家會比較熟悉。常見的日誌收集架構包含利用Fluentd對系統日誌進行收集,然後利用ELK或者Splunk進行日誌分析。而對於效能監控,Prometheus是常見的流行的選擇。

分散式鏈路跟蹤主要功能:

  • 故障快速定位:可以通過呼叫鏈結合業務日誌快速定位錯誤資訊。
  • 鏈路效能視覺化:各個階段鏈路耗時、服務依賴關係可以通過視覺化介面展現出來。
  • 鏈路分析:通過分析鏈路耗時、服務依賴關係可以得到使用者的行為路徑,彙總分析應用在很多業務場景。

基本原理

目前常見的鏈路追蹤系統的原理基本都是根據2010年由谷歌釋出的一篇《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》論文為原型實現的。

img

Trace

指一個請求經過所有服務的路徑,每一條區域性鏈路都用一個全域性唯一的traceid來標識。

Span

為了表達父子呼叫關係,引入了span

同一層級parent id相同,span id不同,span id從小到大表示請求的順序。

總結:通過事先在日誌中埋點,找出相同traceId的日誌,再加上parent id和span id就可以將一條完整的請求呼叫鏈串聯起來。

Annotations

Dapper中還定義了annotation的概念,用於使用者自定義事件,用來輔助定位問題。

通常包含以下四個Annotaion註解資訊,分別對應客戶端和服務端相應事件。

img

呼叫耗時可以通過T4-T1得到,客戶端傳送資料包的網路耗時可以通過T2-T1實現。

鏈路資訊的還原依賴於帶內和帶外兩種資料。

帶外資料是各個節點產生的事件,如cs,ss,這些資料可以由節點獨立生成,並且需要集中上報到儲存端。

帶內資料如traceid,spanid,parentid,這些資料需要從鏈路的起點一直傳遞到終點。通過帶內資料的傳遞,可以將一個鏈路的所有過程串起來。

取樣和儲存

為了減少效能消耗,避免儲存資源的浪費,dapper並不會上報所有的span資料,而是使用取樣的方式。舉個例子,每秒有1000個請求訪問系統,如果設定取樣率為1/1000,那麼只會上報一個請求到儲存端。

鏈路中的span資料經過收集和上報後會集中儲存在一個地方,Dapper使用了BigTable資料倉儲,常用的儲存還有ElasticSearch, HBase, In-memory DB等。

Opentraceing 資料模型

Opentracing 是分散式鏈路追蹤的一種規範標準,是 CNCF(雲原生計算基金會)下的專案之一。只要某鏈路追蹤系統實現了 Opentracing 規定的介面(interface),符合Opentracing 定義的表現行為,那麼就可以說該應用符合 Opentracing 標準。

它的資料模型和谷歌Dapper論文裡的如出一轍。

span

Span 是一條追蹤鏈路中的基本組成要素,一個 Span 表示一個獨立的工作單元,比如可以表示一次函式呼叫,一次 HTTP 請求等等。Span 會記錄如下基本要素:

  • 服務名稱(operation name)

  • 服務的開始時間和結束時間

  • K/V形式的Tags

    儲存使用者自定義標籤,主要用於鏈路追蹤結果的查詢過濾。Span 中的 tag 僅自己可見,不會隨著 SpanContext 傳遞給後續 Span。

  • K/V形式的Logs

    與 tags 不同的是,logs 還會記錄寫入 logs 的時間,因此 logs 主要用於記錄某些事件發生的時間

  • SpanContext

    SpanContext攜帶著一些用於跨服務通訊的(跨程式)資料,主要包含:

    • 足夠在系統中標識該span的資訊,比如:span_id,trace_id
    • Baggage Items,為整條追蹤鏈儲存跨服務(跨程式)的K/V格式的使用者自定義資料。
  • References:該span對一個或多個span的引用(通過引用SpanContext)

trace

Trace表示一次完整的追蹤鏈路,trace由一個或多個span組成。

Inject/Extract

Opentracing 提供了 Inject/Extract 用於在請求中注入 SpanContext 或者從請求中提取出 SpanContext。

客戶端通過 Inject 將 SpanContext 注入到載體中,隨著請求一起傳送到服務端。

服務端則通過 Extract 將 SpanContext 提取出來,進行後續處理。

常見框架

框架對比

Google Dapper論文發出來之後,很多公司基於鏈路追蹤的基本原理給出了各自的解決方案,具體如下:

  • Twitter:Zipkin
  • Uber:Jaeger
  • Elastic Stack:Elastic APM
  • Apache:SkyWalking(國內開源愛好者吳晟開源)
  • Naver:Pinpoint(韓國公司開發)
  • 阿里:鷹眼。
  • 大眾點評:Cat。
  • 京東:Hydra

為了便於各系統間能彼此相容互通,OpenTracing組織制定了一系列標準,旨在讓各系統提供統一的介面。

國內這些基本都沒開源,主要的開源框架對比如下:

img

原理

Zipkin

Zipkin 相對成熟,開源於2012年,同時也比較簡單,Java 系大部分都會選擇 Zipkin。

img

在服務執行的過程中會產生很多鏈路資訊,產生資料的地方可以稱之為Reporter。將鏈路資訊通過多種傳輸方式如HTTP,RPC,kafka訊息佇列等傳送到Zipkin的採集器,Zipkin處理後最終將鏈路資訊儲存到儲存器中。運維人員通過UI介面呼叫介面即可查詢呼叫鏈資訊。

Jaeger

Jaeger 則是 CNCF 旗下,對 K8s 有較好的相容性,Go 語言系可能是個不錯的選擇。

jaeger-architecture.png

Jaeger的原理和Zipkin二者的架構有些類似。都是由嵌入到程式碼中的client來收集資料,並傳輸到Collector端進行儲存,然後集中通過UI進行展示。

具體流程如下:

  • 1)客戶端通過 6831 埠上報資料給 agent
  • 2)agent通過 14250 埠將資料傳送給 collector
  • 3)collector 將資料寫入 kafka
  • 4)Ingester 從 kafka中讀取資料並寫入儲存後端
  • 5)query 從儲存後端查詢資料並展示

另外近兩年基於 ServiceMesh 的 ”無” 侵入式鏈路追蹤也廣受歡迎,似乎是一個被看好的方向,其代表作之一 Istio 便是使用 CNCF 出身的 Jaeger,且 Jaeger 還相容 Zipkin,在這點上 Jaeger 完勝。

相關文章