隨着美團點評的業務發展,公司的分佈式系統變得愈來愈複雜,咱們亟需一個工具可以梳理內部服務之間的關係,感知上下游服務的形態。好比一次請求的流量從哪一個服務而來、最終落到了哪一個服務中去?服務之間是RPC調用,仍是HTTP調用?一次分佈式請求中的瓶頸節點是哪個,等等。html
MTrace,美團點評內部的分佈式會話跟蹤系統,其核心理念就是調用鏈:經過一個全局的ID將分佈在各個服務節點上的同一次請求串聯起來,還原原有的調用關係、追蹤系統問題、分析調用數據、統計系統指標。這套系統借鑑了2010年Google發表的一篇論文《dapper》,並參考了Twitter的Zipkin以及阿里的Eagle Eye的實現。
那麼咱們先來看一下什麼是調用鏈,調用鏈其實就是將一次分佈式請求還原成調用鏈路。顯式的在後端查看一次分佈式請求的調用狀況,好比各個節點上的耗時、請求具體打到了哪臺機器上、每一個服務節點的請求狀態,等等。它能反映出一次請求中經歷了多少個服務以及服務層級等信息(好比你的系統A調用B,B調用C,那麼此次請求的層級就是3),若是你發現有些請求層級大於10,那這個服務頗有可能須要優化了。前端
如上圖所示,紅框內顯示了一次分佈式請求通過各個服務節點的具體IP,經過該IP就能夠查詢一次分佈式請求是否有跨機房調用等信息,優化調用鏈路的網絡結構。mysql
再好比上圖,紅框部分顯示的是系統調用的瓶頸節點,因爲該節點的耗時,致使了整個系統調用的耗時延長,所以該節點須要進行優化,進而優化整個系統的效率。這種問題經過調用鏈路能很快發現下游服務的瓶頸節點;可是假如沒有這樣的系統,咱們會怎樣作呢?首先我會發現下游服務超時形成了個人服務超時,這時我會去找這個下游服務的負責人,而後該負責人發現也不是他本身服務的問題,而是他們調用了其餘人的接口形成的問題,緊接着他又去找下游的服務負責人。咱們都知道跨部門之間的溝通成本很高的,這麼找下去會花費大量的沒必要要時間,而有了MTrace以後,你只須要點開鏈路就能發現超時問題的瓶頸所在。sql
咱們再來看下上面這張圖,紅框部分都是同一個接口的調用,一次請求調用相同的接口10幾回甚至是幾十次,這是咱們不想看到的事情,那麼整個系統能不能對這樣的請求進行優化,好比改爲批量接口或者提升整個系統調用的並行度?在美團點評內部咱們會針對這樣的鏈路進行篩選分析,而後提供給業務方進行優化。後端
經過MTrace不只能作上述這些事情,經過它的特性,還能攜帶不少業務感興趣的數據。由於MTrace能夠作到數據和一次請求的綁定以及數據在一次請求的網絡中傳遞。好比一些關鍵的異常log,通常服務的異常log頗有多是由於上游或者下游的異常形成的,那就須要咱們手動地對各個不一樣服務的異常log作mapping。看此次的異常log對應到上游服務的哪一個log上,是否是由於上游傳遞的一些參數形成了該次異常?而經過MTrace就能夠將請求的參數、異常log等信息經過traceId進行綁定,很容易地就把這些信息聚合到了一塊兒,方便業務端查詢問題。網絡
業務端每每有這樣的需求,它但願一些參數能在一次分佈式請求一直傳遞下去,而且能夠在不一樣的RPC中間件間傳遞。MTrace對該類需求提供了兩個接口:架構
put(map<String, String> data) putOnce(map<String, String> data)
以下圖所示app
以上的兩種接口能夠用於業務自定義傳遞數據,好比經過傳遞一個服務標識,用於AB test,下游的全部服務獲取到test的標識就會走test的策略,即上游服務能夠傳遞一些參數,控制全部下游服務的邏輯。固然業務也能夠經過該接口傳遞一些臨時性的數據。框架
主要分爲三層:數據埋點上報、數據收集計算、數據前端展現。異步
分佈式調用鏈跟蹤系統設計目標:
全局惟一,64位整數,用於標識一次分佈式請求,會在RPC調用的網絡中傳遞。
簽名方式生成:0, 0.1, 0.1.1, 0.2。用於標識一次RPC在分佈式請求中的發生順序和嵌套層次關係,好比0.2就是0節點服務調用的第二個服務。
業務端自定義埋點,業務感興趣的想上傳到後端的數據,好比該次請求的用戶ID等。
提供統一的SDK,在各個中間件中埋點,生成traceID等核心數據,上報服務的調用數據信息。
業內有些系統是使用註解的方式實現的埋點,這種方式看似很優雅,可是須要業務方顯式依賴一些AOP庫,這部分很容易出現問題,由於AOP方式太過透明,致使查問題很麻煩,並且業務方配置的東西越多越容易引發一些意想不到的問題,因此咱們的經驗是儘可能在各個統一的中間件中進行顯式埋點,雖然會致使代碼間耦合度增長,可是方便後續定位問題。其次,爲了整個框架的統一,MTrace並不是僅支持Java一種語言,而AOP的特性不少語言是不支持的。
Agent僅僅會轉發數據,由Agent判斷將數據轉發到哪裏,這樣就能夠經過Agent作數據路由、流量控制等操做。也正是因爲Agent的存在,使得咱們能夠在Agent層實現一些功能,而不須要業務端作SDK的升級,要知道業務端SDK升級的過程是很緩慢的,這對於整個調用鏈的系統來講是不可接受的,由於MTrace整個系統是針對龐大的分佈式系統而言的,有一環的服務缺失也會形成必定的問題。
目前MTrace支持的中間件有:
Client Send : 客戶端發起請求時埋點,須要傳遞一些參數,好比服務的方法名等
Span span = Tracer.clientSend(param);
Server Recieve : 服務端接收請求時埋點,須要回填一些參數,好比traceId,spanId
Tracer.serverRecv(param);
ServerSend : 服務端返回請求時埋點,這時會將上下文數據傳遞到異步上傳隊列中
Tracer.serverSend();
Client Recieve : 客戶端接收返回結果時埋點,這時會將上下文數據傳遞到異步上傳隊列中
Tracer.clientRecv();
上圖CS、SR爲建立上下文的位置,CR、SS爲歸檔上下文的位置。
上下文歸檔,會把上下文數據異步上傳到後端,爲了減輕對業務端的影響,上下文上報採用的是異步隊列的方式,數據不會落地,直接經過網絡形式傳遞到後端服務,在傳遞以前會對數據作一層壓縮,主要是壓縮比很可觀,能夠達到10倍以上,因此就算犧牲一點CPU資源也是值得的。具體上報的數據如圖所示:
咱們在SDK與後端服務之間加了一層Kafka,這樣作既能夠實現兩邊工程的解耦,又能夠實現數據的延遲消費。咱們不但願由於瞬時QPS太高而引發的數據丟失,固然爲此也付出了一些實效性上的代價。
調用鏈路數據的實時查詢主要是經過Hbase,使用traceID做爲RowKey,能自然的把一整條調用鏈聚合在一塊兒,提升查詢效率。
離線數據主要是使用Hive,能夠經過SQL進行一些結構化數據的定製分析。好比鏈路的離線形態,服務的出度入度(有多少服務調用了該服務,該服務又調用了多少下游服務)
前端展現,主要遇到的問題是NTP同步的問題,由於調用鏈的數據是從不一樣機器上收集上來的,那麼聚合展現的時候就會有NTP時間戳不一樣步的問題,這個問題很難解決,因而咱們採起的方式是前端作一層適配,經過SpanId定位調用的位置而不是時間,好比0.2必定是發生在0.1這個Span以後的調用,因此若是時間出現漂移,就會根據SpanId作一次校訂。即判斷時間順序的優先級爲最高是spanid,而後是時間戳。
核心概念:調用鏈;
用途:定位系統瓶頸,優化系統結構、統計系統指標、分析系統數據;
架構:埋點上報、收集計算、展現分析。
分佈式會話跟蹤系統主要的特色就是能關聯服務之間的聯動關係,經過這層關係能夠延伸出來不少有意義的分析數據,統計數據。爲優化系統結構,查詢系統瓶頸問題帶來了極大的便利。
[1] 分佈式會話跟蹤系統架構設計與實踐
http://tech.meituan.com/mt-mtrace.html
[2] 分佈式調用跟蹤系統調研筆記
http://ginobefunny.com/post/learning_distributed_systems_tracing/
[3] 分佈式調用跟蹤與監控實戰
https://yq.aliyun.com/articles/75338
[4] 惟品會Microscope——大規模分佈式系統的跟蹤、監控、告警平臺
http://blog.csdn.net/alex19881006/article/details/24381109
[5] #研發解決方案介紹#Tracing(鷹眼)
http://www.cnblogs.com/zhengyun_ustc/p/55solution2.html
[6] 從宏觀到微觀——天機與鷹眼聯手
http://www.cnblogs.com/zhengyun_ustc/p/m2m.html
[7] 分佈式系統調用跟蹤實踐
https://t.hao0.me/devops/2016/10/15/distributed-invoke-trace.html
[8] 微服務架構下,如何實現分佈式跟蹤?
http://www.infoq.com/cn/articles/how-to-realize-distributed-tracking
[9] LTrace-鏈家全鏈路跟蹤平臺設計實踐