Golang中主要結合jaeger和opentracing去實現鏈路追蹤
鏈路追蹤中的基本概念:
tracer、span
tracer代表了一個流程或事務在分布式系統中的執行過程,tracer由多個span構成的有向無環圖,每個span代表tracer中被命名並計時的連續性執行片段
span代表系統中具有開始時間和執行時長的邏輯單元,span之間通過嵌套或者順序排列建立邏輯因果關系
關系:
分布式追蹤中的每個組件都包含自己的一個或者多個span。例如,在一個常規的RPC調用過程中,在RPC的客戶端和服務端,至少各有一個span,用於記錄RPC調用的客戶端和服務端信息。
一個父級的span會顯示的並行或者串行啟動多個子span。
一個 tracer 過程中,各span的關系 [Span A] ←←←(the root span) | +------+------+ | | [Span B] [Span C] ←←←(Span C 是 Span A 的孩子節點, ChildOf) | | [Span D] +---+-------+ | | [Span E] [Span F] >>> [Span G] >>> [Span H] ↑ ↑ ↑ (Span G 在 Span F 后被調用, FollowsFrom)
tracer和span的時間軸關系
tracer 與 span 的時間軸關系 ––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time [Span A···················································] [Span B··············································] [Span D··········································] [Span C········································] [Span E·······] [Span F··] [Span G··] [Span H··]
在分布式服務中需要用一個標志連接彼此的關系
traceId
假設服務調用關系為 a->b->c->d
,請求從 a 開始發起。 那么 a 負責生成 traceId,並在調用 b 的時候把 traceId 傳遞給 b,以此類推,traceId 會從 a 層層傳遞到 d。
這個 traceId 長這樣: {root span id}:{this span id}:{parent span id}:{flag}
。假設 a 是請求發起者,flag 固定為1,那么 a,b,c,d 的 traceId 分別是:
a_span_id:a_span_id:0:1 a_span_id:b_span_id:a_span_id:1 a_span_id:c_span_id:b_span_id:1 a_span_id:d_span_id:c_span_id:1
jaeger的5大組件:
jaeger-client:代碼接入的 jaegerClient。
jaeger-agent:jaeger-client 會把 span 上報給 jaeger-agent,這個 aegent 最好和 jaeger-client 部署在同一台服務器,離得近上報也快,否則可能會因為上報數據反而拖累業務
jaeger-collector:負責從 jaeger-agent 那里拿數據的服務, 有 push /pull 兩種方式
storage:存儲jaeger-collector 拿到的數據的地方,可以選 es 或者 cassandra。
jaeger-query:負責從 storage 查詢數據
運行流程圖:
一個簡單的微服務使用鏈路追蹤實例