大規模分布式鏈路分析計算在字節跳動的實踐
一. 綜述
微服務架構的快速發展使得分布式鏈路追蹤系統成為觀測體系中越來越重要的組件。字節跳動的分布式鏈路追蹤系統經歷了數年的發展后,已覆蓋了字節的絕大部分在線業務,完成了對數萬微服務和數百萬微服務實例的在線鏈路追蹤。在經典的指標觀測分析和單請求鏈路追蹤的基礎上,如何從浩瀚如海的分布式鏈路數據中進一步挖掘出更高層次的信息,為業務的架構優化、服務治理、成本優化等場景提供更高效的數據支持,成為了下一步亟待回答的問題。
本次分享主要介紹我們構建海量鏈路數據分析計算系統的實踐經驗,以及一些具體的落地場景。
二. 可觀測性與鏈路追蹤
2.1 基本概念
為了方便讀者更好的理解“鏈路分析”,首先淺聊一下什么是“可觀測性”和“鏈路追蹤”。對“可觀測性”和“鏈路追蹤”的概念已經熟悉的讀者可以跳過本章節。
隨著微服務架構的快速發展,軟件系統正在從單體應用發展為由大量微服務節點構成的復雜應用。為了更好的管控復雜的軟件系統,“可觀測性”工具正在變得越來越重要。“可觀測性”工具構建的基礎是可觀測性數據,可觀測性數據一般包括如下部分:鏈路追蹤 Trace、日志 Logging、時序 Metrics、代碼級 Profiling、事件 Event 和 元數據相關的 CMDB 等。
為了幫助大家對可觀測性工具有一個更直觀的感受,這里用一個例子來闡述如何基于可觀測性工具來解決工作中的實際問題:某值班人員收到告警通知服務的失敗率正在上升,點擊關聯到錯誤指標對應的 Trace,在 Trace 中定位到錯誤的源頭,在源頭查看到關鍵的異常日志和代碼棧,并發現源頭報錯服務正在執行一個變更操作,于是基本定位到此變更很可能就是導致此故障的原因。有了高質量的可觀測性數據和工具,一個對此系統并不是非常熟悉的值班人員,就可能快速地完成此次故障的排查與止損。
分布式鏈路追蹤(Trace) 是可觀測性系統的其中一個組件。狹義上講 Trace 是對單次請求的明細追蹤,記錄請求在各環節上的調用關系,耗時,以及各類明細標簽與事件。同時 Trace 還有一個角色是各類可觀測性數據的鏈接紐帶,即同一個 Request Context 的數據載體,分布式請求上的各類信息(Metrics/Logs..)通過 Trace 實現了可靠關聯,進而可以構建各類可觀測性數據的上卷下鉆的跳轉功能。
2.2 字節鏈路追蹤系統
字節鏈路追蹤系統經歷了數年的發展,現已覆蓋公司絕大部分在線業務。整體發展歷程如下:
2019: Trace 1.0 完成了 Trace 組件能力的構建。
2020: Trace 2.0 實現了 Metrics/Trace/Log 的埋點一體化,對數據協議與技術架構進行了升級,并開始構建一站式觀測平臺 Argos。
2021: 與字節絕大部分主流框架組件實現了默認集成,全司各業務線微服務覆蓋度 > 80%。
2022: 構建與探索場景化、智能化的場景,例如本分享聊的“鏈路分析”。
字節鏈路追蹤系統當前的現狀數據(2022 年 10 月):
覆蓋面: 5 萬+ 微服務 /FAAS 數,300 萬+ 容器實例數。
使用量: 日 UV 6 千+ ,日 PV 4 萬+。
吞吐量: Span 數 2 千萬+/s (默認 0.1% 采樣)。
資源配比: 100+ CPU cores 支撐 100 萬 Span/s。
SDK 性能: 單線程 40w Span/s。
查詢性能: TraceID 點查 P50 < 100 ms, P99 < 500 ms。
數據產生到可檢索時延: AVG < 1 分鐘,P99 < 2 分鐘。
存儲資源: 10 PB (3 副本 TTL 15 天)。
字節鏈路追蹤系統從數據接入側、消費存儲側、到查詢平臺側的整體架構如下圖所示,更多細節可閱讀之前的??分享??,上一次分享較為詳細的介紹了如何從零到一構建一個分布式鏈路追蹤系統。本文主要聊鏈路追蹤系統中的鏈路聚合計算分析部分。
三. 鏈路分析技術實踐
3.1 需求場景
經常使用 Trace 的同學對 Trace 的印象可能是通過 TraceID 或者某些 Tag 檢索出一條或者一些 Trace,然后從 Trace 數據中仔細查看明細的調用軌跡和各種 Tag 來分析一些具體問題,比如一個請求為什么慢,或者一個請求為什么出錯了。
但是我們還面臨著一些更高層級的問題,例如,面對一個不斷變化的復雜微服務系統:
- 穩定性:緊急狀況時,哪些服務可以被降級,哪些服務必須被保障?高風險的易故障點在哪里??
- 流量/容量:如果某頁面的 PV 要增加10倍,哪些服務需要擴容?需要擴容多少??
- 成本性能:哪里存在明顯的性能反模式?哪里存在架構不合理帶來的性能浪費??
這些問題的答案靠人工去一條一條看 Trace 難以得到可靠結果。但是卻可以從大量的 Trace 數據中自動化地計算出來,為最終決策提供可靠的數據支持。我們把這種對大量 Trace 的聚合計算叫做 鏈路分析。
3.2 基本原理
鏈路分析的基本原理就是對大量的 Trace 進行聚合計算,一般遵循 MapReduce 計算模型,過程中可能會結合一些訂閱規則和其他數據,得到計算結果,然后應用到具體的場景化應用中去。
3.3 技術架構
適合對大量鏈路數據進行聚合計算的可選模式主要有三種,分別是從基于在線數據流的流式計算、從在線存儲中查詢有限條 Trace 然后進行的即興(抽樣)計算,以及基于離線數倉的離線計算。這三種計算模式的特性分析如下表所示。
計算方案 | 優點 | 缺點 |
流式計算 | - 近實時的分析結果 | - 無法對任意時段任意條件的數據進行計算 |
即興(抽樣)計算 | - 可對任意時段任意條件的數據發起分析并快速獲取結果 | 只能對抽樣的有限條 Trace 進行計算,數據完整性較低 |
離線計算 | - 數據完整性和準確度高 | - 小時級或天級的延遲的分析結果 |
分析完了三種聚合計算模式的特性后,再分析下鏈路分析場景所面臨的技術需求。
需求類型 | 描述 | 此類需求高的場景舉例 | 合適的計算方案 |
實時性需求 | 需要分析最新的數據嗎還是可以接受一定的延遲? | 故障歸因 | 即興計算/流式計算 |
數據完整性需求 | 抽樣一部分數據計算能否滿足需求?還是必須對所有 Trace 計算才能得到結果? | 流量估算 | 離線計算/流式計算 |
需求即興程度 | 任務是即興發起且必須快速拿到結果的嗎? | 故障歸因 | 即興計算 |
基于上述分析,我們認為并不存在一種計算模式就能解決所有問題,因此最終選擇的技術方案是流式,即興,離線一體化的技術方案:基于統一的基礎數據模型和邏輯算子,支持三種不同的計算引擎,以實現不同的場景化需求。
在落地此方案的過程中,我們總結了一些有益的實踐經驗:
- 邏輯算子與計算引擎分離
Trace 本身數據結構就較為復雜,其分析計算邏輯也往往有一定的復雜度,算子與引擎分離便于相同邏輯算子應用于不同計算引擎,可以較好地提升研發效率和代碼可維護性。例如性能瓶頸分析相關算法,既可以用于即興計算,也可以用于離線計算。
- 自動化異常數據檢測與封禁
Trace 數據常常會存在一些數據不規范現象,例如超高維度的接口名,導致聚合后的數據維度遠超預期,影響計算任務的穩定性。自動化的異常數據發現與封禁或降級機制能起到較好的保護作用。
- 保留原始樣本提高可解釋性
盡量保留聚合分析結果對應的代表原始(極值)Trace 樣本,可以提升分析結果的可解釋性和用戶信任度。
- 配備訂閱和降級機制
大數據量的計算成本較高,非基礎功能可采用按需訂閱模式以提升 ROI;建設對任務進行靈活降級的能力,資源緊張的情況下優先保障高頻基礎功能的高可用。
四. 鏈路分析落地場景
介紹完鏈路分析的底層技術架構后,我們來介紹一些具體的落地場景。
4.1 精準鏈路拓撲計算
鏈路分析使用最高頻最廣泛的場景當屬鏈路拓撲的計算。這里說的“鏈路拓撲”是指輸入任意一個服務節點即可獲取流經此節點的所有 Trace 的聚合路徑,從而清晰的得知此服務節點的上下游依賴拓撲關系。
由于字節的微服務數目極多且有各類中臺和基礎服務,調用關系較為復雜,因此我們做拓撲計算的目標是:
- 精準:只會檢索到與被檢索節點有直接流量的拓撲節點
- 靈活:可以按照任意節點(非僅入口),不同深度,不同粒度(服務/接口/集群/機房)進行拓撲檢索
- 實時:nice to have
舉例說明什么是精準性需求:如下圖所示,“抖音.X” 和 “火山.Y” 都調用了 “中臺.Z”,但是對于 “抖音.X” 的流量 “中臺.Z” 會使用 “Redis.抖音”,而對于 “火山.Y” 的流量 “中臺.Z” 會使用 “Redis.火山”,因此實際上 “抖音.X” 和 “Redis.火山” 是沒有直接依賴關系的。那么當我們檢索 “抖音.X” 時希望得到的拓撲是 [“抖音.X”, “中臺.Z”,“Redis.抖音”],而不要包含 “Redis.火山”。
舉例說明什么是靈活性需求:如下圖所示,不僅可以按照入口來檢索拓撲,也可以按照中間節點 “中臺.Z" 或者是存儲組件節點 "Redis.抖音" 來檢索拓撲;不僅可以按照服務+接口粒度來檢索拓撲,也可以按照服務粒度、服務+集群粒度、服務+機房粒度等其他粒度來檢索拓撲。
面對這樣的技術需求,我們研究了業界現有的一些拓撲計算方案:
- 方案一:也是開源主流方案,聚合單跳調用關系,檢索拓撲時將單跳的調用關系進行組裝。此方案簡單,低成本,但是精度較低,對于中小型的微服務系統是可以的,但是對于字節場景,例如上述例子中希望用 “抖音.X” 檢索拓撲時希望不要看到 “Redis.火山” 的需求則無法滿足。
- 方案二:由復旦 & Ebay 分享,將 Trace 按照 Path 進行分組聚合,每個服務節點對應一組 Path。檢索時首先檢索到服務對應的 PathID 列表,然后再根據 PathID 檢索出 Path 路徑聚合成拓撲。此方案精度最高,可以清晰的梳理出每個服務節點對應的所有調用路徑,但是在字節的實際場景中,我們發現 Path 膨脹非常嚴重,一個服務節點動輒成千上萬的 Path,成本高檢索慢,難以滿足字節場景的實際需求。
結合字節場景的實際需求,平衡精度、成本和檢索速度,最終我們設計了一種新的方案。
- 方案三:為每個節點計算出一張拓撲圖,存儲載體選擇圖數據庫。圖數據庫的一個點對應一個服務節點,圖數據庫的一條邊對應一個["所屬拓撲",“源節點”,“目標節點”]三元組。在上述例子中,有這樣一些邊:
所屬拓撲 | 源節點 | 目標節點 | 上圖中對應標注顏色 |
抖音.X | 抖音.X | 中臺.Z | 藍色 |
抖音.X | 中臺.Z | Redis.抖音 | 藍色 |
火山.Y | 火山.Y | 中臺.Z | 黃色 |
火山.Y | 中臺.Z | Redis.火山 | 黃色 |
中臺.Z | 抖音.X | 中臺.Z | 綠色 |
中臺.Z | 火山.Y | 中臺.Z | 綠色 |
中臺.Z | 中臺.Z | Redis.抖音 | 綠色 |
中臺.Z | 中臺.Z | Redis.火山 | 綠色 |
- 當需要檢索“抖音.X”對應拓撲時,首先定位到圖數據庫中“抖音.X”對應的點,然后以此為起點發起圖的遍歷搜索,找到所有滿足“所屬拓撲=抖音.X”的邊(即圖中所有藍色的邊),得到了“抖音.X”所對應的拓撲為["抖音.X", "中臺.Z", "Redis.抖音"]。
- 這個方案精度能夠滿足需求,成本相對折中,同時很好的利用了圖數據庫的特性,可以實現非常高效的拓撲查詢。同時,由于鏈路拓撲的數據完整性需求較高,對實時性有一定的需求,因此我們使用了流式計算引擎來支持鏈路拓撲的計算,大致流程如下圖所示。
精準鏈路拓撲的應用場景比較廣,這里舉一些具體的例子:
- 全鏈路實時觀測:實時觀測拓撲各節點的流量/延遲/錯誤率/資源使用率/告警/變更等,快速從全鏈路視角獲取整體狀態信息。
?
- 混沌演練:為故障演練提供鏈路依賴底圖,生成演練計劃,對全鏈路各個環節進行故障注入,收集與驗證系統的反應得到演練報告。
- 壓測準備: 提前梳理壓測流量將會流經的節點,讓相關節點做好壓測準備。
- 服務架構治理: 為服務架構治理場景提供上下游依賴梳理依據。
- 故障歸因: 為故障歸因提供上下游依賴遍歷的底圖數據。
4.2 全鏈路流量估算
全鏈路流量估算主要回答的問題是:
- 流量流向哪些下游?如果當前節點的流量增加了 N,那么這些下游節點的流量會增加多少?
- 流量來自哪些上游?如果當前節點的流量增加了 N,那么這些流量是由誰帶來的?占比如何?
全鏈路流量估算是在精準拓撲計算的基礎之上實現的,因此也采用了流式計算的方式,基于各路徑的 Trace 數目以及 Trace 所對應的采樣率數據進行估算。其計算結果格式如下圖所示,每張拓撲中的每條邊對應一個估算流量和流量比例。基于這樣的數據,對于任意一個微服務接口,我們都可以給出上面兩個問題的答案。
全鏈路流量估算的主要應用場景如下:
- 業務活動擴容估算: 業務在進行大促活動前,往往先由產品估算出 DAU 的增量,然后將 DAU 增量轉換為一組入口服務接口的 QPS 增量,進而再根據全鏈路流量比例估算出全鏈路各環節的 QPS 增量和擴容需求。可靠的全鏈路流量比例數據可以為此場景提供很好的輔助支持。
- 成本容量治理: 準確的全鏈路流量估算數據,有助于業務構建更加精細的成本容量規劃,促進降本增效。
- 流量變化根因分析: 當流量發生預期外的波動變化時,全鏈路流量估算數據可以幫助快速分析出波動的根因與來源。
4.3 強弱依賴分析
強弱依賴信息是服務穩定性治理場景的重要數據支撐,它也是可以通過線上的 Trace 數據自動化地計算出來的。
強依賴:異常發生時,影響核心業務流程,影響系統可用性的依賴稱作強依賴。
弱依賴:異常發生時,不影響核心業務流程,不影響系統可用性的依賴稱作弱依賴。
如下圖所示,當 A 調用 B 失敗時,如果 A 仍然能成功響應其 Client,則 B 是 A 的弱依賴;當 A 調用 B 失敗時,如果 A 無法成功響應其 Client,則 B 是 A 的強依賴。
強弱依賴計算的技術目標包括:
- 準確性: 盡可能高,尤其是減少“強誤判弱”,提供判定依據樣本
- 覆蓋度: 盡可能高,盡可能多的為線上存在的調用關系給出強弱依賴數據
- 粒度: <調用方服務接口,被調方服務接口>、<場景,調用方服務接口,被調方服務接口>
- 實時性: nice to have
為了盡可能滿足數據的完整性和及時性需求,我們選擇了流式計算模式,從數據流中選擇帶 Error 的 Trace 進行強弱依賴關系計算。需要注意短期的實時數據樣本往往不夠,需要結合歷史累積數據共同判定再下結論。
強弱依賴分析的主要挑戰:
- 準確率: 不同業務線判定業務穩態的規則較難統一,需要推動業務完善數據標記或規則錄入。
- 覆蓋率: 部分路徑線上常態化錯誤率極低,較難收集到足夠的錯誤樣本,需要配合混沌演練進行補充。
強弱依賴分析的主要應用場景包括:
- 限流降級預案配置指導: 強弱依賴數據可以回答緊急狀況時哪些服務可以被降級,哪些服務必須被保障的問題。弱依賴可以進行限流降級,而強依賴則應當盡可能的保障高可用。
- 超時漏斗配置指導: 強弱依賴數據可以指導業務更合理的配置超時漏斗。如下圖所示,弱依賴配置超時時間過長是不合理的,可能會導致不必要的慢請求;如果強依賴配置的超時時間過短也是不合理的,可能會導致不必要的失敗請求影響用戶體驗。
- 輔助自動化故障歸因: 準確的強弱依賴信息,對自動化故障歸因可以起到較好的輔助作用。
- 服務架構治理: 準確的強弱依賴信息,可以協助業務優化架構,治理不符合預期的強依賴,提前準備災備方案,提升整體的穩定性和高可用。
4.4 全鏈路性能反模式分析
在實踐的過程中,我們觀察到有一些非常典型的性能反模式問題是可以從 Trace 數據中自動化的計算發掘,常見的性能反模式包括:
- 調用放大: 單請求中,大量調用同一服務接口。如果在線鏈路中出現了調用放大比例極高的 case,往往不僅暴露出性能問題,還很可能會造成穩定性風險,需要及早治理掉。
- 重復調用: 單請求中,多處使用相同 Request 調用同一個服務接口。這種情況常見于基礎信息的重復獲取,例如多處重復去請求 user info 或者 device info,是可以進行優化的。
- 讀寫放大: 單請求中,從底層服務獲取的數據量遠大于最終返回給client的數據量。這種情況常見于濫用重接口獲取輕信息,例如調用重接口請求了 user 的所有信息,卻只取了 user name 一個字段。
- 串行循環: 串行循環特征較為明顯,其形態一般如下圖所示,一般可優化為并行或批量調用。
性能反模式問題的發掘還有如下兩個需求:
- 優先發現極值問題并提供 worst case 樣本
- 優先發現高流量+核心鏈路上的反模式問題
因此性能反模式的分析任務需要自動化發現最嚴重的那些反模式問題,給出極值樣本,并且關聯出這些問題所在路徑的流量和入口優先級,從而幫助業務對服務進行延遲優化和成本優化,及早解決掉相關的潛在穩定性風險。
4.5 全鏈路性能瓶頸分析
單請求的分布式 Trace 視圖清晰直接,但是局限性在于觀察者無法確定單請求所呈現出的 Trace Pattern 是普遍現象還是特殊現象。因此從大量的 Trace 數據中分析鏈路性能瓶頸,從而識別出整體性能 Pattern 和 worst case 樣本也是鏈路分析的一個需求場景。
從批量 Trace 中聚合計算出鏈路性能 Pattern,既有即興模式的需求,也有離線模式的需求。即興模式下可以滿足對任意時段、靈活條件(各類tag,耗時區間)篩選批量 Trace 并快速獲取分析結果的需求。離線訂閱模式下可以滿足更完整的對全量 Trace 數據的整體性能模式分析需求,并觀察長期變化趨勢。因此我們會將鏈路性能分析聚合算子復用在即興和離線兩種計算模式下。
分析結果示例:
4.6 錯誤傳播鏈分析
單條 Error Trace 可以觀察出一條錯誤傳播路徑,但是觀察者無法確認一條錯誤傳播路徑是否一定代表了普遍問題,也無法回答錯誤傳播的影響面如何。因此聚合大量的 Error Trace 去分析整體的錯誤來源、傳播路徑和影響面也是鏈路分析的一個需求場景。
和鏈路性能分析類似,從批量 Trace 中聚合計算出錯誤傳播路徑,既有即興模式的需求,也有離線模式的需求。我們也會將錯誤傳播鏈分析算子應用在即興和離線兩種計算模式下。即興模式可以滿足對任意時段、靈活條件(各類tag)篩選批量 Error Trace 并快速獲取聚合分析結果的需求。離線訂閱模式則可以滿足更完整的對全量 Error Trace 數據的聚合分析需求,并觀察長期變化趨勢,輔助業務進行長期的穩定性優化工作。
分析結果示例:
五. 小結與展望
本文主要介紹了在完成了從零到一的鏈路追蹤基礎能力的構建之后,如何對海量的鏈路數據進行聚合分析來回答更高層面的場景化問題。分享了我們的具體技術選型過程和落地的技術架構,以及一些較為成功的落地案例。
最后分享后續的一些展望:
- 數據質量持續建設: 數據質量對于鏈路數據分析的結果優劣起到極其重要的作用。不斷完善業務語義規范,推進各層面接入覆蓋會是我們后續持續投入的工作。
- 場景化: 開放能力持續建設,沉淀業務知識和專家經驗,打磨業務最佳實踐。
- 智能化: 基于數據+知識+算法,持續提升應對故障歸因、穩定性優化、性能成本優化等場景的能效。
- 擁抱云原生 : 完善 OpenTelemetry 接入,打磨基礎組件,更好的適應各類云上場景。
六. 加入我們
我們是字節跳動-基礎架構-應用觀測(服務端)團隊,專注于 PB 級別海量數據的可觀測性基礎設施(Metrics、Tracing、Logging、Event、Profiling)和上層可觀測性應用(E.g. 報警生命周期管理、異常檢測、根因分析)的建設,為字節跳動整體業務的穩定性、性能優化、服務治理等方向保駕護航。