1. 程式人生 > >螞蟻金服分散式鏈路跟蹤元件 SOFATracer 總覽 | 剖析

螞蟻金服分散式鏈路跟蹤元件 SOFATracer 總覽 | 剖析

SOFA
Scalable Open Financial Architecture
是螞蟻金服自主研發的金融級分散式中介軟體,包含了構建金融級雲原生架構所需的各個元件,是在金融場景裡錘鍊出來的最佳實踐。


SOFATracer 是一個用於分散式系統呼叫跟蹤的元件,通過統一的 TraceId 將呼叫鏈路中的各種網路呼叫情況以日誌的方式記錄下來,以達到透視化網路呼叫的目的,這些鏈路資料可用於故障的快速發現,服務治理等。


本文為《剖析 | SOFATracer 框架》第一篇。《剖析 | SOFATracer 框架》系列由 SOFA 團隊和原始碼愛好者們出品,專案代號:<SOFA:TracerLab/>

文章尾部有參與方式,歡迎同樣對原始碼熱情的你加入。


0. 前言

在單體應用時代,我們不需要花費時間去關心呼叫鏈路這個東西。
但是鏈路跟蹤不僅僅是在分散式場景下才會有,即使是單體應用,同樣也會存在呼叫鏈路。

例如,我們把應用中的每個服務介面作為一個鏈路節點,那麼從請求進來到返回響應,把這個過程中多歷經的所有的方法介面串聯起來,就能組成一條完整的鏈路,如下圖所示:

對於單體應用而言,如果訪問一個資源沒有成功,那麼我們可以很快的鎖定是哪一臺機器,然後通過查詢這臺機器上的日誌就能定位問題。
但是在微服務體系架構下,這種方式會顯得非常無力。對於一個稍具規模的應用來說,一次請求可能會跨越相當多的服務節點,在這種情況下,如果一個請求沒有得到成功的響應,就不能確定到底是哪個節點出了問題。

因此在面對這種複雜的大規模分散式叢集來實現的服務體系來說,就需要一些可以幫助理解各個應用的線上呼叫行為、並可以分析遠端呼叫的元件。

基於上述背景,螞蟻金服開源了基於 OpenTracing 規範(http://opentracing.io/documentation/pages/spec.html)實現的 SOFATracer 分散式鏈路跟蹤元件,為實施大規模服務化體系架構場景下提供了鏈路跟蹤的解決方案。

在介紹 SOFATracer 之前,先來了解一下 Opentracing 規範。

1. Opentracing 簡介

首先來解釋下 OpenTracing 是什麼OpenTracing

致力於為分散式跟蹤建立更標準化的API和工具,它由完整的API規範、實現該規範的框架、庫以及專案文件組成。

OpenTracing 提供了一套平臺無關、廠商無關的 API,這樣不同的組織或者開發人員就能夠更加方便的新增或更換追蹤系統的實現。 OpenTracing API 中的一些概念和術語,在不同的語言環境下都是共享的。

1.1 資料模型

Opentracing 規範中,一條 trace 鏈路是由多個與之關聯的 span 組成,一條鏈路整體可以看做是一張有向無環圖,各個span之間的邊緣關係被稱之為“References”。下面是官方提供的示例:


如果以時間軸維度來看的話,也可以表現為下面的形式(官方示例):


  • root span : 當前鏈路中的第一個 span

  • ChildOfFollowFrom 是目前被定義的兩種 References 型別

    • ChildOf : 父 Span 某種程度上取決於子Span, (子Span的結果可能會對父Span產生影響)

    • FollowFrom : 父 Span 不以任何方式依賴子 Span

但是為了簡化 span 之間的這種依賴關係,在具體實現時通常會將具有巢狀關係的作為 ChildOf,平行執行的作為FollowFrom,比如:

a. ChildOf 示例

methodA 中呼叫了 method B :

methodA(){            // spanA start
    methodB();            
}                     // spanA finish
methodB(){            // spanB start
}                     // spanB finish
複製程式碼


產生的 span 在時間維度上展現的視角如下:

這種關係一般會表示為 SpanB ChildOf SpanA

b. FollowFrom 示例

method 方法中,methodA 執行之後 methodB 執行 :

method(){
    methodA();
    methodB();
}
複製程式碼


產生的 span 在時間維度上展現的視角如下:

這種關係一般會表示為 SpanB FollowFrom SpanA

1.2 API

Opentracing API 是對分散式鏈路中涉及到的一些列操作的高度抽象集合。Opentracing 中將所有核心的元件都宣告為介面,例如 TracerSpanSpanContextFormat(高版本中還包括 ScopeScopeManager)等。SOFATracer 使用的版本是 0.22.0 ,主要是對 TracerSpanSpanContext 三個概念模型的實現。下面就針對這三個元件結合 SOFATracer 來分析。

1.3 SOFATracer 標準實現

下圖為 SOFATracer 中對於這三個核心介面實現的類圖結構:

由於篇幅原因,下面的介紹過程中一些點不會展開說明,有興趣的同學可以自行官網檢視完整的 OpenTracing-api 規範 (https://opentracing.io/specification/)。

a. Tracer & SOFATracer

Tracer 是一個簡單、廣義的介面,它的作用就是構建 span 和傳輸 span 。核心介面列表如下:

介面

描述

SpanBuilder buildSpan(String operationName)

根據指定的operationName構建一個新的span

<C> void inject(SpanContext spanContext, Format<C> format, C carrier);

將 spanContext 以 format 的格式注入到 carrier 中

<C> SpanContext extract(Format<C> format, C carrier);

以 format 的格式從carrier中解析出 SpanContext

SofaTracer 實現了 Tracer 介面,並擴充套件了取樣、資料上報等能力。

b. Span & SOFATracerSpan

Span 是一個跨度單元,在實際的應用過程中,Span 就是一個完整的資料包,其包含的就是當前節點所需要上報的資料。核心介面列表如下:

介面

描述

SpanContext context()

從 span 中獲取 SpanContext

void finish()/void finish(long finishMicros)

結束一個 span

void close()

關閉 span

Span setTag(String key, value)

設定 tags

Span log(long timestampMicroseconds, String event)

設定 log 事件

Span setOperationName(String operationName)

設定span的operationName

Span setBaggageItem(String key, String value)

設定 BaggageItem

String getBaggageItem(String key)

獲取 BaggageItem


關於tagslog的解釋:如果把從進入公司到離開公司這段時間作為一個 span,那麼 tags 裡面可以是你寫的程式碼,你喝的水,甚至你講過的話;log 則更關注某個時刻的事,比如在12:00 去吃了個飯,在15:00 開了個會。

如果說 tags 裡面都是和公司有關的,那麼 Baggage 裡面則不僅僅是侷限於你在公司的事,比如你口袋裡的手機。

SofaTracerSpan 在實現 Span 介面,並擴充套件了對 Referencetags、執行緒非同步處理以及外掛擴充套件中所必須的 logType 和產生當前 span Tracer 型別等處理的能力。

c. SpanContext & SOFATracerSpanContext

SpanContext 對於 OpenTracing 實現是至關重要的,通過 SpanContext 可以實現跨程序的鏈路透傳,並且可以通過 SpanContext 中攜帶的資訊將整個鏈路串聯起來。

官方文件中有這樣一句話:“在 OpenTracing 中,我們強迫 SpanContext 例項成為不可變的,以避免 Spanfinishreference 操作時會有複雜的生命週期問題。” 這裡是可以理解的,如果 SpanContext 在透傳過程中發生了變化,比如改了 tracerId,那麼就可能導致鏈路出現斷缺。

SpanContext 中只有一個介面:

介面

描述

Iterable<Map.Entry<String, String>> baggageItems();

拿到所有的baggageItems 透傳資料

SofaTracerSpanContext 實現了 SpanContext 介面,擴充套件了構建 SpanContext、序列化 baggageItems 以及SpanContext等新的能力,除此之外,SpanContext 在跨進行透傳時攜帶的資訊進行了規範:

攜帶資訊
描述

traceId

全鏈路唯一的標識資訊

spanId

spanId

parentId

父spanId

isSampled

取樣標記

sysBaggage

系統透傳資料

bizBaggage

業務透傳資料

2. SOFATracer 擴充套件

為了滿足在複雜場景下的鏈路跟蹤需求,SOFATracerOpentracing 規範基礎上又提供了豐富的擴充套件能力。

2.1 SOFATracer 架構及功能擴充套件

SOFATracer 基於 OpenTracing 規範(https://opentracing.io/specification/)實現,並且通過 Disruptor (https://github.com/LMAX-Exchange/disruptor)元件實現了日誌的無鎖非同步列印能力。

  • 基於 SLF4J 的 MDC 擴充套件能力

應用在通過面向日誌程式設計介面 SLF4J 列印應用日誌時,可以只在對應的日誌實現配置檔案的 PatternLayout 中新增相應的引數即可,如新增 [%X{SOFA-TraceId},%X{SOFA-SpanId}] ,那麼應用日誌就可以在發生鏈路呼叫時打印出相應的 TraceIdSpanId ,而無論應用具體的日誌實現是 LogbackLog4j2 或者 Log4j。關於這部分的實現原理,期待大家一起編寫,領取方式見文末。

  • SOFATracer 的埋點機制

SOFATracer 目前僅提供了基於自身 API 埋點的方式。SOFATracer 中所有的外掛均需要實現自己的 Tracer 例項,如 MvcSpringMvcTracerHttpClientHttpClientTracer 等,如下圖所示:

SOFATracer 將不同的擴充套件元件分為 AbstractClientTracerAbstractServerTracer,再通過AbstractClientTracerAbstractServerTracer衍生出具體的元件 Tracer 實現。這種方式的好處在於,所有的外掛實現均有 SOFATracer 本身來管控,對於不同的元件可以輕鬆的實現差異化和定製化。

但是為了能夠擁抱社群,我們在後續的版本中將會提供基於 Opentracing API 的埋點擴充套件實現,從而實現與 opentracing-contrib 的無縫對接。基於 Opentracing API 的外掛埋點方案如下圖所示:


關於 SOFATracer 基於特有 API 埋點的實現以及如何實現對接 OT-api 埋點,期待大家一起編寫,領取方式見文末。

  • SOFATracer 的資料上報機制

SOFATracer 中並沒有將不同的 Reporter 設計成不同的策略,然後根據不同的策略來實現具體的上報操作,而是使用了一種類似組合的方式,並且在執行具體上報的流程中通過引數來調控是否執行具體的上報。

從流程圖中可以看到,此過程中涉及到了三個上報點,首先是上報到 zipkin,後面是落盤;在日誌記錄方面,SOFATracer 中為不同的元件均提供了獨立的日誌空間,除此之外,SOFATracer 在鏈路資料採集時提供了兩種不同的日誌記錄模式:摘要日誌和統計日誌,這對於後續構建一些如故障的快速發現、服務治理等管控端提供了強大的資料支撐。關於資料上報,期待大家一起編寫,領取方式見文末。

  • SOFATracer 的取樣機制

對於鏈路中的資料,並非所有的資料都是值得關注的。一方面是可以節約磁碟空間,另一方面可以將某些無關資料直接過濾掉。基於此,SOFATracer 提供了鏈路資料取樣能力。目前我們提供了兩種策略,一種是基於固定比率的取樣,另一種是基於使用者擴充套件實現的自定義取樣;在自定義取樣設計中,我們將 SofaTracerSpan 例項作為取樣計算的條件,使用者可以基於此實現豐富的取樣規則。關於取樣機制,期待大家一起編寫,領取方式見文末。

  • SOFATracer 鏈路透傳機制

關於透傳機制,我們不僅需要考慮執行緒內傳遞,還需要考慮跨執行緒以及非同步執行緒場景,對於分散式鏈路來說,最核心還有如何實現跨程序的資料透傳。關於 SOFATracer鏈路透傳 以及 OpenTracing 新規範中對執行緒傳遞的支援,期待大家一起編寫,領取方式見文末。

2.2 SOFATracer RoadMap

首先介紹下目前 SOFATracer 的現狀和一些正在做的事情。


SOFATracer 版本說明:

  • 3.x 版本支援 webflux 等,基於分支釋出。

  • 2.x 版本基於master 釋出,目前版本是 2.3.0 。

歡迎對相關功能和 feature 有興趣的同學,一起參與開發~

歡迎加入,參與 SOFATracer 原始碼解析

本文作為《剖析 | SOFATracer 元件系列》第一篇,主要還是希望大家對 SOFATracer 元件有一個認識和了解,之後,我們會逐步詳細介紹每部分的程式碼設計和實現,預計會按照如下的目錄進行:

  • 分散式鏈路跟蹤元件 SOFATracer 概述【已完成】

  • SOFATracer 資料上報機制和原始碼分析【待領取】

  • SOFATracer API 元件埋點機制和原始碼分析【待領取】

  • SOFATracer 鏈路透傳原理與 SLF4J MDC 的擴充套件能力分析【待領取】

  • SOFATracer 的取樣策略和原始碼分析【待領取】

如果有同學對以上某個主題特別感興趣的,可以留言討論,我們會適當根據大家的反饋調整文章的順序,謝謝大家關注 SOFA ,關注 SOFATracer,我們會一直與大家一起成長的。

領取方式:
掃碼關注並回複本公眾號想認領的文章名稱,我們將會主動聯絡你,確認資質後,即可加入,It's your show time!

除了原始碼解析,也歡迎提交 issue 和 PR:
SOFATracerhttps://github.com/alipay/sofa-tracer

長按關注,獲取分散式架構乾貨

歡迎大家共同打造 SOFAStack https://github.com/alipay