閱讀248 返回首頁    go 微軟 go windows


京東如何由“調用鏈”實現多維度的分布式跟蹤?

京東商城基礎平台團隊:作為京東的一級部門與技術基石,基礎平台部專注於四個技術方向:軟件定義數據中心與容器集群;存儲與數據庫技術;機器學習的業務應用;商城整體架構優化。京東商城首席架構師劉海鋒擔任部門負責人。基礎平台運營多個數據中心數萬台服務器,支撐京東無數在線業務(團隊公眾號ID:ipdchat)。

 

1 CallGraph的產生背景

 

隨著京東業務的高速增長,京東研發體係陸續實施了SOA化和微服務戰略,以應對日益複雜的業務和急劇增加的應用種類。這些分布式應用彼此依賴,共同協作來完成所有京東的業務場景,其動態變化的複雜性和數量已超出想象,對其進行監控並試圖掌控全局已非人力所及,迫切需要一種軟件工具來幫助相關人員理解係統行為,從而為諸如流程優化、架構優化、程序優化,以及擴容、限流、降級等運維行為提供科學的客觀依據。

 

CallGraph根據Google為其基於日誌的分布式跟蹤係統Dapper發表的論文,由京東商城基礎平台部自主研發,目前已經上線。業界亦有類似係統,比如淘寶鷹眼、新浪WatchMan等等,但CallGraph除了提供與這些係統類似的功能外,還有其自身的特色。

 

2 CallGraph的核心概念

 

“調用鏈”是CallGraph最重要的概念,一條調用鏈包含了從源頭請求(比如前端網頁請求、無線客戶端請求等)到最後底層係統(比如數據庫、分布式緩存等)的所有中間環節,如下圖所示。

 

20170207093816654.jpg

 

每次調用,都會在源頭請求中產生一個全局唯一的ID(稱為“TraceId”),通過網絡依次將TraceId傳到下一個環節,該過程被稱為“透明數據傳輸”(簡稱“透傳”),圖中的每一個環節都會生成包含TraceId在內的日誌信息,通過TraceId將散落在調用鏈中不同係統上的“孤立”日誌聯係在一起,然後通過日誌分析,重組還原出更多有價值的信息。

 

3 CallGraph的特性及使用場景

 

CallGraph本質上是一種監控係統,但它提供了一般監控係統所沒有的特性,每種特性都有其典型使用場景,為相關人員提供了強大的問題排查手段和決策依據,現總結如下:

 

 

20170207093826887.jpg

 

4 CallGraph的設計目標

 

針對CallGraph這樣的監控係統,特製定了如下設計目標:

 

1、低侵入性

作為非業務係統,應當盡可能少侵入或者不侵入其他業務係統,保持對使用方的透明性,這樣可以大大減少開發人員的負擔和接入門檻。

 

2、低性能影響

CallGraph通過對各中間件jar包進行改造,完成日誌數據的產生和收集,我們稱這種改造為“埋點”。由於埋點都發生在業務核心流程上,所以應該盡最大努力降低對業務係統造成的性能影響。

 

3、靈活的應用策略

為了消除業務方因使用CallGraph會對其自身產生影響的擔憂,應該提供靈活的配置策略,以讓業務方決定是否開啟跟蹤,以及收集數據的範圍和粒度,並提供技術手段保障配置必須生效。

 

4、時效性(time-efficient)

從數據的產生和收集,到數據計算/處理,再到展現,都要求盡可能快速。

 

5 CallGraph的實現架構

 

20170207093847136.jpg

 

1、CallGraph核心包

Callgraph-核心包被各中間件jar包引用,核心包裏完成了具體的埋點邏輯,各中間件在合適的地方調用核心包提供的API來完成埋點;核心包產生的日誌被存放在內存磁盤上,由日誌收集Agent發送到JMQ裏。

 

2、JMQ

JMQ是京東的分布式消息隊列,利用其強勁的性能,充當日誌數據管道,Storm將不斷地消費裏麵的日誌數據。

 

3、Storm

利用Storm進行流式計算,對日誌數據並行進行整理和各種計算,並將結果分別存放到實時數據存儲和離線數據存儲中。

 

4、存儲

包括實時數據和離線數據兩部分存儲。實時數據部分包括了Jimdb、Hbase和ES,Jimdb是京東自己的分布式緩存係統,裏存放了調用量、TP等實時指標數據;利用Hbase的SchemaLess特性,存放了固化後的鏈路數據,因為不同的鏈路包含的中間環節數量不一樣,無法用像Mysql這樣的強Schema特性的存儲,利用TraceId就可以從Hbase裏查詢到某一次調用的所有中間環節的信息。離線數據部分包括HDFS和Spark,用於海量曆史數據分析,並且還會把一些結果存放到Mysql中。

 

5、CallGraph-UI

這是CallGraph提供給用戶的交互界麵,在這裏麵用戶可以查看屬於自己的所有係統以及各係統內的應用的調用鏈路的詳細情況,包括應用間的相互依賴關係圖,某種服務方法的來源分析、入口分析、路徑分析,以及某次具體的調用鏈路的詳情等等,還可以對應用進行諸如“采樣率”等配置的設置。

 

6、UCC

UCC是京東自己的分布式配置係統,CallGraph用它來存放所有的配置信息,並且同步到應用服務器本地的配置文件中。核心包將定期檢查這些配置文件,以使配置生效。當UCC故障後,也可以通過直接操縱本地配置文件,使配置生效。

 

7、管理元數據

存放CallGraph的管理元數據,比如鏈路簽名與應用的映射關係、鏈路簽名與服務方法的映射關係等等;

 

6 CallGraph的技術實現

 

6.1 埋點和調用上下文透傳

 

該部分屬於架構圖中的CallGraph-核心包的重點部分,也是難點部分。CallGraph-核心包完成埋點邏輯,如下圖所示:

 

20170207093857748.jpg

 

前端應用和各中間件jar包引入CallGraph核心包,前端應用利用Web容器的Filter機製調用核心包的startTrace開啟跟蹤,收到響應後調用endTrace結束此次跟蹤,各中間件在合適的地方調用核心包提供的clientSend、serverRecv、serverSend和clientRecv等原語API,其中,橙色的完成“創建上下文”,綠色的完成“生成日誌”。

 

對於進程間的上下文透傳,調用上下文放在本地ThreadLocal,對業務透明,調用上下文在中間件的網絡請求中傳遞,並在對端收到後進行重組還原出調用上下文,過程如下圖所示:    

      20170207093905944.jpg

 

對於異步調用,將涉及到線程間上下文透傳,通過java字節碼增強的方式在CallGraph核心包載入期織入增強邏輯,以透明的方式完成線程間上下文的透傳。這裏又可分為兩種類型,一種是直接創建新線程的方式,如下圖所示

 

20170207093915574.jpg

 

這種方式通過對JDK線程對象(Thread)進行增強完成,子線程將把父線程的上下文作為自己的上下文(圖中的“子上下文”);對於使用Java線程池來提交異步任務來說,就不存在“父子”線程關係了,這時通過對各種JDK線程池的增強,實現了上下文透傳,如下圖所示:

 

20170207093921502.jpg 

 

上述過程對開發人員完全透明,對運維人員來說也很方便,做到了“低侵入性”。

 

6.2 日誌格式設計

 

CallGraph的日誌格式需要滿足不同中間件的特定要求,同時還要保證版本的兼容性。總體上說,CallGraph的日誌格式分成固定部分和可變部分,其中固定部分由如下組成:

  • TraceId、RpcId、開始時間、調用類型、對端IP

  • 調用耗時

  • 調用結果

  • 與中間件相關的數據(比如:rpc調用的接口、方法,mq的topic名稱等)

  • 通信負載量(請求字節數/響應字節數)

 

可變部分最重要的就是“自定義數據”,用戶可以使用CallGraph-核心包API增加自己的特殊字段,以用於特殊目的。通過抽象設計,不同場景的日誌格式都有專門的encoder類,在輸出日誌時配套使用。

 

6.3 高性能的鏈路日誌輸出

 

為了徹底避免和業務競爭I/O資源,CallGraph專門在應用服務器上開辟專門的內存區域,並虛擬成磁盤設備,核心包產生的日誌存放在這樣的內存磁盤上,完全不占用磁盤I/O,並且速度極快。同時開發專門的日誌模塊,日誌輸出采取批量、異步方式寫入內存磁盤,並在日誌量過大時采取“丟棄日誌”的方式最大程度地降低對業務的影響,如下圖所示:

 

20170207093929268.jpg

 

6.4 TP日誌和鏈路日誌分離

 

為了最大程度減少對業務性能的影響,在實踐中,多數情況下會開啟“采樣率”機製,比如1000次調用,隻收集1次調用的信息,這樣可以極大地降低日誌產生量。但是對於TP指標來說,必須記錄每次調用的TP值,否則提供的TP50、TP99、TP999指標將不準確,從而變得無意義。

 

從本質上說,鏈路信息和TP性能指標是兩種不同屬性的數據,因此在核心包裏分別對這兩種數據進行獨立處理,彼此互不影響,采用各自的日誌收集及輸出策略,TP指標的處理如下圖所示:

 

20170207093937843.jpg

 

6.5 實時配置

 

當雙11或者618大促時,各業務係統為了確保業務正常,基本上都會對非業務係統采取降級的手段。CallGraph為滿足業務方的這種需求,提供了豐富的配置和降級手段。CallGraph提供了基於應用、應用分組、應用服務器IP等多維度的配置方式,每個維度上都提供了“是否開啟鏈路跟蹤”、“鏈路采樣率”、“是否開啟TP跟蹤”、“TP顆粒度”等配置項,來供業務方根據情況來使用。

 

業務方通過CallGraph-UI管理端自助設置業務的各配置項。全部配置信息存放在UCC(京東的分布式配置係統)上,同時也會同步到應用服務器的本地配置文件中。CallGraph-核心包有專門的Daemon線程定期訪問本地的這些配置文件,以使配置生效;當UCC出現故障,不能被正常訪問時,也可以直接操縱這些本地配置文件,確保配置立即生效。

 

6.6 storm流式計算

 

所有日誌,不管是鏈路日誌還是TP日誌,最後都必須經過storm進行計算產生結果數據,並分別存儲到實時數據存儲和離線數據存儲中,如下圖所示:

 

20170207093945862.jpg 

 

離線分析Bolt由一係列Bolt組成,它們分析鏈路日誌信息,負責產生符合離線數據模型的結果數據,後續將由大數據技術比如spark/flume等進行計算,得到大時間尺度下的固定後的鏈路的一些特征指標,比如調用次數、平均耗時、錯誤率等等。

 

實時分析Bolt分析TP日誌信息,負責生成實時指標數據,並存儲在Jimdb中,供CallGraph-UI調用展示。

 

6.7 實時數據分析-秒級監控

 

這是CallGraph區別與其他類似係統的一大功能。其他類似係統隻提供鏈路日誌分析,而鏈路日誌的分析需要積累海量數據,然後借助大數據相關技術進行分析,其實時性較低。針對業務方對實時分析的需求,CallGraph采用分布式緩存係統Jimdb來存放實時數據,針對來源分析、入口分析、鏈路分析等可以提供1小時內的實時分析結果(Jimdb中的數據設置過期時間,自動過期),其中涉及到調用量、調用量占比、TP性能指標等的展示,該功能被內部稱為“秒級監控”。“秒級監控”需要對TP日誌進行分析,原理如下圖所示:

 

20170207093952336.jpg

 

LogRealTimeBolt將從LogTPSpout中得到TP原始日誌,進行整理、分析和計算,並將結果暫時緩存在“本地緩存”中,當達到累積計數條件後,再批量地匯總到Jimdb存儲中,這樣做的好處是先在本地進行合並計算,另外也減少了Jimdb的I/O次數。

 

7 CallGraph的未來之路

 

CallGraph在京東的曆史還很短,將來還有很長的路要走。為了進一步滿足業務方對CallGraph的需求,未來CallGraph將陸續完善和提供如下功能:

 

  1. 進一步優化實時數據的處理機製,使得時延更低,達到真正的“實時”。目前該功能由於需要經過日誌收集、JMQ以及storm等過程,所以存在十幾秒到幾十秒鍾的時延,屬於“準實時”的範疇;

     

  2. 完善實時的錯誤發現及報警機製,進一步提高發現問題的及時性;

     

  3. 接入更多的中間件,進一步豐富調用鏈內容,使調用鏈更長更完整;

     

  4. 提供完整的API接口,將調用鏈數據共享給兄弟團隊,方便他們構建自己的調用鏈分析係統;

     

  5. 借助深度學習算法,進一步挖掘調用鏈曆史數據的價值,力爭在更多維度上提供出有價值的分析數據。

最後更新:2017-05-15 18:02:25

  上一篇:go  一個參數救活被hang住的數據庫!
  下一篇:go  【資料合集】Apache Flink 精選PDF下載