分布式鏈路追蹤

分布式鏈路追蹤(Distributed Tracing),也叫 分布式鏈路跟蹤,分布式跟蹤辩涝,分布式追蹤 等等。

本文使用分布式Trace來簡(jiǎn)稱分布式鏈路追蹤勘天。

本篇文章只是從大致的角度來闡述什么是分布式Trace怔揩,以及一個(gè)分布式Trace系統(tǒng)具備哪些要點(diǎn)和特征。

場(chǎng)景

先從幾個(gè)場(chǎng)景來看為什么需要分布式Trace

場(chǎng)景1

開發(fā)A編寫了一段代碼脯丝,代碼依賴了很多的接口商膊。一個(gè)調(diào)用下去沒出結(jié)果,或者超時(shí)了宠进,Debug之后發(fā)現(xiàn)是接口M掛了晕拆,然后找到這個(gè)接口M的負(fù)責(zé)人B,告知B接口掛了材蹬。B拉起自己的調(diào)用和Debug環(huán)境实幕,按照之前傳過來的調(diào)用方式重新Debug了一遍自己的接口,發(fā)現(xiàn)NND是自己依賴的接口N掛了赚导,然后找到接口N負(fù)責(zé)人C茬缩。C同樣Debug了自己的接口(此處省略一萬個(gè)‘怎么可能呢赤惊,你調(diào)用參數(shù)不對(duì)吧’)吼旧,最終發(fā)現(xiàn)是某個(gè)空判斷錯(cuò)誤,修復(fù)bug未舟,轉(zhuǎn)告給B說我們bug修復(fù)了圈暗,B再轉(zhuǎn)告給A說,是C那個(gè)傻x弄掛了裕膀,現(xiàn)在Ok了员串,你試一下。

就這樣昼扛,一個(gè)上午就沒了寸齐,看著手頭的需求越堆越高,內(nèi)心是這樣

image.jpg

場(chǎng)景2

哪一天系統(tǒng)完成了開發(fā)抄谐,需要進(jìn)行性能測(cè)試渺鹦,發(fā)現(xiàn)哪些地方調(diào)用比較慢,影響了全局蛹含。A工程師拉起自己的系統(tǒng)毅厚,調(diào)用一遍,就匯報(bào)給老板浦箱,時(shí)間沒啥問題吸耿。B工程師拉起自己的系統(tǒng)祠锣,調(diào)用了一遍,也沒啥問題咽安,同時(shí)將結(jié)果匯報(bào)了給老板伴网。C工程師這時(shí)候發(fā)現(xiàn)自己的系統(tǒng)比較慢,debug發(fā)現(xiàn)原來是自己依賴的接口慢了妆棒,于是找到接口負(fù)責(zé)人是偷。。balabala募逞,和場(chǎng)景1一樣蛋铆,弄好了。老板一一把這些都記錄下來放接,滿滿的一本子刺啦。哪天改了個(gè)需求,又重新來一遍纠脾,勞民傷財(cái)玛瘸。

解決方案

這兩種場(chǎng)景只是縮影,假設(shè)這時(shí)候有這樣一種系統(tǒng)苟蹈,

image.jpg

它記錄了所有系統(tǒng)的調(diào)用和依賴糊渊,以及這些依賴之間的關(guān)系和性能。打個(gè)比方慧脱,一個(gè)網(wǎng)頁訪問了應(yīng)用M渺绒,應(yīng)用M又分別訪問了A,B菱鸥,C宗兼,D四個(gè)應(yīng)用,如下面這樣的結(jié)構(gòu)

image.png

那么在這個(gè)系統(tǒng)中就能夠看到氮采,一個(gè)網(wǎng)頁Request了一個(gè)應(yīng)用M殷绍,花費(fèi)了多少時(shí)間,請(qǐng)求的IP是多少鹊漠,請(qǐng)求的網(wǎng)絡(luò)開銷是多少主到。應(yīng)用M執(zhí)行時(shí)間是多久,是否執(zhí)行成功躯概,訪問A登钥,B,C楞陷,D分別花了多少時(shí)間怔鳖,是否成功,返回了什么內(nèi)容,測(cè)試是否通過结执。 然后到下一步度陆,A,B献幔,C懂傀,D四個(gè)應(yīng)用本次執(zhí)行的時(shí)間是多久烁挟,有沒有超時(shí)膘侮,調(diào)用了多少次DB适瓦,每次調(diào)用花費(fèi)了多少時(shí)間充坑。

作為示例,給出一個(gè)阿里鷹眼的trace圖:

image.png

trace就猶如一張大的json表腥泥,同一層級(jí)的數(shù)據(jù)代表同一層級(jí)的應(yīng)用奏篙,越往下代表是對(duì)下層某個(gè)應(yīng)用的依賴宋光。從圖中可以很方便的看到每一個(gè)應(yīng)用調(diào)用的名稱情连,調(diào)用花費(fèi)的時(shí)間叽粹,以及是否成功。

下面這張圖是我們使用微軟的application insights生成的tracing圖

image.png

有些敏感數(shù)據(jù)打上了馬賽克却舀,盡請(qǐng)諒解虫几。不過還是可以清晰的看到應(yīng)用之間的依賴關(guān)系,有處標(biāo)紅來代表此次調(diào)用出現(xiàn)了問題挽拔。

有了這個(gè)系統(tǒng)辆脸,場(chǎng)景1和場(chǎng)景2中的需求就能解決嗎?如果有了分布式trace螃诅,這些場(chǎng)景中的問題又是怎么解決呢啡氢?

對(duì)于場(chǎng)景1中的case,開發(fā)A發(fā)現(xiàn)自己的接口掛了或者比較慢州刽,而且Debug發(fā)現(xiàn)并不是自己代碼的錯(cuò)誤空执,這時(shí)候他找到自己的這一次trace,圖中就會(huì)列出來這一次trace的所有依賴和調(diào)用穗椅,以及各調(diào)用之間的關(guān)系。A發(fā)現(xiàn)奶栖,自己調(diào)用的鏈路到N接口那里就斷了匹表,并且調(diào)用N接口返回500錯(cuò)誤,于是A直接和N接口的負(fù)責(zé)人C聯(lián)系宣鄙,C立馬修復(fù)了錯(cuò)誤袍镀。

在A調(diào)用出錯(cuò)的時(shí)候,系統(tǒng)自動(dòng)檢測(cè)出在N接口出錯(cuò)冻晤,系統(tǒng)立馬生成一份錯(cuò)誤報(bào)告發(fā)到A和C的郵箱苇羡,A拿到報(bào)告的時(shí)候就直接能夠知道那個(gè)環(huán)節(jié)出錯(cuò)了,而C拿到報(bào)告的時(shí)候發(fā)現(xiàn)鼻弧,A在調(diào)用我的接口设江,并且我的接口出錯(cuò)了锦茁。這就是出錯(cuò)的主動(dòng)通知。

對(duì)于場(chǎng)景2叉存,項(xiàng)目開發(fā)完成了码俩,或者有新的pull request merge到主分支了,觸發(fā)了自動(dòng)化測(cè)試歼捏。測(cè)試下來同樣生成一張鏈路分析圖稿存,不管是開發(fā),測(cè)試瞳秽,DBA瓣履,還是老板,很容易從里面看到哪些應(yīng)用的響應(yīng)速度慢了练俐,讀取DB的時(shí)間慢了拂苹,接口掛了這些參數(shù)。再也不用一個(gè)一個(gè)搜集評(píng)測(cè)報(bào)告了痰洒。加快了持續(xù)集成和持續(xù)迭代瓢棒。

image.jpg

分布式Trace關(guān)乎到的不僅僅是開發(fā),運(yùn)維丘喻,還有測(cè)試脯宿,DBA,以及你老板的工作量泉粉。

上面的例子只是一個(gè)縮影连霉,如果一個(gè)公司內(nèi)部存在成千上萬個(gè)接口調(diào)用,到時(shí)候接口負(fù)責(zé)人都找不到的時(shí)候嗡靡,時(shí)間成本和溝通成本無法想象跺撼。

標(biāo)準(zhǔn)

現(xiàn)有的分布式Trace基本都是采用了google 的Dapper標(biāo)準(zhǔn)。

google Dapper

Dapper的思想很簡(jiǎn)單讨彼,就是在每一次調(diào)用棧中歉井,使用同一個(gè)TraceId將不同的server聯(lián)系起來。

我們使用幾張Dapper的圖來簡(jiǎn)單說明下

依賴

首先來一張應(yīng)用依賴圖

image.png

就是這樣一個(gè)調(diào)用鏈哈误,一個(gè)用戶請(qǐng)求了應(yīng)用A哩至,應(yīng)用A需要請(qǐng)求應(yīng)用B和應(yīng)用C,而應(yīng)用C需要請(qǐng)求應(yīng)用D和應(yīng)用E蜜自。

span

Dapper首先要做的就是規(guī)定Trace的結(jié)構(gòu)和基本要素菩貌,如下圖:

image.png

一次單獨(dú)的調(diào)用鏈也可以稱為一個(gè)span,dapper記錄的是span的名稱重荠,以及每個(gè)span的ID和父ID箭阶,以重建在一次追蹤過程中不同span之間的關(guān)系,上圖中一個(gè)矩形框就是一個(gè)span,前端從發(fā)出請(qǐng)求到收到回復(fù)就是一個(gè)span仇参。

再細(xì)化到一個(gè)span的內(nèi)部嘹叫,如下圖:

image.png

對(duì)于一個(gè)特定的span,記錄從Start到End冈敛,首先經(jīng)歷了客戶端發(fā)送數(shù)據(jù)待笑,然后server接收數(shù)據(jù),然后server執(zhí)行內(nèi)部邏輯抓谴,這中間可能去訪問另一個(gè)應(yīng)用暮蹂。執(zhí)行完了server將數(shù)據(jù)返回,然后客戶端接收到數(shù)據(jù)癌压。

一個(gè)span的內(nèi)容就能構(gòu)成Trace上面的一個(gè)基本元素仰泻,可以在這個(gè)span中埋點(diǎn)打上各種各樣的Trace類型,比如滩届,一般將客戶端發(fā)送記錄成依賴(dependency)集侯,服務(wù)端接收客戶端以及回復(fù)給客戶端這兩個(gè)時(shí)間統(tǒng)一記錄成請(qǐng)求(request),如果打上這兩種帜消,那么在運(yùn)行完這個(gè)span之后棠枉,日志庫(kù)中就會(huì)多出兩條日志,一條是dependency的日志泡挺,一條是request的日志辈讶。

現(xiàn)在的Trace SDK,都可以進(jìn)行配置去自動(dòng)記錄一些事件娄猫,比如數(shù)據(jù)庫(kù)調(diào)用依賴贱除,http調(diào)用依賴,記錄上游的請(qǐng)求等等媳溺,也可以自己手動(dòng)埋點(diǎn)月幌,在需要打上記錄點(diǎn)的地方寫上記錄的代碼即可。

結(jié)構(gòu)

Dapper中給出的是一張這樣的圖


image.png

首先各個(gè)日志收集點(diǎn)按照一定的采樣率將日志寫進(jìn)數(shù)據(jù)文件悬蔽,然后通過管道將這些日志文件按照一定的traceId排定輸出到BigTable中去扯躺。

如果一個(gè)系統(tǒng)完成了上面闡述的架構(gòu),基本可以構(gòu)成一個(gè)簡(jiǎn)單的Trace系統(tǒng)屯阀。

traceId和parentId的生成

在整個(gè)過程中缅帘,TraceId和ParentId的生成至關(guān)重要。首先解釋下TraceIdParentId难衰。TraceId是標(biāo)識(shí)這個(gè)調(diào)用鏈的Id,整個(gè)調(diào)用鏈逗栽,從瀏覽器開始放完盖袭,到A到B到C,一直到調(diào)用結(jié)束,所有應(yīng)用在這次調(diào)用中擁有同一個(gè)TraceId鳄虱,所以才能把這次調(diào)用鏈在一起弟塞。

既然知道了這次調(diào)用鏈的整個(gè)Id,那么每次查找問題的時(shí)候拙已,只要知道某一個(gè)調(diào)用的TraceId决记,就能把所有這個(gè)Id的調(diào)用全部查找出來,能夠清楚的知道本地調(diào)用鏈經(jīng)過了哪些應(yīng)用倍踪,產(chǎn)生了哪些調(diào)用系宫。但是還缺一點(diǎn),那就是鏈建车。

在java中有種數(shù)據(jù)結(jié)構(gòu)叫LinkedList扩借,還有種數(shù)據(jù)結(jié)構(gòu)叫Tree,即通過父節(jié)點(diǎn)就能夠知道子節(jié)點(diǎn)缤至,或者通過子節(jié)點(diǎn)能夠知道父節(jié)點(diǎn)是誰(雙向鏈表)潮罪,那么我想知道應(yīng)用A調(diào)用了哪些應(yīng)用,而又有哪些應(yīng)用調(diào)用了應(yīng)用A领斥,單純從TraceId里面根本看不出來嫉到,必須要指定自己的父節(jié)點(diǎn)才行,這就是ParentId的作用月洛。

先來看一張常規(guī)的調(diào)用圖


image.jpg

調(diào)用從一個(gè)瀏覽器發(fā)起何恶,然后進(jìn)入到微服務(wù)框架中,每一個(gè)服務(wù)都是一個(gè)獨(dú)立的應(yīng)用膊存,應(yīng)用之間通過RPC進(jìn)行調(diào)用导而。

分布式trace有兩個(gè)要求,1 是所有的一次調(diào)用鏈都采用一個(gè)traceId隔崎,2是能夠記錄這次調(diào)用時(shí)從哪里來的今艺。

在這點(diǎn)上不同的產(chǎn)品有不同的實(shí)現(xiàn)方式。

可以想象爵卒,最簡(jiǎn)單的虚缎,就是在一開始瀏覽器請(qǐng)求的時(shí)候,定義兩個(gè)字段(約定好的)钓株,比如一個(gè)叫TraceId实牡,一個(gè)叫ParentId,放到http的header中轴合,傳遞給應(yīng)用A创坞,應(yīng)用A解析傳遞過來的字段,就知道了TraceIdParentId受葛,即知道了本次調(diào)用鏈的Id题涨,以及上一個(gè)應(yīng)用的本次節(jié)點(diǎn)Id偎谁,然后就打上日志:某某時(shí)間應(yīng)用A收到了一條請(qǐng)求,TraceId是XXX纲堵,它的ParentId是XX巡雨。

這樣以后在查找問題的時(shí)候,先找到這次調(diào)用鏈的TraceId席函,發(fā)現(xiàn)有兩個(gè)應(yīng)用記錄了這個(gè)Id铐望,一個(gè)是前端的瀏覽器端記錄過,一個(gè)是應(yīng)用A記錄過茂附,并且鏈接關(guān)系是前端訪問的應(yīng)用A正蛙。

傳遞兩個(gè)參數(shù)的方式簡(jiǎn)潔易懂,這有個(gè)不好的地方何之,就是每次需要傳遞兩個(gè)參數(shù)跟畅,那么有沒有一種方案能夠?qū)蓚€(gè)Id合并為一個(gè)Id呢?可以的溶推。不同的產(chǎn)品實(shí)現(xiàn)是不一樣的徊件。

用上面的圖作一定解析,(上面的圖是阿里的鷹眼使用的Trace架構(gòu))蒜危,首先為第一個(gè)發(fā)起這個(gè)請(qǐng)求的request分配一個(gè)根id虱痕,即TraceId,就是上面圖中的0辐赞,這個(gè)0就是整個(gè)Trace中的TraceId部翘,然后應(yīng)用A拿到了這個(gè)號(hào),再在這個(gè)0后面添加上0.1和0.2分配給A所請(qǐng)求的應(yīng)用B和C响委,B跟C拿到0.1和0.2之后新思,便可以把這個(gè)Id作為ParentId,那么應(yīng)用B怎么獲取TraceId呢赘风,很簡(jiǎn)單夹囚,只要把string split一下,取第一個(gè)值就行邀窃,這里取出來就是0. 所以在設(shè)計(jì)Id組成的時(shí)候荸哟,不要把分隔符設(shè)計(jì)進(jìn)去,不然就不搞混的瞬捕。

業(yè)內(nèi)實(shí)現(xiàn)

openTracing是為了解決不同系統(tǒng)之間的兼容性設(shè)計(jì)的鞍历,現(xiàn)在也成為了各個(gè)第三方Trace系統(tǒng)的依賴的規(guī)范。

這是開源的產(chǎn)品

寫在后面

這篇文章只是從最簡(jiǎn)單的方面去闡述分布式Trace肪虎,甚至連分布式都沒有涉及劣砍。真正搭建一個(gè)分布式Trace,不僅僅需要定義結(jié)構(gòu)扇救,還需要保證日志的高可用秆剪,支持高并發(fā)和高性能赊淑。

比如阿里的鷹眼架構(gòu):

image.jpg

使用Storm集收集和分類日志數(shù)據(jù)爵政,然后將簡(jiǎn)單分析完的數(shù)據(jù)一方面寫進(jìn)Hbase供實(shí)時(shí)查詢仅讽,一方面將全量的日志寫進(jìn)HDFS,使用hadoop集群對(duì)這些數(shù)據(jù)進(jìn)行統(tǒng)計(jì)計(jì)算钾挟,經(jīng)過鷹眼的服務(wù)器把數(shù)據(jù)渲染展示出來洁灵。

可以看到,使用高可用的鷹眼中間件掺出,即需要保證日志的寫入不會(huì)丟失徽千,又不會(huì)對(duì)現(xiàn)有的業(yè)務(wù)產(chǎn)生性能影響,選擇合適的消息采樣率至關(guān)重要汤锨。日志文件收集的數(shù)據(jù)庫(kù)双抽,需要保證在大并發(fā)的條件下依然能夠順利寫入和讀取。還需要保證不同的server之間的數(shù)據(jù)關(guān)聯(lián)和事務(wù)保證闲礼。

這一系列的加起來牍汹,就是個(gè)龐大的系統(tǒng)了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柬泽,一起剝皮案震驚了整個(gè)濱河市慎菲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锨并,老刑警劉巖露该,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異第煮,居然都是意外死亡解幼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門包警,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撵摆,“玉大人,你說我怎么就攤上這事揽趾√ɑ悖” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵篱瞎,是天一觀的道長(zhǎng)苟呐。 經(jīng)常有香客問我,道長(zhǎng)俐筋,這世上最難降的妖魔是什么牵素? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮澄者,結(jié)果婚禮上笆呆,老公的妹妹穿的比我還像新娘请琳。我一直安慰自己,他們只是感情好赠幕,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布俄精。 她就那樣靜靜地躺著,像睡著了一般榕堰。 火紅的嫁衣襯著肌膚如雪竖慧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天逆屡,我揣著相機(jī)與錄音圾旨,去河邊找鬼。 笑死魏蔗,一個(gè)胖子當(dāng)著我的面吹牛砍的,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莺治,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼廓鞠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了产雹?” 一聲冷哼從身側(cè)響起诫惭,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔓挖,沒想到半個(gè)月后夕土,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘟判,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年怨绣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拷获。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡篮撑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匆瓜,到底是詐尸還是另有隱情赢笨,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布驮吱,位于F島的核電站茧妒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏左冬。R本人自食惡果不足惜桐筏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拇砰。 院中可真熱鬧梅忌,春花似錦狰腌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蹋笼,卻和暖如春展姐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剖毯。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留教馆,地道東北人逊谋。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像土铺,于是被迫代替她去往敵國(guó)和親胶滋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容