看完這篇,分布式服務鏈路追蹤的原理就被你摸透了

2021-10-09 13:27:54 字數 3776 閱讀 8348

分布式呼叫跟蹤系統實際上是隨著微服務才火起來的乙個概念,google早在很多年前(2023年初便已經使用自研容器)已經微服務化了,所以他的分布式跟蹤理論目前是最成熟的。

分布式跟蹤系統出現的原因簡單的說是因為在分布式系統中一次請求中會包含很多的rpc,迫切需要一些可以幫助理解系統行為和分析效能問題的工具,需要斷定具體哪個服務拖了後腿。

根據**來看,先看乙個例子:

a~e分別表示五個服務,使用者發起一次請求到a,然後a分別傳送rpc請求到b和c,b處理請求後返回,c還要發起兩個rpc請求到d和e,和d和e互動之後再返還給a,由a來響應最初的請求。

對於這樣乙個請求,簡單實用的分布式跟蹤的實現,就是為伺服器上每一次你傳送和接收動作來收集跟蹤識別符號(message identifiers)和時間戳(timestamped events)。也就是將這些記錄與特定的請求進行關聯到一起。

目前學術界與工業界有如下兩種方案,將一些記錄與某個特定的請求關聯到一起

黑盒方案(black box)

黑盒方案假定需要跟蹤的除了上述資訊之外沒有額外的資訊,這樣就可以使用統計回歸技術來推斷兩者之間的關係。

日誌還是一樣的記錄,只是通過機器學習的方法來關聯記錄與特定的請求。

以一條特定請求requestx為變數,通過黑盒(也就是機器學習的模型,比如回歸分析)從a的日誌中找出一條記錄與之對應,同理可以找出b、c、d、e等等的相關記錄。

黑盒方案的優勢就是不需要改變現有日誌記錄方法,但是缺點非常明顯,由於依賴統計推理,黑盒方案的精度往往不高(可以經過大量的資料學習和訓練,進行提高精度),實際使用中效果不好。

(比如project5,wap5和sherlock)

基於標註的方案(annotation-based)

基於標註的方案依賴於應用程式或中介軟體明確地標記乙個所有服務全域性id,藉此將一串請求關聯起來。

比如對requestx來說,賦予乙個標誌符1000,後續相關各個服務都會將識別符號1000與記錄一起打在日誌裡。

這種方法的優勢就是比較精確,目前google、twitter、**等都採用這種方式。

具體的做法就是根據請求中的traceid來獲取trace這個例項,各種程式語言有各自的方式。獲取到trace例項後就可以呼叫recorder(記錄器)來記錄span了,記錄值先直接以日誌的形式存在本地,然後跟蹤系統會啟動乙個collector(收集器) daemon(守護執行緒)來收集日誌,然後整理日誌寫入資料庫。 解析的日誌結果建議放在bigtable(cassandra、hdfs等)這類稀疏表的資料庫裡。因為每個trace攜帶的span可能不一樣,最終的記錄是每一行代表乙個trace,這一行的每一列代表乙個span。

但是基於標註的方案最主要的缺點也很明顯,需要**植入。(所以如何減少**侵入是最大的問題)

對於減少**的侵入性,建議將核心跟蹤**做的很輕巧,然後把它植入公共元件中,比如執行緒呼叫、控制流以及rpc庫。

分布式跟蹤系統要做的就是記錄每次傳送和接受動作的識別符號和時間戳,將一次請求涉及到的所有服務串聯起來,只有這樣才能搞清楚一次請求的完整呼叫鏈。

每個跟蹤樹trace都要定義乙個全域性唯一的traceid,推薦用64位的整數表示,在這個跟蹤中的所有span都將獲取到這個traceid。 每個span都有乙個parentspanid和它自己的spanid。上圖那個例子中a服務的parentspanid為空,spanid為1;然後b服務的parentspanid為1,spanid為2;c服務的parentspanid也為1,spanid為3,以此類推。

圖3:在圖2中所示的乙個單獨的span的細節圖

從上圖可以首先能看出來這個span是一次」hello.call」的rpc,spanid是5,parentspanid是3,traceid是100。 我們重點看一下client send, server recv, server send, client recv即cs, sr, ss, cr。

通過收集這四個時間戳,就可以在一次請求完成後計算出整個trace的執行耗時和網路耗時,以及trace中每個span過程的執行耗時和網路耗時。

在google的環境中,所有的應用程式使用相同的執行緒模型、控制流和rpc系統,既然不能讓工程師寫**記錄日誌,那麼就只能讓這些執行緒模型、控制流和rpc系統來自動幫助工程師記錄日誌了。

各個服務將span資料寫到本機日誌上;

跟蹤系統的成本由兩部分組成:

正在被監控的系統在生成追蹤和收集追蹤資料的消耗導致系統效能下降

需要使用一部分資源來儲存和分析跟蹤資料。雖然你可以說乙個有價值的元件植入跟蹤帶來一部分效能損耗是值得的,我們相信如果基本損耗能達到可以忽略的程度,那麼對跟蹤系統最初的推廣會有極大的幫助。

4.1 生成跟蹤的損耗

4.2 跟蹤收集的消耗

4.3 在生產環境下對負載的影響分布式跟蹤系統的實現要求是效能低損耗的,尤其在生產環境中分布式跟蹤系統不能影響到核心業務的效能。 google也不可能每次請求都跟蹤的,所以要進行取樣,每個應用和服務可以自己設定取樣率。取樣率應該是每個應用自己的配置裡配置的,這樣每個應用可以動態調整,特別是剛應用剛上線使可以適當調高取樣率。

一般在系統峰值流量很大的情況下,只需要取樣其中很小一部分請求,例如1/1000的取樣率,即分布式跟蹤系統只會在1000次請求中取樣其中的某一次。

5.1 可變取樣

5.2 應對積極取樣(coping with aggressive sampling)

5.3 在收集過程中額外的取樣

為了維持物質資源的需求和漸增的bigtable的吞吐之間的靈活性,我們在收集系統自身上增加了額外的取樣率的支援。我們充分利用所有span都來自乙個特定的跟蹤並分享同乙個跟蹤id這個事實,雖然這些span有可能橫跨了數千個主機。對於在收集系統中的每乙個span,我們用hash演算法把跟蹤id轉成乙個標量z,這裡0<=z<=1。如果z比我們收集系統中的係數低的話,我們就保留這個span資訊,並寫入到bigtable中。反之,我們就拋棄他。通過在取樣決策中的跟蹤id,我們要麼儲存、要麼拋棄整個跟蹤,而不是單獨處理跟蹤內的span。我們發現,有了這個額外的配置引數使管理我們的收集管道變得簡單多了,因為我們可以很容易地在配置檔案中調整我們的全域性寫入率這個引數。

合併的影響:我們的模型隱含的前提是不同的子系統在處理的都是來自同乙個被跟蹤的請求。在某些情況下,緩衝一部分請求,然後一次性操作乙個請求集會更加有效。(比如,磁碟上的一次合併寫入操作)。在這種情況下,乙個被跟蹤的請求可以看似是乙個大型工作單元。此外,當有多個追蹤請求被收集在一起,他們當中只有乙個會用來生成那個唯一的跟蹤id,用來給其他span使用,所以就無法跟蹤下去了。我們正在考慮的解決方案,希望在可以識別這種情況的前提下,用盡可能少的記錄來解決這個問題。

記錄核心級的資訊:一些核心可見的事件的詳細資訊有時對確定問題根源是很有用的。我們有一些工具,能夠跟蹤或以其他方式描述核心的執行,但是,想用通用的或是不那麼突兀的方式,是很難把這些資訊到**到使用者級別的跟蹤上下文中。我們正在研究一種妥協的解決方案,我們在使用者層面上把一些核心級的活動引數做快照,然後繫結他們到乙個活動的span上。

mapreduce是一種程式設計模型,用於大規模資料集(大於1tb)的並行運算。概念"map(對映)「和"reduce(歸約)」,是它們的主要思想,都是從函式式程式語言裡借來的,還有從向量程式語言裡借來的特性。它極大地方便了程式設計人員在不會分布式並行程式設計的情況下,將自己的程式執行在分布式系統上。 當前的軟體實現是指定乙個map(對映)函式,用來把一組鍵值對對映成一組新的鍵值對,指定併發的reduce(歸約)函式,用來保證所有對映的鍵值對中的每乙個共享相同的鍵組。

spring cloud 分布式鏈路追蹤

微服務之間進行呼叫 那麼如果我負責乙個模組 別人負責另乙個模組 我呼叫了他的方法 測試那邊卻報了錯 那是我的問題還是他的問題 這個時候大家應該就能想到日誌可以解決這個問題 如何使用日誌呢 先在配置檔案中加 logging path d logs poppy mall 日誌的存放位址最好再加個專案名的...

微服務 關於分布式鏈路追蹤

本篇的主要思路在於從分布式鏈路的思想開始,接下來介紹應用較廣泛的開源實現zipkin,最後對spring cloud sleuth這個具體的解決方案進行說明。為什麼需要鏈路追蹤 鏈路治理 微服務是乙個分布式服務的設計正規化,目的是將複雜的單體應用進行拆分,左耳朵耗子 前輩說關於服務依賴的一句話 微服...

docker zipkin(分布式鏈路追蹤)實踐

參考 dependenciesspring name test 在zipkin上顯示的服務名,不寫則是 default zipkin base url zipkin服務的位址 sender type web 網上有人在zipkin上查不到記錄,說加上這個即可,但本人親測不加也是可以查到記錄 sleu...