【架构】分布式追踪系统设计与实现
分布式追蹤系統(tǒng)
使用 Zipkin 和 Brave 實(shí)現(xiàn)分布式系統(tǒng)追蹤(基礎(chǔ)篇) - 推酷OpenZipkin · A distributed tracing systemTwitter zipkin 分布式跟蹤系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn) - 馬宏的世界 - 博客頻道 - CSDN.NETopenzipkin/brave: Java distributed tracing implementation compatible with Zipkin backend services.openzipkin/zipkin: Zipkin is a distributed tracing systemzipkin - liaokailin的專欄 - 博客頻道 - CSDN.NET#研發(fā)解決方案介紹#Tracing(鷹眼) - 旁觀者 - 博客園分布式系統(tǒng)為什么需要 Tracing? 先介紹一個(gè)概念:分布式跟蹤,或分布式追蹤。 電商平臺由數(shù)以百計(jì)的分布式服務(wù)構(gòu)成,每一個(gè)請求路由過來后,會經(jīng)過多個(gè)業(yè)務(wù)系統(tǒng)并留下足跡,并產(chǎn)生對各種Cache或DB的訪問,但是這些分散的數(shù)據(jù)對于問題排查,或是流程優(yōu)化都幫助有限。對于這么一個(gè)跨進(jìn)程/跨線程的場景,匯總收集并分析海量日志就顯得尤為重要。要能做到追蹤每個(gè)請求的完整調(diào)用鏈路,收集調(diào)用鏈路上每個(gè)服務(wù)的性能數(shù)據(jù),計(jì)算性能數(shù)據(jù)和比對性能指標(biāo)(SLA),甚至在更遠(yuǎn)的未來能夠再反饋到服務(wù)治理中,那么這就是分布式跟蹤的目標(biāo)了。在業(yè)界,twitter 的 zipkin 和淘寶的鷹眼就是類似的系統(tǒng),它們都起源于 Google Dapper 論文,就像歷史上 Hadoop 發(fā)源于 Google Map/Reduce 論文,HBase 源自 Google BigTable 論文一樣。 好了,整理一下,Google叫Dapper,淘寶叫鷹眼,Twitter叫ZipKin,京東商城叫Hydra,eBay叫Centralized Activity Logging (CAL),大眾點(diǎn)評網(wǎng)叫CAT,我們叫Tracing。 這樣的系統(tǒng)通常有幾個(gè)設(shè)計(jì)目標(biāo): (1)低侵入性——作為非業(yè)務(wù)組件,應(yīng)當(dāng)盡可能少侵入或者無侵入其他業(yè)務(wù)系統(tǒng),對于使用方透明,減少開發(fā)人員的負(fù)擔(dān); (2)靈活的應(yīng)用策略——可以(最好隨時(shí))決定所收集數(shù)據(jù)的范圍和粒度; (3)時(shí)效性——從數(shù)據(jù)的收集和產(chǎn)生,到數(shù)據(jù)計(jì)算和處理,再到最終展現(xiàn),都要求盡可能快; (4)決策支持——這些數(shù)據(jù)是否能在決策支持層面發(fā)揮作用,特別是從 DevOps 的角度; (5)可視化才是王道。 先來一個(gè)直觀感受: 下面依次展示了 ZipKin、鷹眼、窩窩的調(diào)用鏈繪制界面。 圖1 twitter zipkin 調(diào)用鏈 圖2 淘寶鷹眼的調(diào)用鏈 圖3 京東商城hydra調(diào)用鏈 圖4 窩窩tracing調(diào)用鏈 鼠標(biāo)移動到調(diào)用鏈的每一層點(diǎn)擊,可以看到執(zhí)行時(shí)長、宿主機(jī)IP、數(shù)據(jù)庫操作、傳入?yún)?shù)甚至錯(cuò)誤堆棧等等具體信息。淘寶如何實(shí)現(xiàn)的: 同一次請求的所有相關(guān)調(diào)用的情況,在淘寶 EagleEye 里稱作?調(diào)用鏈。同一個(gè)時(shí)刻某一臺服務(wù)器并行發(fā)起的網(wǎng)絡(luò)調(diào)用有很多,怎么識別這個(gè)調(diào)用是屬于哪個(gè)調(diào)用鏈的呢?可以在各個(gè)發(fā)起網(wǎng)絡(luò)調(diào)用的中間件上下手。
? 在前端請求到達(dá)服務(wù)器時(shí),應(yīng)用容器在執(zhí)行實(shí)際業(yè)務(wù)處理之前,會先執(zhí)行 EagleEye 的埋點(diǎn)邏輯(類似 Filter 的機(jī)制),埋點(diǎn)邏輯為這個(gè)前端請求分配一個(gè)全局唯一的調(diào)用鏈ID。這個(gè)ID在 EagleEye 里面被稱為 TraceId,埋點(diǎn)邏輯把 TraceId 放在一個(gè)調(diào)用上下文對象里面,而調(diào)用上下文對象會存儲在 ThreadLocal 里面。調(diào)用上下文里還有一個(gè)ID非常重要,在 EagleEye 里面被稱作 RpcId。RpcId 用于區(qū)分同一個(gè)調(diào)用鏈下的多個(gè)網(wǎng)絡(luò)調(diào)用的發(fā)生順序和嵌套層次關(guān)系。對于前端收到請求,生成的 RpcId 固定都是0。
? 當(dāng)這個(gè)前端執(zhí)行業(yè)務(wù)處理需要發(fā)起 RPC 調(diào)用時(shí),淘寶的 RPC 調(diào)用客戶端 HSF 會首先從當(dāng)前線程 ThreadLocal 上面獲取之前 EagleEye 設(shè)置的調(diào)用上下文。然后,把 RpcId 遞增一個(gè)序號。在 EagleEye 里使用多級序號來表示 RpcId,比如前端剛接到請求之后的 RpcId 是0,那么 它第一次調(diào)用 RPC 服務(wù)A時(shí),會把 RpcId 改成 0.1。之后,調(diào)用上下文會作為附件隨這次請求一起發(fā)送到遠(yuǎn)程的 HSF 服務(wù)器。
? HSF 服務(wù)端收到這個(gè)請求之后,會從請求附件里取出調(diào)用上下文,并放到當(dāng)前線程 ThreadLocal 上面。如果服務(wù)A在處理時(shí),需要調(diào)用另一個(gè)服務(wù),這個(gè)時(shí)候它會重復(fù)之前提到的操作,唯一的差別就是 RpcId 會先改成 0.1.1 再傳過去。服務(wù)A的邏輯全部處理完畢之后,HSF 在返回響應(yīng)對象之前,會把這次調(diào)用情況以及 TraceId、RpcId 都打印到它的訪問日志之中,同時(shí),會從 ThreadLocal 清理掉調(diào)用上下文。如圖6-1展示了一個(gè)瀏覽器請求可能觸發(fā)的系統(tǒng)間調(diào)用。
圖6-1-一個(gè)瀏覽器請求可能觸發(fā)的系統(tǒng)間調(diào)用
? 圖6-1描述了 EagleEye 在一個(gè)非常簡單的分布式調(diào)用場景里做的事情,就是為每次調(diào)用分配 TraceId、RpcId,放在 ThreadLocal 的調(diào)用上下文上面,調(diào)用結(jié)束的時(shí)候,把 TraceId、RpcId 打印到訪問日志。類似的其他網(wǎng)絡(luò)調(diào)用中間件的調(diào)用過程也都比較類似,這里不再贅述了。訪問日志里面,一般會記錄調(diào)用時(shí)間、遠(yuǎn)端IP地址、結(jié)果狀態(tài)碼、調(diào)用耗時(shí)之類,也會記錄與這次調(diào)用類型相關(guān)的一些信息,如URL、服 務(wù)名、消息topic等。很多調(diào)用場景會比上面說的完全同步的調(diào)用更為復(fù)雜,比如會遇到異步、單向、廣播、并發(fā)、批處理等等,這時(shí)候需要妥善處理好 ThreadLocal 上的調(diào)用上下文,避免調(diào)用上下文混亂和無法正確釋放。另外,采用多級序號的 RpcId 設(shè)計(jì)方案會比單級序號遞增更容易準(zhǔn)確還原當(dāng)時(shí)的調(diào)用情況。
? 最后,EagleEye 分析系統(tǒng)把調(diào)用鏈相關(guān)的所有訪問日志都收集上來,按 TraceId 匯總在一起之后,就可以準(zhǔn)確還原調(diào)用當(dāng)時(shí)的情況了。
圖6-2-一個(gè)典型的調(diào)用鏈
? 如圖6-2所示,就是采集自淘寶線上環(huán)境的某一條實(shí)際調(diào)用鏈。調(diào)用鏈通過樹形展現(xiàn)了調(diào)用情況。調(diào)用鏈可以清晰地看到當(dāng)前請求的調(diào)用情況,幫助問題定 位。如上圖,mtop應(yīng)用發(fā)生錯(cuò)誤時(shí),在調(diào)用鏈上可以直接看出這是因?yàn)榈谒膶拥囊粋€(gè)(tair@1)請求導(dǎo)致網(wǎng)絡(luò)超時(shí),使最上層頁面出現(xiàn)超時(shí)問題。這種調(diào)用鏈,可以在 EagleEye 系統(tǒng)監(jiān)測到包含異常的訪問日志后,把當(dāng)前的錯(cuò)誤與整個(gè)調(diào)用鏈關(guān)聯(lián)起來。問題排查人員在發(fā)現(xiàn)入口錯(cuò)誤量上漲或耗時(shí)上升時(shí),通過 ?EagleEye 查找出這種包含錯(cuò)誤的調(diào)用鏈采樣,提高故障定位速度。
調(diào)用鏈數(shù)據(jù)在容量規(guī)劃和穩(wěn)定性方面的分析
? 如果對同一個(gè)前端入口的多條調(diào)用鏈做匯總統(tǒng)計(jì),也就是說,把這個(gè)入口URL下面的所有調(diào)用按照調(diào)用鏈的樹形結(jié)構(gòu)全部疊加在一起,就可以得到一個(gè)新的樹結(jié)構(gòu)(如圖6-3所示)。這就是入口下面的所有依賴的調(diào)用路徑情況。
圖6-3-對某個(gè)入口的調(diào)用鏈做統(tǒng)計(jì)之后得到的依賴分析
? 這種分析能力對于復(fù)雜的分布式環(huán)境的調(diào)用關(guān)系梳理尤為重要。傳統(tǒng)的調(diào)用統(tǒng)計(jì)日志是按固定時(shí)間窗口預(yù)先做了統(tǒng)計(jì)的日志,上面缺少了鏈路細(xì)節(jié)導(dǎo)致沒辦法對超過兩層以上的調(diào)用情況進(jìn)行分析。例如,后端數(shù)據(jù)庫就無法評估數(shù)據(jù)庫訪問是來源于最上層的哪些入口;每個(gè)前端系統(tǒng)也無法清楚確定當(dāng)前入口由于雙十一活動流量翻倍,會對后端哪些系統(tǒng)造成多大的壓力,需要分別準(zhǔn)備多少機(jī)器。有了 EagleEye 的數(shù)據(jù),這些問題就迎刃而解了。 下圖6-4展示了數(shù)據(jù)流轉(zhuǎn)過程。 圖6-4 鷹眼的數(shù)據(jù)收集和存儲 京東如何實(shí)現(xiàn)的:? 京東商城引入了阿里開源的服務(wù)治理中間件 Dubbo,所以它的分布式跟蹤 Hydra 基于 Dubbo 就能做到對業(yè)務(wù)系統(tǒng)幾乎無侵入了。 Hydra 的領(lǐng)域模型如下圖7所示: 圖7 hydra 領(lǐng)域模型以及解釋 hydra 數(shù)據(jù)存儲是 HBase,如下圖8所示: 圖8 hydra 架構(gòu) 窩窩如何實(shí)現(xiàn)的:? 2012年,逐漸看到自建分布式跟蹤系統(tǒng)的重要性,但隨即意識到如果沒有對 RPC 調(diào)用框架做統(tǒng)一封裝,就可能侵入到每一個(gè)業(yè)務(wù)工程里去寫埋點(diǎn)日志,于是推廣 Dubbo 也提上日程。2013年,確定系統(tǒng)建設(shè)目標(biāo),開始動手。由于 tracing 跟 DevOps 息息相關(guān),所以數(shù)據(jù)聚合、存儲、分析和展示由運(yùn)維部向榮牽頭開發(fā),各個(gè)業(yè)務(wù)工程數(shù)據(jù)埋點(diǎn)和上報(bào)由研發(fā)部國璽負(fù)責(zé)。 經(jīng)過后續(xù)向榮、劉卓、國璽、明斌等人的不斷改進(jìn),技術(shù)選型大致如下所示。- 埋點(diǎn)
- 實(shí)現(xiàn)線程內(nèi) trace 上下文傳遞,即服務(wù)器內(nèi)部的方法互調(diào)時(shí)不需要強(qiáng)制在方法形參中加 Message 參數(shù);
- 實(shí)現(xiàn) trace 埋點(diǎn)邏輯自動織入功能,即業(yè)務(wù)開發(fā)人員不需要在方法中打印 trace 日志,只需要給該方法加注解標(biāo)識 ;
- 原理:
- 利用 Javaagent 機(jī)制,執(zhí)行 main 方法之前,會先執(zhí)行 premain 方法,在該方法中將字節(jié)碼轉(zhuǎn)換器載入 instrumentation,而后 jvm 在加載 class 文件之前都會先執(zhí)行字節(jié)碼轉(zhuǎn)換器。
- 字節(jié)碼轉(zhuǎn)換器中的邏輯為,識別出注解 trace 的類及方法,并修改該方法字節(jié)碼,織入埋點(diǎn)邏輯。進(jìn)入方法時(shí)會初始 trace 上下文信息,并存儲在線程的 threadLocals 中,退出方法會打印 trace 日志并清空該方法的上下文。
- 數(shù)據(jù)聚合
- 應(yīng)用層 trace 日志通過 flume agents 實(shí)時(shí)發(fā)送至 flume collector;
- 數(shù)據(jù)存儲
- 服務(wù)端分別通過 hdfs-sink 和 hbase-sink,實(shí)時(shí)錄入至 hbase、hdfs;
- hdfs 有 tmp 臨時(shí)文件存放實(shí)時(shí)聚合過來的數(shù)據(jù),每5分鐘生成一個(gè) done 文件;
- 數(shù)據(jù)分析和統(tǒng)計(jì)
- load 程序每 4 分鐘檢查 done 文件并存放至 hive 表 hkymessage 指定分區(qū);
- 分析程序每5分鐘執(zhí)行一次, 將生成統(tǒng)計(jì)數(shù)據(jù)入庫, 結(jié)果集數(shù)據(jù)如下:
數(shù)據(jù)格式:{5個(gè)分層的5個(gè)響應(yīng)時(shí)段請求個(gè)數(shù)合集}?? {5個(gè)分層5-10s和大于10s散點(diǎn)數(shù)據(jù)合集}? 當(dāng)前5分鐘最后一次請求rootid? 統(tǒng)計(jì)時(shí)間
- 數(shù)據(jù)展示
- 基于 Python 的 Django
總結(jié)
以上是生活随笔為你收集整理的【架构】分布式追踪系统设计与实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Druid详细配置信息
- 下一篇: bootstrap-导航条反色的导航条