首屆雲原生程式設計挑戰賽正在報名中,初賽共有三個賽道,題目如下:
賽道一:實作一個分布式統計和過濾的鍊路追蹤
賽道二:實作規模化容器靜态布局和動态遷移
賽道三:服務網格控制面分治體系建構
立即報名(報名時間即日起至07/01):
https://tianchi.aliyun.com/specials/promotion/cloudnative#problem-definition 本文主要針對賽道一題目做出剖析,幫助選手更高效的解題。背景
為了應對各種複雜的業務,系統架構也從單機大型軟體演化成微服務架構。微服務建構在不同的軟體集上,這些軟體子產品可能是由不同團隊開發的,可能使用不同的程式設計語言來實作,還可能釋出在多台伺服器上。是以,如果一個服務出現問題,可能導緻幾十個服務都出現異常。
分布式追蹤系統用來記錄請求範圍内的資訊,使用者在頁面的一次點選發送請求,這個請求的所有處理過程,比如經過多少個服務,在哪些機器上執行,每個服務的耗時和異常情況。可參考
鍊路追蹤的概念采集鍊路資料過程中,采集的資料越多,消耗的成本就越多。為了降低成本,目前普遍的做法是對資料進行采樣。請求是否采樣都是從頭節點決定并通過跟蹤上下文透傳到所有節點(head-based sampling)。
目前業界普遍的采樣都是按照這個方式,比如固定比例采樣(Probabilistic Sampling),蓄水池采樣(Rate Limiting Sampling),混合采樣(Adaptive Sample)。這樣的采樣可以保證整個調用鍊的完整性。但是這樣采樣也帶來兩個問題:
1、有些異常和慢請求因為采樣的原因沒有被采集到,而這些鍊路資料對業務很重要。
2、99% 的請求都是正常的,而這些資料對問題排查并不重要,也就是說大量的成本花在并不重要的資料上。
本題目是另外一種采樣方式(tail-based Sampling),隻要請求的鍊路追蹤資料中任何節點出現重要資料特征(錯慢請求),這個請求的所有鍊路資料都采集(由分布式微服務的各個節點上産生),這種采樣方式在一些場景特别有效,比如錯慢全采,大客戶全采。目前開源的鍊路追蹤産品都沒有實作完整的 tail-based Sampling ,主要的挑戰是:任何節點出現符合采樣條件的鍊路資料,那就需要把這個請求的所有鍊路資料采集。即使這些鍊路資料在這個鍊路節點之前或者之後産生,即使這些鍊路資料在分布式系統的成百上千台機器上。
一 賽題
首屆雲原生程式設計挑戰賽1:實作一個分布式統計和過濾的鍊路追蹤連結使用者需要實作兩個程式,一個是數量流(橙色标記)的處理程式,該程式拉取資料後進行處理,一個是後端程式(藍色标記),和用戶端資料流處理程式(橙色标記)通信,将最終資料結果在後端引擎上聚合。

架構示例圖
賽題可以了解為很多組資料(trace)分布在兩台機器上,任何一條資料(span)符合采集條件( http.status_code 不為 200,或者 error 等于1),需要将這組資料(trace)從兩台機器上采集下來,在後端程式上聚合彙總。
資料聚合過程如下圖
資料處理示例圖
二 賽題分析
賽題資料處理很簡單,就是一個 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 )建構調用關系的一顆樹。
實際場景中的鍊路詳情展示(阿裡雲鍊路追蹤産品)
簡化後,選手隻需要根據資料的 startTime 做升序排序,生成 checkSum(Md5)值,保證資料完整性的同時降低業務邏輯的強耦合。具體的 Md5 計算可參考 Demo 。
其他的優化點
1、rpc 建立長連接配接。
2、Demo 程式采用的 http 方式,本地在服務端程式除了開放了8002端口,還開放了8003,8004端口。選手可以利用這些端口開啟長連接配接通信,比如dubbo,grpc,加快處理過程,提高性能。
3、多線程拉取。
4、為了充分利用資料處理程式的機器資源,可以
通過Rang方式多線程去拉取資料。
例如curl -H 'Range: bytes=200-2000' "http://localhost:8081/trace1.data"
三 賽題評測
評測環境由 1 台 2 核 4G 的評測機,2 台 2 核 4G 的資料流處理機器和 1 台 1 核 2G 的後端服務組成。資料流處理機器和後端服務機器都會在docker内運作(docker 容器會限制 CPU 和記憶體大小)。
1、使用者送出編譯好的docker image(不限定開發語言,分布式程式建議用go和java)。
2、通過kubernetes的部署docker 容器。
3、評測機器調用資料流處理機器和後端服務機器,檢查應用是否啟動。
4、評測機器發送評測資料的位置發給資料流處理機器和後端服務機器,并開始計時。
5、評測機器收到上報的接口,并進行分值計算。
6、評測程式的跑分方式:将選手生成的結果同已知結果進行對比,計算 F1 Score;同時記錄整個跑分從開始到輸出結果的時間 time,最後的比賽得分: F1/time。即 F1 值越大越好,耗時越小越好。
四 總結
本文結合首屆雲原生挑戰賽的賽題背景、題目場景、題目分析和評測環境與過程的角度,介紹了分布式鍊路跟蹤系統的tail-based sampling的基本設計思路,希望對即将參加比賽的同學們能有所幫助,也歡迎更多的技術同學報名參加我們的挑戰賽,分享你在程式設計方面的思考和實踐。