背景
随着滬江業務的高速發展,公司服務之間的調用關系愈加複雜,如何理清并跟蹤它們之間的調用關系就顯的比較關鍵。線上每一個請求會經過多個業務系統,并産生對各種緩存或者 DB 的通路,但是這些分散的資料對于問題排查,或者流程優化提供的幫助有限。在這樣複雜的業務場景下,業務流會經過很多個微服務的處理和傳遞,我們難免會遇到這些問題:
- 一次請求的流量從哪個服務而來? 最終落到了哪個服務中去?
- 為什麼這個請求這麼慢? 到底哪個環節出了問題?
- 這個操作需要依賴哪些東西? 是資料庫還是消息隊列? Redis挂了,哪些業務受影響?
設計目标
- 低消耗性:跟蹤系統對業務系統的影響應該做到足夠小。在一些高度優化過的服務,即使一點點損耗也容易察覺到,而且有可能迫使線上負責的部署團隊不得不将跟蹤系統關停
- 低侵入性:作為非業務元件,應當盡可能少侵入或者無侵入業務系統,對于使用方透明,減少開發人員的負擔
- 時效性:從資料的收集産生,到資料計算處理,再到最終展現,都要求盡可能快
- 決策支援:這些資料是否能在決策支援層面發揮作用,特别是從 DevOps 的角度
- 資料可視化:做到不用看日志通過可視化進行篩選
實作功能
- 故障定位:調用鍊路跟蹤,一次請求的邏輯軌迹可以完整清晰的展示出來。
- 性能分析:調用鍊的各個環節分别添加調用耗時,可以分析出系統的性能瓶頸,并針對性的優化。
- 資料分析:調用鍊是一條完整的業務日志,可以得到請求的行為路徑,彙總分析應用在很多業務場景
設計思路
對于上面那些問題,業内已經有了一些具體實踐和解決方案。通過調用鍊的方式,把一次請求調用過程完整的串聯起來,這樣就實作了對請求鍊路的監控。
在業界,目前已知的分布式跟蹤系統,比如「Twitter Zipkin 與淘寶鷹眼」,設計思想都是來自 Google Dapper 的論文 「Dapper, a Large-Scale Distributed Systems Tracing Infrastructure」
典型分布式調用過程
1:這個路徑由使用者的X請求發起,穿過一個簡單的服務系統。用字母辨別的節點代表分布式系統中的不同處理過程。
分布式服務的跟蹤系統需要記錄在一次特定的請求後系統中完成的所有工作的資訊。舉個例子,圖1展現的是一個和5台伺服器相關的一個服務,包括:前端(A),兩個中間層(B和C),以及兩個後端(D和E)。當一個使用者(這個用例的發起人)發起一個請求時,首先到達前端,然後發送兩個 RPC 到伺服器 B 和 C 。B 會馬上做出反應,但是 C 需要和後端的 D 和 E 互動之後再返還給 A ,由 A 來響應最初的請求。對于這樣一個請求,簡單實用的全鍊路跟蹤的實作,就是為伺服器上每一次你發送和接收動作來收集與跟蹤
調用鍊路關系圖
cs - CLIENT_SEND,用戶端發起請求
技術選型
綜上,考慮到公司目前以 Http 請求為主的場景,最終決定采用參考 Zipkin 的實作思路,同時以 OpenTracing 标準來相容多語言用戶端
系統設計
整體架構圖及說明
一般全鍊路跟蹤系統主要有四個部分:資料埋點、資料傳輸、資料存儲、查詢界面
資料埋點
- 通過內建 SDK 到滬江統一開發架構中,進行低侵入性的資料收集
- 采用 AOP 切面方式,将收集的資料存儲在本地線程變量 ThreadLocal 中,對應用透明
- 資料記錄 TraceId、事件應用、接口、開始時間、耗時
- 資料采用異步線程隊列的方式發送到 Kafka 隊列中,減少對業務的影響
目前支援的中間件有:
- Http 中間件
- Mysql 中間件
- RabbitMQ 中間件
資料傳輸
我們在 SDK 與後端服務之間加了一層 Kafka ,這樣做既可以實作工程解耦,又可以實作資料的延遲消費,起到削峰填谷的作用。我們不希望因為瞬時 QPS 過高而導緻資料丢失,當然為此也付出了一些實效性上的代價。
Kafka Manager 展示
資料存儲
資料存儲采用 ElasticSearch ,主要存儲 Span 與 Annotation 相關的資料,考慮到資料量的規模,先期隻儲存最近 1 個月的資料。
ELasticSearch Head 資料
查詢界面
通過可視化 Web 界面來查詢分布式調用鍊路,同時還提供根據項目次元分析依賴聚合
查詢頁面
Trace 樹
依賴分析
遇到的一些坑
Web 頁面加載逾時
問題
使用 Zipkin 官網 UI 的時候,會偶發性的出現業務加載逾時。
解決方案
原因是 Zipkin 加載頁面的時候會一次性加載該項目裡面所有的 Span ,當項目使用 Restful 形式的 API 時,就會産生幾百萬的 Span。最後,我們重寫 UI 頁面采用懶加載的方式,預設展示最近 10 條 Span,同時支援輸入字元來動态查詢 Span 的功能。
Span 堆積過多
問題
當使用頁面查詢 Trace 的時候,發現某個鍊路堆積到上千條 Span
解決方案
排查下來,業務方使用 HttpClient 中間件發送 HTTP 請求逾時的時候,SDK 并未攔截逾時異常,導緻事件一直在存儲線上程對應的 ThreadLocal 中。發現之後,在對應異常流程中,SDK 攔截請求異常,并清理 ThreadLocal 中對應的事件。
總結
全鍊路跟蹤系統關鍵點:調用鍊。
每次請求都生成全局唯一的 TraceID,通過該 ID 将不同的系統串聯起來。實作調用鍊跟蹤,路徑分析,幫助業務人員快速定位性能瓶頸,排查故障原因。
參考資料
- Google Dapper http://bigbully.github.io/Dapper-translation/
- Twitter http://zipkin.io/
- 窩窩網 Tracing 文章 http://www.cnblogs.com/zhengyun_ustc/p/55solution2.html
作者:老曹
來源-微信公衆号:滬江技術
出處:https://mp.weixin.qq.com/s/uYTVNMpX8Ci0oFvqEF_jlA