各大廠分散式鏈路跟蹤系統架構對比
隨著網際網路架構的擴張,分散式系統變得日趨複雜,越來越多的元件開始走向分散式化,如微服務、訊息收發、分散式資料庫、分散式快取、分散式物件儲存、跨域呼叫,這些元件共同構成了繁雜的分散式網路,那現在的問題是一個請求經過了這些服務後其中出現了一個呼叫失敗的問題,只知道有異常,但具體的異常在哪個服務引起的就需要進入每一個服務裡面看日誌,這樣的處理效率是非常低的。
分散式呼叫鏈其實就是將一次分散式請求還原成呼叫鏈路。顯式的在後端檢視一次分散式請求的呼叫情況,比如各個節點上的耗時、請求具體打到了哪臺機器上、每個服務節點的請求狀態等等。
鏈路跟蹤系統的功能
(1)故障快速定位
通過呼叫鏈跟蹤,一次請求的邏輯軌跡可以用完整清晰的展示出來。開發中可以在業務日誌中新增呼叫鏈ID,可以通過呼叫鏈結合業務日誌快速定位錯誤資訊。
(2)各個呼叫環節的效能分析
在呼叫鏈的各個環節分別新增呼叫時延,可以分析系統的效能瓶頸,進行鍼對性的優化。通過分析各個環節的平均時延,QPS等資訊,可以找到系統的薄弱環節,對一些模組做調整,如資料冗餘等。
(3)資料分析等
呼叫鏈繫結業務後檢視具體每條業務資料對應的鏈路問題,可以得到使用者的行為路徑,經過了哪些伺服器上的哪個服務,彙總分析應用在很多業務場景。
(4)生成服務呼叫拓撲圖
通過視覺化分散式系統的模組和他們之間的相互聯絡來理解系統拓撲。點選某個節點會展示這個模組的詳情,比如它當前的狀態和請求數量。
分散式呼叫跟蹤系統的設計
(1)分散式呼叫跟蹤系統的設計目標
低侵入性,應用透明:作為非業務元件,應當儘可能少侵入或者無侵入其他業務系統,對於使用方透明,減少開發人員的負擔
低損耗:服務呼叫埋點本身會帶來效能損耗,這就需要呼叫跟蹤的低損耗,實際中還會通過配置取樣率的方式,選擇一部分請求去分析請求路徑
大範圍部署,擴充套件性:作為分散式系統的元件之一,一個優秀的呼叫跟蹤系統必須支援分散式部署,具備良好的可擴充套件性
(2)埋點和生成日誌
埋點即系統在當前節點的上下文資訊,可以分為客戶端埋點、服務端埋點,以及客戶端和服務端雙向型埋點。埋點日誌通常要包含以下內容:
TraceId、RPCId、呼叫的開始時間,呼叫型別,協議型別,呼叫方ip和埠,請求的服務名等資訊;
呼叫耗時,呼叫結果,異常資訊,訊息報文等;
預留可擴充套件欄位,為下一步擴充套件做準備;
(3)抓取和儲存日誌
日誌的採集和儲存有許多開源的工具可以選擇,一般來說,會使用離線+實時的方式去儲存日誌,主要是分散式日誌採集的方式。典型的解決方案如Flume結合Kafka等MQ。
(4)分析和統計呼叫鏈資料
一條呼叫鏈的日誌散落在呼叫經過的各個伺服器上,首先需要按 TraceId 彙總日誌,然後按照RpcId 對呼叫鏈進行順序整理。用鏈資料不要求百分之百準確,可以允許中間的部分日誌丟失。
(5)計算和展示
彙總得到各個應用節點的呼叫鏈日誌後,可以針對性的對各個業務線進行分析。需要對具體日誌進行整理,進一步儲存在HBase或者關係型資料庫中,可以進行視覺化的查詢。
鏈路跟蹤Trace模型
一次典型的分散式呼叫過程,如下圖所示:
Trace呼叫模型,主要有以下概念:
Trace:一次完整的分散式呼叫跟蹤鏈路。
Span: 追蹤服務調基本結構,表示跨服務的一次呼叫; 多span形成樹形結構,組合成一次Trace追蹤記錄。
Annotation:在span中的標註點,記錄整個span時間段內發生的事件。
BinaryAnnotation:可以認為是特殊的Annotation,使用者自定義事件。
Annotation型別:保留型別
Cs CLIENT_SEND,客戶端發起請求
Cr CLIENT_RECIEVE,客戶端收到響應
Sr SERVER_RECIEVE,服務端收到請求
Ss SERVER_SEND,服務端傳送結果
使用者自定義型別:
Event 記錄普通事件
Exception 記錄異常事件
Client && Server:對於跨服務的一次呼叫,請求發起方為client,服務提供方為server
各術語在一次分散式呼叫中,關係如下圖所示:
呼叫跟蹤系統的選型
大的網際網路公司都有自己的分散式跟蹤系統,比如Google的Dapper,Twitter的zipkin,淘寶的鷹眼,新浪的Watchman,京東的Hydra等,下面來簡單分析。
Google的Drapper
Dapper是Google生產環境下的分散式跟蹤系統,Dapper有三個設計目標:
低消耗:跟蹤系統對線上服務的影響應該做到足夠小。
應用級的透明:對於應用的程式設計師來說,是不需要知道有跟蹤系統這回事的。如果一個跟蹤系統想生效,就必須需要依賴應用的開發者主動配合,那麼這個跟蹤系統顯然是侵入性太強的。
延展性:Google至少在未來幾年的服務和叢集的規模,監控系統都應該能完全把控住。
處理分為3個階段:
①各個服務將span資料寫到本機日誌上;
②dapper守護程序進行拉取,將資料讀到dapper收集器裡;
③dapper收集器將結果寫到bigtable中,一次跟蹤被記錄為一行。
阿里-鷹眼
關於淘寶的鷹眼系統,主要資料來自於內部分享:
鷹眼埋點和生成日誌:
如何抓取和儲存日誌,記錄本地檔案,使用額外的後臺程序定期(時間間隔小)收集日誌。這種方式的優勢在於對應用的效能影響小,方便做訊息堆積;但是需要在每臺業務server上都部署並管理日誌收集agent,運維量比較大。
鷹眼的實現小結:
注意Dapper與Eagle eye都不開源。
阿里EDAS+ARMS的立體化監控體系
通過阿里雲提供的EDAS結合ARMS可以打造立體化監控體系,其中EDAS用於應用管控層面,用於控制鏈路和應用;而ARMS更關注業務運營層面,如電商交易、車聯網、零售;實際上,監控需要全方位關注業務、鏈路、應用、系統,通過ARMS與EDAS相互補全,形成了立體化監控體系。
大眾點評——CAT
架構簡單。可以實現一個Trace系統的所有功能。架構如下圖所示:
跟蹤模型
Transaction是最重要的事件訊息型別,適合記錄跨越系統邊界的程式訪問行為,比如遠端呼叫,資料庫呼叫,也適合執行時間較長的業務邏輯監控,記錄次數與時間開銷。Transaction可巢狀。
跨服務的跟蹤功能與點評內部的RPC框架整合,這部分未開源。
客戶端接入方式
對於方法呼叫、sql、url請求等粒度較小的興趣點,需要業務人員手寫程式碼實現。
日誌收集方式
直接向日志收集器發非同步請求(有本地記憶體快取),一臺客戶端會連向幾個服務端,當一個服務端出問題,資料不會丟失。
當所有服務端都掛掉,訊息會存入queue,當queue滿了,就丟棄了,沒有做資料儲存本地等工作。
全量取樣,系統繁忙的時候對效能影響較大(可能達到10%的影響)
最後一個穩定版本是2014年1月,之後已經失去維護。
京東-hydra
與dubbo框架整合。對於服務級別的跟蹤統計,現有業務可以無縫接入。對於細粒度的興趣點,需要業務人員手動新增。架構如下:
Hydra中跟蹤資料模型
Trace: 一次服務呼叫追蹤鏈路。
Span: 追蹤服務調基本結構,多span形成樹形結構組合成一次Trace追蹤記錄。
Annotation: 在span中的標註點,記錄整個span時間段內發生的事件。
BinaryAnnotation: 屬於Annotation一種型別和普通Annotation區別,這鍵值對形式標註在span中發生的事件,和一些其他相關的資訊。
日誌收集方式
與CAT類似。支援自適應取樣,規則粗暴簡單,對於每秒鐘的請求次數進行統計,如果超過100,就按照10%的比率進行取樣。
開源專案已於2013年6月停止維護。
Twitter—OpenZipkin
功能、資料跟蹤模型與hydra類似。Zipkin本身不開源,開源社群的是另外一套scala實現,依託於finagle這個RPC框架。架構如下:
Zipkin與其他Trace系統的不同之處在於:
Zipkin中針對 HttpClient、jax-rs2、jersey/jersey2等HTTP客戶端封裝了攔截器。可以在較小的程式碼侵入條件下實現URl請求的攔截、時間統計和日誌記錄等操作。
日誌收集
Cat是直接將日誌發往消費叢集;hydra是發給日誌收集器,日誌收集器推到訊息佇列;Zipkin的client將統計日誌發往訊息佇列,日誌收集器讀取後落地儲存;Dapper和Eagle eye是記錄本地檔案,後臺程序定期掃描。
Trace系統現狀分析
以上幾款鏈路跟蹤系統都各自滿足了請求鏈路追蹤的功能,但落實到我們自己的生產環境中時,這些Trace系統存在諸多問題:Google和alibaba的Trace系統不開源,但現階段來說阿里是做得最好的,如果用的是阿里的伺服器,可考慮直接用阿里的追蹤系統以節省開發代價;
京東和點評的雖然開源,但是已經多年沒有維護,專案依賴的jdk版本以及第三方框架過於陳舊等等,不適合用在生產環境中;
Twitter的OpenZipkin使用scala開發,而且其實現基於twitter內部的RPC框架finagle,第三方依賴比較多,接入和運維的成本非常高。
如果不是用阿里的服務,我們可以借鑑這些開源實現的思想, 自行開發Trace系統。那是自己從0開始開發還是基於開源方案二次開發? 這裡面也要考慮到跨平臺,如NET和java環境,儘量減少原系統的侵入性或只需要更改少量的程式碼即可接入,在這裡可以基於zipkin和pinpoint進行二次開發,功能可參考阿里的系統。
Zipkin 和 Pinpoint 選型對比
Pinpoint 與 Zipkin 都是基於 Google Dapper 的那篇論文,因此理論基礎大致相同。Pinpoint 與 Zipkin 有明顯的差異,主要體現在如下幾個方面:
- Pinpoint 是一個完整的效能監控解決方案:有從探針、收集器、儲存到 Web 介面等全套體系;而 Zipkin 只側重收集器和儲存服務,雖然也有使用者介面,但其功能與 Pinpoint 不可同日而語。反而 Zipkin 提供有 Query 介面,更強大的使用者介面和系統整合能力,可以基於該介面二次開發實現。
- Zipkin 官方提供有基於 Finagle 框架(Scala 語言)的介面,而其他框架的介面由社群貢獻,目前可以支援 Java、Scala、Node、Go、Python、Ruby 和 C# 等主流開發語言和框架;但是 Pinpoint 目前只有官方提供的 Java Agent 探針,其他的都在請求社群支援中。
- Pinpoint 提供有 Java Agent 探針,通過位元組碼注入的方式實現呼叫攔截和資料收集,可以做到真正的程式碼無侵入,只需要在啟動伺服器的時候新增一些引數,就可以完成探針的部署;而 Zipkin 的 Java 介面實現 Brave,只提供了基本的操作 API,如果需要與框架或者專案整合的話,就需要手動新增配置檔案或增加程式碼。
- Pinpoint 的後端儲存基於 HBase,而 Zipkin 基於 Cassandra。
接入難度
因為 Brave 的注入需要依賴底層框架提供相關介面,因此並不需要對框架有一個全面的瞭解,只需要知道能在什麼地方注入,能夠在注入的時候取得什麼資料就可以了。就像上面的例子,我們根本不需要知道 MySQL 的 JDBC Driver 是如何實現的也可以做到攔截 SQL 的能力。但是 Pinpoint 就不然,因為 Pinpoint 幾乎可以在任何地方注入任何程式碼,這需要開發人員對所需注入的庫的程式碼實現有非常深入的瞭解,通過檢視其 MySQL 和 Http Client 外掛的實現就可以洞察這一點,當然這也從另外一個層面說明 Pinpoint 的能力確實可以非常強大,而且其預設實現的很多外掛已經做到了非常細粒度的攔截。
針對底層框架沒有公開 API 的時候,其實 Brave 也並不完全無計可施,我們可以採取 AOP 的方式,一樣能夠將相關攔截注入到指定的程式碼中,而且顯然 AOP 的應用要比位元組碼注入簡單很多。
以上這些直接關係到實現一個監控的成本,在 Pinpoint 的官方技術文件中,給出了一個參考資料。如果對一個系統整合的話,那麼用於開發 Pinpoint 外掛的成本是 100,將此外掛整合入系統的成本是 0;但對於 Brave,外掛開發的成本只有 20,而整合成本是 10。從這一點上可以看出官方給出的成本參考資料是 5:1。但是官方又強調了,如果有 10 個系統需要整合的話,那麼總成本就是 10 * 10 + 20 = 120,就超出了 Pinpoint 的開發成本 100,而且需要整合的服務越多,這個差距就越大。
從短期目標來看,Pinpoint 確實具有壓倒性的優勢:無需對專案程式碼進行任何改動就可以部署探針、追蹤資料細粒化到方法呼叫級別、功能強大的使用者介面以及幾乎比較全面的 Java 框架支援。但是長遠來看,學習 Pinpoint 的開發介面,以及未來為不同的框架實現介面的成本都還是個未知數。相反,掌握 Brave 就相對容易,而且 Zipkin 的社群更加強大,更有可能在未來開發出更多的介面。在最壞的情況下,我們也可以自己通過 AOP 的方式新增適合於我們自己的監控程式碼,而並不需要引入太多的新技術和新概念。而且在未來業務發生變化的時候,Pinpoint 官方提供的報表是否能滿足要求也不好說,增加新的報表也會帶來不可以預測的工作難度和工作量。
最後還要考慮日誌收集(直接傳送、記錄到本地再上傳)、日誌接收(訊息佇列,直接進入ElasticSearch)、資料清洗(Logstach、Storm、SparkStreaming)、日誌儲存(Mysql、Hbase、ElasticSearch)、頁面展示(自研還是直接用第三方的)。