1. 程式人生 > 實用技巧 >鏈路追蹤系統:雲原生比賽分析

鏈路追蹤系統:雲原生比賽分析

摘要

本人近日在參加阿里雲原生的鏈路追蹤系統設計比賽,在比賽中感覺收穫頗多,包括一些工具框架的使用,例如okhttp以及springboot,同時也對於如何使用springboot有了更進一步的認識。本部落格就自己的收穫以及對於賽題進行簡單的梳理。比賽的詳細介紹詳見比賽首頁

鏈路追蹤

本次比賽是需要實現鏈路追蹤系統,關於鏈路追蹤的詳細介紹可參加官網的詳細介紹,本人簡單說一下我的理解,在本賽題中,鏈路實際上就是多個同處一個事務或流程中的http呼叫。因為對於網路系統程式設計(或者雲原生or分散式),單個事務的執行勢必涉及到多個不同系統,而體現在具體執行中,就是一個個不同的http呼叫組成了一個事務的執行。本質上,同屬一個呼叫鏈路的http span

組成了一個有向無環圖,本次比賽為了簡化,直接將同屬相同呼叫鏈路的http span用全域性唯一的traceId進行了標識,也就是不需要參賽選手進行呼叫鏈路的組建,只需要將資料流中所關心的呼叫鏈路給出即可。

資料格式

比賽中給出的http span是以http流給出的,每條http span佔據一行,資料格式如下:

traceId | startTime | spanId | parentSpanId | duration | serviceName | spanName | host | tags

具體各欄位意義解釋如下的:

  • traceId:全域性唯一的Id,用作整個鏈路的唯一標識與組裝
  • startTime:呼叫的開始時間
  • spanId: 呼叫鏈中某條資料(span)的id
  • parentSpanId: 呼叫鏈中某條資料(span)的父親id,頭節點的span的parantSpanId為0
  • duration:呼叫耗時
  • serviceName:呼叫的服務名
  • spanName:呼叫的埋點名
  • host:機器標識,比如ip,機器名
  • tags: 鏈路資訊中tag資訊,存在多個tag的key和value資訊。格式為key1=val1&key2=val2&key3=val3 比如 http.status_code=200&error=1

比賽給了兩條http流,而且為了簡化比賽,假定相同traceIdspan

前後不會超過2萬條。

賽題分析

在不考慮資料量的條件下,最樸素的解決方法當然就是在客戶端將http流全部快取下來,然後存入HashMap<String,List<String>>中,其中Key是符合上報條件的traceIdValue是與之對應的所有http span,再按照http spanstartTime屬性升序排序即可。由於資料量龐大,顯然這樣的方案不可行,但是我們注意到題目中給出的提示,假定相同traceIdspan前後不會超過2萬條,這樣我們實際上就可以將龐大的資料流分割成基本單位為2萬大小的batch來逐步的處理,為了說明方便,給出如下的示意圖:

如上圖所示,我們將資料流按照上述形式進行了分割以後,實際上就可以轉化為樸素的解法了,處理紅色batch時,需要將前後各一個batch進行彙總,共同計算結果,這是由於相同的traceId有可能橫跨兩個batch,但是出現在前面還是後面是不確定的,因此需要一起計算。需要注意的是,由於相同的呼叫鏈路有可能出現在不同的資料流中,我們需要將當前batch多個數據流中有問題的traceId全部彙總以後,在進行彙總計算。說明了整體的演算法思路之後,我們分析一下時間複雜度,假設總的資料量為N,由於每個batch都需要重複計算前後各一個batch,那麼總的複雜度為3N。

賽題互動邏輯設計

由於比賽要求實現客戶端和服務端,實際上就是將過濾和計算模組解耦,方便以後的系統設計。客戶端需要進行存在問題的traceId過濾彙報以及資料的快取服務,後端則負責將客戶端上報過來的有問題的traceId拉取客戶端當前快取的資料,然後在進行彙總以及最終的上報。由於涉及到複雜的http互動,繪製如下的示意圖明確互動過程:

賽題具體實現

整體設計流程基本上都體現在上圖中了,然後下面闡述實現中的幾個關鍵點:

  • 由於呼叫鏈路並行存在多條資料流中,我們根據過濾出的traceId後端進行計算時,一定要拿到多條資料流的彙總結果,這樣才能保證結果的正確性。還有就是當客戶端將當前batch和下一個batch過濾結果都彙總完畢時,才可以進行最終結果的彙總。其目的是為了保證traceId出現在不同的batch這一現象。

  • 前後端傳遞資料使用okhttp模組和fastjson,分別為我們提供了http通訊和物件的序列化服務,而http的請求處理我們使用springboot來完成。

  • 為了方便客戶端和後端的互動,我們設計了TraceIdBatch類,方便我們判斷前後端的狀態。其UML圖如下:

    其中batchPos是為了標記backend正在處理的batch序號,processCount用來標記已彙總資料裡的個數,當已彙總的資料流大於等於提供的資料流條數,標誌著客戶端當前batch過濾彙報的完成,backend就可以根據彙總的結果向client拉取結果,進行計算。