本文檔適用人員:研發




淘寶如何實現的:
在前端請求到達服務器時,應用容器在執行實際業務處理之前,會先執行 EagleEye 的埋點邏輯(類似 Filter 的機制),埋點邏輯為這個前端請求分配一個全局唯一的調用鏈ID。這個ID在 EagleEye 里面被稱為 TraceId,埋點邏輯把 TraceId 放在一個調用上下文對象里面,而調用上下文對象會存儲在 ThreadLocal 里面。調用上下文里還有一個ID非常重要,在 EagleEye 里面被稱作 RpcId。RpcId 用於區分同一個調用鏈下的多個網絡調用的發生順序和嵌套層次關系。對於前端收到請求,生成的 RpcId 固定都是0。
當這個前端執行業務處理需要發起 RPC 調用時,淘寶的 RPC 調用客戶端 HSF 會首先從當前線程 ThreadLocal 上面獲取之前 EagleEye 設置的調用上下文。然后,把 RpcId 遞增一個序號。在 EagleEye 里使用多級序號來表示 RpcId,比如前端剛接到請求之后的 RpcId 是0,那么 它第一次調用 RPC 服務A時,會把 RpcId 改成 0.1。之后,調用上下文會作為附件隨這次請求一起發送到遠程的 HSF 服務器。
HSF 服務端收到這個請求之后,會從請求附件里取出調用上下文,並放到當前線程 ThreadLocal 上面。如果服務A在處理時,需要調用另一個服務,這個時候它會重復之前提到的操作,唯一的差別就是 RpcId 會先改成 0.1.1 再傳過去。服務A的邏輯全部處理完畢之后,HSF 在返回響應對象之前,會把這次調用情況以及 TraceId、RpcId 都打印到它的訪問日志之中,同時,會從 ThreadLocal 清理掉調用上下文。如圖6-1展示了一個瀏覽器請求可能觸發的系統間調用。

圖6-1-一個瀏覽器請求可能觸發的系統間調用
圖6-1描述了 EagleEye 在一個非常簡單的分布式調用場景里做的事情,就是為每次調用分配 TraceId、RpcId,放在 ThreadLocal 的調用上下文上面,調用結束的時候,把 TraceId、RpcId 打印到訪問日志。類似的其他網絡調用中間件的調用過程也都比較類似,這里不再贅述了。訪問日志里面,一般會記錄調用時間、遠端IP地址、結果狀態碼、調用耗時之類,也會記錄與這次調用類型相關的一些信息,如URL、服 務名、消息topic等。很多調用場景會比上面說的完全同步的調用更為復雜,比如會遇到異步、單向、廣播、並發、批處理等等,這時候需要妥善處理好 ThreadLocal 上的調用上下文,避免調用上下文混亂和無法正確釋放。另外,采用多級序號的 RpcId 設計方案會比單級序號遞增更容易准確還原當時的調用情況。
最后,EagleEye 分析系統把調用鏈相關的所有訪問日志都收集上來,按 TraceId 匯總在一起之后,就可以准確還原調用當時的情況了。
圖6-2-一個典型的調用鏈
如圖6-2所示,就是采集自淘寶線上環境的某一條實際調用鏈。調用鏈通過樹形展現了調用情況。調用鏈可以清晰地看到當前請求的調用情況,幫助問題定 位。如上圖,mtop應用發生錯誤時,在調用鏈上可以直接看出這是因為第四層的一個(tair@1)請求導致網絡超時,使最上層頁面出現超時問題。這種調用鏈,可以在 EagleEye 系統監測到包含異常的訪問日志后,把當前的錯誤與整個調用鏈關聯起來。問題排查人員在發現入口錯誤量上漲或耗時上升時,通過 EagleEye 查找出這種包含錯誤的調用鏈采樣,提高故障定位速度。
調用鏈數據在容量規划和穩定性方面的分析
如果對同一個前端入口的多條調用鏈做匯總統計,也就是說,把這個入口URL下面的所有調用按照調用鏈的樹形結構全部疊加在一起,就可以得到一個新的樹結構(如圖6-3所示)。這就是入口下面的所有依賴的調用路徑情況。

圖6-3-對某個入口的調用鏈做統計之后得到的依賴分析
這種分析能力對於復雜的分布式環境的調用關系梳理尤為重要。傳統的調用統計日志是按固定時間窗口預先做了統計的日志,上面缺少了鏈路細節導致沒辦法對超過兩層以上的調用情況進行分析。例如,后端數據庫就無法評估數據庫訪問是來源於最上層的哪些入口;每個前端系統也無法清楚確定當前入口由於雙十一活動流量翻倍,會對后端哪些系統造成多大的壓力,需要分別准備多少機器。有了 EagleEye 的數據,這些問題就迎刃而解了。


- 埋點
- 實現線程內 trace 上下文傳遞,即服務器內部的方法互調時不需要強制在方法形參中加 Message 參數;
- 實現 trace 埋點邏輯自動織入功能,即業務開發人員不需要在方法中打印 trace 日志,只需要給該方法加注解標識 ;
- 原理:
- 利用 Javaagent 機制,執行 main 方法之前,會先執行 premain 方法,在該方法中將字節碼轉換器載入 instrumentation,而后 jvm 在加載 class 文件之前都會先執行字節碼轉換器。
- 字節碼轉換器中的邏輯為,識別出注解 trace 的類及方法,並修改該方法字節碼,織入埋點邏輯。進入方法時會初始 trace 上下文信息,並存儲在線程的 threadLocals 中,退出方法會打印 trace 日志並清空該方法的上下文。
- 數據聚合
- 應用層 trace 日志通過 flume agents 實時發送至 flume collector;
- 數據存儲
- 服務端分別通過 hdfs-sink 和 hbase-sink,實時錄入至 hbase、hdfs;
- hdfs 有 tmp 臨時文件存放實時聚合過來的數據,每5分鍾生成一個 done 文件;
- 數據分析和統計
- load 程序每 4 分鍾檢查 done 文件並存放至 hive 表 hkymessage 指定分區;
- 分析程序每5分鍾執行一次, 將生成統計數據入庫, 結果集數據如下:
數據格式:{5個分層的5個響應時段請求個數合集} {5個分層5-10s和大於10s散點數據合集} 當前5分鍾最后一次請求rootid 統計時間
- 數據展示
- 基於 Python 的 Django
窩窩的解決方案介紹列表:
#研發解決方案#基於StatsD+Graphite的智能監控解決方案
#研發解決方案介紹#Recsys-Evaluate(推薦評測)
#數據技術選型#即席查詢Shib+Presto,集群任務調度HUE+Oozie
