分佈式調用跟蹤系統架構設計與實踐

0、前言

隨着美團點評的業務發展,公司的分佈式系統變得愈來愈複雜,咱們亟需一個工具可以梳理內部服務之間的關係,感知上下游服務的形態。好比一次請求的流量從哪一個服務而來、最終落到了哪一個服務中去?服務之間是RPC調用,仍是HTTP調用?一次分佈式請求中的瓶頸節點是哪個,等等。html

一、簡介

MTrace,美團點評內部的分佈式會話跟蹤系統,其核心理念就是調用鏈:經過一個全局的ID將分佈在各個服務節點上的同一次請求串聯起來,還原原有的調用關係、追蹤系統問題、分析調用數據、統計系統指標。這套系統借鑑了2010年Google發表的一篇論文《dapper》,並參考了Twitter的Zipkin以及阿里的Eagle Eye的實現。
那麼咱們先來看一下什麼是調用鏈,調用鏈其實就是將一次分佈式請求還原成調用鏈路。顯式的在後端查看一次分佈式請求的調用狀況,好比各個節點上的耗時、請求具體打到了哪臺機器上、每一個服務節點的請求狀態,等等。它能反映出一次請求中經歷了多少個服務以及服務層級等信息(好比你的系統A調用B,B調用C,那麼此次請求的層級就是3),若是你發現有些請求層級大於10,那這個服務頗有可能須要優化了。前端

1.1 網絡優化

如上圖所示,紅框內顯示了一次分佈式請求通過各個服務節點的具體IP,經過該IP就能夠查詢一次分佈式請求是否有跨機房調用等信息,優化調用鏈路的網絡結構。mysql

1.2 瓶頸查詢

再好比上圖,紅框部分顯示的是系統調用的瓶頸節點,因爲該節點的耗時,致使了整個系統調用的耗時延長,所以該節點須要進行優化,進而優化整個系統的效率。這種問題經過調用鏈路能很快發現下游服務的瓶頸節點;可是假如沒有這樣的系統,咱們會怎樣作呢?首先我會發現下游服務超時形成了個人服務超時,這時我會去找這個下游服務的負責人,而後該負責人發現也不是他本身服務的問題,而是他們調用了其餘人的接口形成的問題,緊接着他又去找下游的服務負責人。咱們都知道跨部門之間的溝通成本很高的,這麼找下去會花費大量的沒必要要時間,而有了MTrace以後,你只須要點開鏈路就能發現超時問題的瓶頸所在。sql

1.3 優化鏈路

咱們再來看下上面這張圖,紅框部分都是同一個接口的調用,一次請求調用相同的接口10幾回甚至是幾十次,這是咱們不想看到的事情,那麼整個系統能不能對這樣的請求進行優化,好比改爲批量接口或者提升整個系統調用的並行度?在美團點評內部咱們會針對這樣的鏈路進行篩選分析,而後提供給業務方進行優化。後端

1.4 異常log綁定

經過MTrace不只能作上述這些事情,經過它的特性,還能攜帶不少業務感興趣的數據。由於MTrace能夠作到數據和一次請求的綁定以及數據在一次請求的網絡中傳遞。好比一些關鍵的異常log,通常服務的異常log頗有多是由於上游或者下游的異常形成的,那就須要咱們手動地對各個不一樣服務的異常log作mapping。看此次的異常log對應到上游服務的哪一個log上,是否是由於上游傳遞的一些參數形成了該次異常?而經過MTrace就能夠將請求的參數、異常log等信息經過traceId進行綁定,很容易地就把這些信息聚合到了一塊兒,方便業務端查詢問題。網絡

1.5 透明傳輸數據

業務端每每有這樣的需求,它但願一些參數能在一次分佈式請求一直傳遞下去,而且能夠在不一樣的RPC中間件間傳遞。MTrace對該類需求提供了兩個接口:架構

put(map<String, String> data)
putOnce(map<String, String> data)
  • put 接口:參數能夠在一次分佈式請求中一直傳遞。
  • putOnce 接口:參數在一次分佈式請求中只傳遞一級。

以下圖所示app

  • 左側綠色部分是put接口,service中調用了put接口傳遞了uid=123456這個參數,它會在網絡中一直傳遞,能夠在服務A中經過get("uid")的方式獲取參數值,也能夠在服務C中經過get("uid")的方式獲取參數值。
  • 右側藍色部分是putOnce接口,service中調用了putOnce接口傳遞pid=11111,它只會傳遞一級,能夠在服務B中經過get("pid")的方式獲取參數值,可是在服務D中就獲取不到pid的值了。

以上的兩種接口能夠用於業務自定義傳遞數據,好比經過傳遞一個服務標識,用於AB test,下游的全部服務獲取到test的標識就會走test的策略,即上游服務能夠傳遞一些參數,控制全部下游服務的邏輯。固然業務也能夠經過該接口傳遞一些臨時性的數據。框架

二、系統架構

主要分爲三層:數據埋點上報、數據收集計算、數據前端展現。異步

分佈式調用鏈跟蹤系統設計目標:

  • 低侵入性 – 做爲非業務組件,應當儘量少侵入或者無侵入其餘業務系統,對於使用方透明,減小開發人員的負擔;
  • 靈活的應用策略 – 能夠(最好隨時)決定所收集數據的範圍和粒度;
  • 時效性 – 從數據的收集和產生,到數據計算和處理,再到最終展示,都要求儘量快;
  • 決策支持 – 這些數據是否能在決策支持層面發揮做用,特別是從 DevOps 的角度;
  • 可視化纔是王道。

2.1 基本概念

traceId

全局惟一,64位整數,用於標識一次分佈式請求,會在RPC調用的網絡中傳遞。

spanId

簽名方式生成:0, 0.1, 0.1.1, 0.2。用於標識一次RPC在分佈式請求中的發生順序和嵌套層次關係,好比0.2就是0節點服務調用的第二個服務。

annotation

業務端自定義埋點,業務感興趣的想上傳到後端的數據,好比該次請求的用戶ID等。

2.2 數據埋點

埋點SDK

提供統一的SDK,在各個中間件中埋點,生成traceID等核心數據,上報服務的調用數據信息。

  • 生成調用上下文;
  • 同步調用上下文存放在ThreadLocal, 異步調用經過顯式調用API的方式支持;
  • 網絡中傳輸關鍵埋點數據,用於中間件間的數據傳遞,支持Thrift, HTTP協議。

業內有些系統是使用註解的方式實現的埋點,這種方式看似很優雅,可是須要業務方顯式依賴一些AOP庫,這部分很容易出現問題,由於AOP方式太過透明,致使查問題很麻煩,並且業務方配置的東西越多越容易引發一些意想不到的問題,因此咱們的經驗是儘可能在各個統一的中間件中進行顯式埋點,雖然會致使代碼間耦合度增長,可是方便後續定位問題。其次,爲了整個框架的統一,MTrace並不是僅支持Java一種語言,而AOP的特性不少語言是不支持的。

Agent

  • 透傳數據,用做數據轉發;
  • 作流量控制;
  • 控制反轉,不少策略能夠經過agent實現,而不須要每次都升級業務代碼中的SDK。

Agent僅僅會轉發數據,由Agent判斷將數據轉發到哪裏,這樣就能夠經過Agent作數據路由、流量控制等操做。也正是因爲Agent的存在,使得咱們能夠在Agent層實現一些功能,而不須要業務端作SDK的升級,要知道業務端SDK升級的過程是很緩慢的,這對於整個調用鏈的系統來講是不可接受的,由於MTrace整個系統是針對龐大的分佈式系統而言的,有一環的服務缺失也會形成必定的問題。

目前MTrace支持的中間件有:

  • 公司內部RPC中間件
  • http中間件
  • mysql中間件
  • tair中間件
  • mq中間件

數據埋點的四個階段:

  • 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資源也是值得的。具體上報的數據如圖所示:

咱們以前在數據埋點時遇到了一些問題:

  • 異步調用
    • 異步IO形成的線程切換,不能經過ThreadLocal傳遞上下文。
    • 顯式的經過API進行埋點傳遞,切換前保存,切換後還原。
    • 提供封裝好的ThreadPool庫。
  • 數據量大,天天千億級別的數據
    • 批量上報
    • 數據壓縮
    • 極端狀況下采樣

2.3 數據存儲

Kafka使用

咱們在SDK與後端服務之間加了一層Kafka,這樣作既能夠實現兩邊工程的解耦,又能夠實現數據的延遲消費。咱們不但願由於瞬時QPS太高而引發的數據丟失,固然爲此也付出了一些實效性上的代價。

實時數據Hbase

調用鏈路數據的實時查詢主要是經過Hbase,使用traceID做爲RowKey,能自然的把一整條調用鏈聚合在一塊兒,提升查詢效率。

離線數據Hive

離線數據主要是使用Hive,能夠經過SQL進行一些結構化數據的定製分析。好比鏈路的離線形態,服務的出度入度(有多少服務調用了該服務,該服務又調用了多少下游服務)

2.4 前端展現

前端展現,主要遇到的問題是NTP同步的問題,由於調用鏈的數據是從不一樣機器上收集上來的,那麼聚合展現的時候就會有NTP時間戳不一樣步的問題,這個問題很難解決,因而咱們採起的方式是前端作一層適配,經過SpanId定位調用的位置而不是時間,好比0.2必定是發生在0.1這個Span以後的調用,因此若是時間出現漂移,就會根據SpanId作一次校訂。即判斷時間順序的優先級爲最高是spanid,而後是時間戳。

三、總結

核心概念:調用鏈;
用途:定位系統瓶頸,優化系統結構、統計系統指標、分析系統數據;
架構:埋點上報、收集計算、展現分析。

分佈式會話跟蹤系統主要的特色就是能關聯服務之間的聯動關係,經過這層關係能夠延伸出來不少有意義的分析數據,統計數據。爲優化系統結構,查詢系統瓶頸問題帶來了極大的便利。

四、Refer

[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-鏈家全鏈路跟蹤平臺設計實踐

https://mp.weixin.qq.com/s/CAC1zG0nX3yMKqwuL2d2jQ

相關文章
相關標籤/搜索