什么是分布式鏈路跟蹤
簡而言之,在分布式系統下,用於跟蹤鏈路而衍生出的一項技術。
應用場景如下:
應用A,B,C,D,E 以一個層級關系依賴, 當用戶向 應用A
發起請求,但是返回了個異常,為了排查這個問題,我們可能要一台台服務器去排查。在分布式架構下,每個應用又部署了幾十上百台服務器, 那一天下來,可能多沒找到問題的觸發點。
通過分布式鏈路跟蹤,結合 如 鷹眼
等平台的 鏈路分析,我們可以很快定位到 問題發生機器地址。
那為什么我們可以很快速定位到哪台機器?
- TraceId 日志收集,收集異常日志,快速發現異常原因
- TraceId 埋入機器IP,快速定位異常機器
基本概念
一條 trace
鏈路是由多個與之關聯的 span
組成,一條鏈路整體可以看做是一張有向無環圖
,各個 span
之間的邊緣關系被稱之為References
。
- traceId: 每條鏈路只有唯一的
traceId
- spanId : 每個節點為一個
span
,存在層級關系
如何自己實現一套 Tracer
引用 SOFATracer 鏈路透傳原理:
- 跨進程的透傳,即如何將鏈路數據從一個進程傳遞到下游進程中
- 線程中的透傳
- 當前請求跨進程調用結束之后,當前如何恢復 tracer 上下文信息
- 如何實現跨線程的透傳,如在當前線程中起一個異步線程的場景
TracerId & SpanId 生成規則
TraceId 生成規則:
服務器 IP + 產生 ID 時候的時間 + 自增序列 + 當前進程號
0ad1348f1403169275002100356696
SpanId 生成規則:
root 節點為0,后續以 .
分割,不斷分層延續
跨進程透傳 TracerId
以 SOFATracer
為例 描述一下,一個 Http
請求是如何跨進程間進行傳輸的.
SofaTracer 源碼地址:
https://github.com/sofastack-guides/sofa-tracer-guides/tree/master/tracer-sample-with-springmvc
在一個 Http 請求中, 當請求經過 Filter
,SOFATracer
做的主要就是判斷當前請求的header中是否存在 traceId
, spanId
從依賴包中,我們可以看到,只有一個filter
Header存在 Tracer 信息
將上下文信息,存放到 ThreadLocal
中
Header 不存在 Tracer 信息
創建一個新的 上下文, 生成 traceId
和 spanId
,然后存放到 ThreadLocal
中
跨線程透傳 TracerId
通過深拷貝,創建一個新的上線文信息, 將 SofaTracerSpanContext 傳遞到子線程中
public SofaTracerSpanContext cloneInstance() {
// 重新構建一個 SofaTracerSpanContext 對象實例
// 這里會以當前父線程中的 tracerId,spanId,parentId以及采樣信息 作為構建構建參數
SofaTracerSpanContext spanContext = new SofaTracerSpanContext(this.traceId, this.spanId,
this.parentId, this.isSampled);
// 系統透傳數據
spanContext.addSysBaggage(this.sysBaggage);
// 業務透傳數據
spanContext.addBizBaggage(this.bizBaggage);
spanContext.childContextIndex = this.childContextIndex;
return spanContext;
}
手擼一個 DEMO
MyFilter
總結
原理看着挺簡單,但是實際使用上,還要考慮很多方面的問題, 如果日志收集,日志分析,traceId 生成規則等等,感興趣的大伙可以去看一下源碼: 傳送門
感謝大家的閱讀,希望對大家有所幫助,我是 九靈
,有需要交流的童鞋可以 加我wx,Jayce-K
,最近致力於幫助更多小伙伴加入大廠,歡迎來撩~