微服務架構學習與思考(09):分佈式鏈路追蹤系統-dapper論文學習
一、技術產生的背景
1.1 背景
先來了解一下分佈式鏈路追蹤技術產生的背景。
在現在這個發達的互聯網世界,互聯網的規模越來越大,比如 google 的搜索,Netflix 的視頻流直播,淘寶的購物等。
像這種大規模的應用,我們每點擊一下鼠標,搜索一個關鍵字,背後可能會有幾百台服務器上的N個服務來為我們提供服務。
我們用谷歌搜索:分佈式
3 個字,搜索一些文章來學習分佈式的知識。假如,查詢時結果返回耗時 5 秒之多。
作為用戶的你,等待這麼長時間才返回結果,心裏肯定不滿意。
那作為一項服務來說,公司為了更好的服務用戶,讓用戶滿意,就必須要縮短用戶等待返回查詢結果的時間,要儘可能快的返回結果。
這樣用戶使用時才會感覺滿意。
當然,這個優化任務就落在了產品技術研發人身上了。- -!
作為開發服務的產品技術人員,要怎麼樣做,才能讓用戶搜索時返回結果很快呢?
這時,產品研發人就思考在思考:
用戶的一次搜索背後可能有幾百個後端服務來提供服務。比如現在流行的微服務架構。
如果後端有一條服務比較慢,那麼就可能會拖慢這整個搜索結果。
在這麼多的服務中,要怎麼樣做,才能找出慢的服務呢?怎麼找出是哪一條後端服務比較慢呢?
產品技術研發研究人員為了解決這個問題,慢慢想出了分佈式鏈路追蹤的技術,在到具體的技術實踐,這是一個漫長的過程。
他們把研究成果匯聚在了 dapper 論文里。
當然它也借鑒了前人的研究成果 ,尤其是 Magpie 和 X-Trace,還有 Pinpoint。
說明:這裡的 Pinpoint 並不是 pinpoint-apm,而是一篇論文
在 [dapper](//research.google/pubs/pub36356/) 論文開頭有這樣一段描述:
Modern Internet services are often implemented as complex, large-scale distributed systems. These applications are constructed from collections of software modules that may be developed by different teams, perhaps in different programming languages, and could span many thousands of machines across multiple physical facili- ties. Tools that aid in understanding system behavior and reasoning about performance issues are invaluable in such an environment.
from: //research.google/pubs/pub36356/
大意是說現代互連網服務,通常都是用複雜的、大規模分佈式集群來實現。這些應用構建在不同的模塊上,這些軟件模塊,可能由不同的團隊開發,可能使用不同的開發語言,可能部署在幾千台服務器上,橫跨多個數據中心。因此,需要一些可以理解這個複雜系統的行為,用於分析性能找出性能問題的工具。
1.2 一個請求的鏈路圖示
Dapper 論文里的一張圖,表示一個請求可能經過的路徑節點:
(圖 1:這個路徑由user用戶的RequestX發起請求,穿過一個簡單的服務系統。用字母標識的節點代表分佈式系統中的不同處理過程,
來自://research.google/pubs/pub36356/)
這張圖是由 5 台服務器提供相關的一個服務,它包含:A-前端,B,C-2個服務中間層,以及 2 個後端 D 和 E。
當一個用戶發起一個請求,首先是到達前端 A, 然後發送 2 個 RPC 請求到服務器 B 和 C。B 馬上會響應請求,但是 C 需要和
後端的 D 和 E 交互之後在返回給 A,最後由 A 來響應最初的請求。
上圖的調用鏈經過了不同的系統,這個系統可能是不同團隊維護,並且使用不同的語言開發。如果服務中出現了問題,比如請求異常,請求超時,那麼怎麼定位是哪個系統的哪一步出現了問題呢?
還有,對系統的監控是 7×24 小時不間斷的。持續的對系統進行監控。
二、Dapper 的分佈式追蹤
2.1 怎麼定義圖1鏈路信息
對於上面圖 1 的一個請求響應路徑,怎麼定義、怎麼能實現分佈式追蹤呢?
簡單實現:為服務器每一次的發送和接收請求來收集追蹤標識(message identifiers)和時間戳(timestamped events)。
從入口開始發起 Request 的請求者(圖 1 中的 RequestX),與這個請求者相關的信息都要關聯上,並記錄下來分析鏈路關係,有什麼好的方案呢?
2 種方案:黑盒(black-box)和基於標註(annotation-based)的監控方案。
黑盒方案:
假定需要追蹤的除了上述信息之外沒有額外的信息,這樣使用統計回歸技術來推斷兩者之間的關係。
基於標註方案:
依賴於應用程序或中間件明確地標記一個全局 ID,從而連接每一條記錄與發起者的請求。
2種方案的比較:
黑盒方案比標註方案跟輕便,但是它需要更多的數據,以獲得足夠的精度,因為他們依賴於統計推論。
標註方案最主要缺點,需要代碼植入。
Google的選擇:
在 google 的生產環境中,所有的應用程序都使用相同的線程模型,控制流和RPC系統,他們可以把代碼植入限制在一個很小的通用組件庫中,從而實現了監測系統的應用對開發人員是有效且透明。
dapper 的追蹤架構是內嵌在 RPC 調用鏈的屬性結構里。當然這個調用鏈路監控,還可以追蹤其他行為,比如外界的 HTTP 請求,Gmail的 SMTP 會話和外部對 SQL 服務器查詢等。
2.2 Dapper 數據結構模型
1、樹形結構,追蹤樹
2、Span 以及 Annotation
(圖 2:來自dapper論文://research.google/pubs/pub36356/)
圖 2,是一個樹形結構,每一個樹節點是整個架構的基本單元,這個節點單元叫做 span,每個節點 span 都有一個唯一的 id:span id,還有一個 name:span name。
節點之間的關係可以用父子來表示,parent id 和 span id,parent id 就是它上一個 span 的 id;如果一個 span 沒有父 id,那麼它就是根節點,root span。
所有的 span 都有一個追蹤請求 id,叫 trace id,作用是標識出一次完整請求。這個 trace id 是全局唯一。
最後,每個 span 還有一個 Annotations,記錄每個 span 中的其他相關信息,比如 span 的開始時間戳,結束時間戳,發送信息等等信息,客戶端和服務端信息都可以記錄。
(圖3:表示一個單獨的 span 結構信息圖,來自 dapper 論文)
// 偽碼錶示結構
struct span {
id // 當前 span 的 id
parent_id // 父 id,上一層 span id
name // 當前 span 的 name
trace_id // 標識一次完整請求的 trace_id
Annotations []annotation // 表示 span 中的其它相關信息
}
struct annotation {
star_time // 此次 span 開始時間戳
end_time // 此次 span 結束時間戳
client_send_info // 客戶端發送信息
client_recv_info // 客戶端接收信息
server_send_info // 服務端發送信息
.. ...
}
2.3 怎麼把追蹤代碼值入相關程序中
dapper 裏面叫植入點。
怎麼把相關追蹤代碼放入到程序中?並且能比較少的改動代碼,又能達到下面三個設計目標。
dapper 里提了 3 個設計目標:
- 低損耗
追蹤系統對在線服務的影響最小化。因為在一些性能比較敏感的服務里,一點點的性能消耗也可能影響用戶體驗。
- 對應用程序透明
對於應用程序來說,它根本覺察不到追蹤系統的存在。
一個追蹤系統,如果需要應用開發者主動配合植入追蹤代碼,那麼追蹤系統的存在不僅會導致眾多額外代碼的修改,最重要的是可能會使
運行良好的系統產生bug。
- 擴展性
google 在未來幾年隨着業務規模增長而擴展集群規模,追蹤系統也能夠應對這種情況。
對於上面 3 點中最重要的一點就是追蹤系統對**應用程序透明**。
那怎麼做才能對應用程序透明?
Dapper 可以近乎零浸入的成本對應用程序鏈路進行追蹤,得益於 google 的服務設施依賴幾個少數的通用組件庫,只要改造這
幾個組件庫就可以了。比如 google 中幾乎所有進程間通信都是建立在 C++ 和 Java 開發的 RPC 框架上,那麼我們只用改造這個 RPC 框架,追蹤系統就能在依賴這個 RPC 框架的應用程序里生效。
當然 dapper 也允許應用開發人員給鏈路追蹤系統添加額外的信息,以監控更高級別的系統行為,或幫助調試問題。它允許用戶通過一個簡單的 API 定義帶時間戳的 Annotation。
2.4 採樣率和追蹤信息的收集
低損耗是 dapper 的一個設計目標,所以 dapper 對系統鏈路信息收集工作對基本組件性能損耗要儘可能的小。還有就是遇到大量請求時只記錄其中一小部分。
(圖4:dapper 收集管道總覽,來自 dapper 論文)
dapper 追蹤系統記錄和收集信息過程分為三個階段(如上圖4):
- span 的數據寫入(1)本地日誌文件,
- 然後 dapper 的 daemon 進程和收集組件把追蹤的數據從生產環境讀取處理(2)。
- 最後一些(3)的 bigtable 倉庫中。
看上面圖4:一次追蹤信息被存儲為 bigtable 的一行,每一列相當於一個 span。
引用參考
-
dapper 論文://research.google/pubs/pub36356/,
作者:Benjamin H. Sigelman, Luiz Andr´e Barroso, Mike Burrows, Pat Stephenson, Manoj Plakal, Donald Beaver, Saul Jaspan, Chandan Shanbhag
- //bigbully.github.io/Dapper-translation/ 中文翻譯版,bigbully
-
X-Trace 論文://www.usenix.org/legacy/event/nsdi07/tech/full_papers/fonseca/fonseca_html/index.html,
作者:Rodrigo Fonseca George Porter Randy H. Katz Scott Shenker Ion Stoica
-
Magpie 論文://www.usenix.org/legacy/publications/library/proceedings/hotos03/tech/full_papers/barham/barham_html/paper.html,作者:Paul Barham, Rebecca Isaacs, Richard Mortier, and Dushyanth Narayanan
Microsoft Research Ltd., Cambridge, UK. -
Pinpoint 論文://roc.cs.berkeley.edu/papers/roc-pinpoint-ipds.pdf,
作者:Mike Y. Chen, Emre Kıcıman, Eugene Fratkin, Armando Fox*, Eric Brewer
(Computer Science Division, University of California, Berkeley)
(*Computer Science Department, Stanford University)