開發與維運

賽題解析 | 初賽賽道一:實現一個分佈式統計和過濾的鏈路追蹤

首屆雲原生編程挑戰賽正在報名中,初賽共有三個賽道,題目如下:

賽道一:實現一個分佈式統計和過濾的鏈路追蹤
賽道二:實現規模化容器靜態佈局和動態遷移
賽道三:服務網格控制面分治體系構建

立即報名(報名時間即日起至07/01):https://tianchi.aliyun.com/specials/promotion/cloudnative#problem-definition

本文主要針對賽道一題目做出剖析,幫助選手更高效的解題。

背景

為了應對各種複雜的業務,系統架構也從單機大型軟件演化成微服務架構。微服務構建在不同的軟件集上,這些軟件模塊可能是由不同團隊開發的,可能使用不同的編程語言來實現,還可能發佈在多臺服務器上。因此,如果一個服務出現問題,可能導致幾十個服務都出現異常。

分佈式追蹤系統用來記錄請求範圍內的信息,用戶在頁面的一次點擊發送請求,這個請求的所有處理過程,比如經過多少個服務,在哪些機器上執行,每個服務的耗時和異常情況。可參考 鏈路追蹤的概念

採集鏈路數據過程中,採集的數據越多,消耗的成本就越多。為了降低成本,目前普遍的做法是對數據進行採樣。請求是否採樣都是從的頭節點決定並通過跟蹤上下文透傳到所有節點(head-based sampling)。目前業界普遍的採樣都是按照這個方式,比如固定比例採樣(Probabilistic Sampling),蓄水池採樣(Rate Limiting Sampling),混合採樣(Adaptive Sample)。這樣的採樣可以保證整個調用鏈的完整性。但是這樣採樣也帶來兩個問題,一 有些異常和慢請求因為採樣的原因沒有被採集到,而這些鏈路數據對業務很重要。二 99%的請求都是正常的,而這些數據對問題排查並不重要,也就是說大量的成本花在並不重要的數據上。

本題目是另外一種採樣方式(tail-based Sampling),只要請求的鏈路追蹤數據中任何節點出現重要數據特徵(錯慢請求),這個請求的所有鏈路數據都採集(由分佈式微服務的各個節點上產生),這種採樣方式在一些場景特別有效,比如錯慢全採,大客戶全採。目前開源的鏈路追蹤產品都沒有實現完整的tail-based Sampling,主要的挑戰是:任何節點出現符合採樣條件的鏈路數據,那就需要把這個請求的所有鏈路數據採集。即使這些鏈路數據在這個鏈路節點之前或者之後產生,即使這些鏈路數據在分佈式系統的成百上千臺機器上。

一 賽題

首屆雲原生編程挑戰賽1:實現一個分佈式統計和過濾的鏈路追蹤鏈接

用戶需要實現兩個程序,一個是數量流(橙色標記)的處理程序,該程序拉取數據後進行處理,一個是後端程序(藍色標記),和客戶端數據流處理程序(橙色標記)通信,將最終數據結果在後端引擎上聚合。

image.png

架構示例圖

賽題可以理解為很多組數據(trace)分佈在兩臺機器上,任何一條數據(span)符合採集條件( http.status_code 不為 200,或者 error 等於1),需要將這組數據(trace)從兩臺機器上採集下來,在後端程序上聚合彙總。

數據聚合過程如下圖
image.png

數據處理示例圖

二 賽題分析

賽題數據處理很簡單,就是一個map-reduce處理。 在實際場景中,無法將所有數據都上報進行實時計算(全量上報的數據量非常大),需要在客戶端完成篩選,在服務端進行聚合。

最大程度利用三臺分佈式機器的資源
最簡單的解決方案是,在一臺機器上讀取多個數據流數據存放到一個文件中。跳過數據同步的過程,直接對這個文件做數據聚合。 這樣處理會帶來兩個問題,1,只利用單臺機器的資源,無法充分利用另外兩臺機器的資源。 2. 存放到文件中,涉及到讀寫硬盤,相比內存處理會慢一些。
為了最大限度的利用三臺機器的資源,需要三者之間良好的協同。我們可以分析鏈路追蹤的場景,需要採集的數據佔總數據的比例比較低。 那可以在數據處理層做第一次過濾,過濾後三臺機器只需要基於需要採集的數據進行通信。
數據處理端的數據緩存,同步
每個節點都只有部分數據,需要將數據進行緩存,再將符合條件的數據在服務端聚合。
數據處理示例圖中,數據流1緩存了traceId:1,traceId:2,traceId:3. 檢測發現traceId:2符合採集條件。 數據流2也緩存了traceId:1,traceId:2,traceId:3,檢測發現traceId:3符合採集條件. 那最終只需要聚合traceId:2,traceId:3的數據。 traceId:1的數據不做任何處理。
在評測環境,數據流1和數據流2都大於4G的數據, 而處理數據流的機器內存都只有4G,無法在內存中做全量緩存。 那選手需要思考做流式緩存處理。在鏈路追蹤的真實場景中,會有時間窗口方式來處理,一般請求不會超過3分鐘,各個數據流節點同步時間窗口內的數據。同步數據,那就需要保持各個接口數據的同步。而各個節點的數據處理有快有慢,同步的話,可能會block數據處理,對性能有影響。通用的解決方式是多個線程來處理,數據處理和數據同步分別兩個線程。,數據處理和線程拉取數據並處理,數據同步是對歷史數據做同步,例如數據處理示例圖中,在數據處理線程處理traceId:3時, 數據同步線程可以上報traceId:2的數據。
服務端的數據緩存,同步和聚合
服務端收集到這個節點的數據後,需要檢查各個節點數據是否齊全,如果齊全的話,那需要收集各個節點的數據,如果不齊全的話,那就需要繼續等待,甚至阻塞數據上報,直到數據齊全或者超時。比如說,採集某一段數據或者某一個時間窗口的數據時, 節點1的數據上報了,節點2數據未上報,那需要繼續等待節點2的數據。由於併發執行的緣故,節點1的數據在持續上報,而節點2數據遲遲未上報,那就需要考慮超時,緩存清除,數據同步。
數據聚合時,題目對真實場景做了簡化。在真實場景中,需要同一個請求的所有數據(同一個traceId下的所有span)構建調用關係的一顆樹。
image.png

實際場景中的鏈路詳情展示(阿里雲鏈路追蹤產品)

簡化後,選手只需要根據數據的startTime做升序排序,生成checkSum(Md5)值,保證數據完整性的同時降低業務邏輯的強耦合。具體的Md5 計算可參考demo
其他的優化點
rpc 建立長連接
demo程序採用的http方式,本地在服務端程序除了開放了8002端口,還開放了8003,8004端口。選手可以利用這些端口開啟長連接通信,比如dubbo,grpc,加快處理過程,提高性能。
多線程拉取
為了充分利用數據處理程序的機器資源,可以通過Rang方式多線程去拉取數據。
例如curl -H 'Range: bytes=200-2000' "http://localhost:8081/trace1.data"

三 賽題評測

評測環境由 1 臺 2 核 4G 的評測機,2 臺 2 核 4G 的數據流處理機器和 1 臺 1 核 2G 的後端服務組成。數據流處理機器和後端服務機器都會在docker內運行(docker 容器會限制 CPU 和內存大小)。

用戶提交編譯好的docker image(不限定開發語言,分佈式程序建議用go和java)
通過kubernetes的部署docker 容器
評測機器調用數據流處理機器和後端服務機器,檢查應用是否啟動
評測機器發送評測數據的位置發給數據流處理機器和後端服務機器,並開始計時。
評測機器收到上報的接口,並進行分值計算。
評測程序的跑分方式:將選手生成的結果同已知結果進行對比,計算 F1 Score;同時記錄整個跑分從開始到輸出結果的時間 time,最後的比賽得分: F1/time。即 F1 值越大越好,耗時越小越好。

四 總結

本文結合首屆雲原生挑戰賽的賽題背景、題目場景、題目分析和評測環境與過程的角度,介紹了分佈式鏈路跟蹤系統的tail-based sampling的基本設計思路,希望對即將參加比賽的同學們能有所幫助,也歡迎更多的技術同學報名參加我們的挑戰賽,分享你在編程方面的思考和實踐。

五 更多

鏈路追蹤相關的介紹

鏈路追蹤的demo(需要開通鏈路追蹤服務,開通後不上報數據,不收取任何費用

apache 頂級項目skywalging,優秀的開源的鏈路追蹤項目

雲原生的可觀察性的開源項目opentelemetry

cncf的標準開源項目 jaeger

Leave a Reply

Your email address will not be published. Required fields are marked *