SpringCloud Sleuth工作原理和源碼分析


 

  1.  工作原理
  2. 源碼分析

 

 

術語(Terminology)

  • Span:基本工作單元,例如,在一個新建的span中發送一個RPC等同於發送一個回應請求給RPC,span通過一個64位ID唯一標識,trace以另一個64位ID表示,span還有其他數據信息,比如摘要、時間戳事件、關鍵值注釋(tags)、span的ID、以及進度ID(通常是IP地址),span在不斷的啟動和停止,同時記錄了時間信息,當你創建了一個span,你必須在未來的某個時刻停止它。
  • Trace:一系列spans組成的一個樹狀結構,例如,如果你正在跑一個分布式大數據工程,你可能需要創建一個trace。
  • Annotation:用來及時記錄一個事件的存在,一些核心annotations用來定義一個請求的開始和結束
    •   cs - Client Sent -客戶端發起一個請求,這個annotion描述了這個span的開始
    •   sr - Server Received -服務端獲得請求並准備開始處理它,如果將其sr減去cs時間戳便可得到網絡延遲
    •   ss - Server Sent -注解表明請求處理的完成(當請求返回客戶端),如果ss減去sr時間戳便可得到服務端需要的處理請求時間
    •   cr - Client Received -表明span的結束,客戶端成功接收到服務端的回復,如果cr減去cs時間戳便可得到客戶端從服務端獲取回復的所有所需時間

將Span和Trace在一個系統中使用Zipkin注解的過程圖形化:

 

每個顏色的注解表明一個span(總計7個spans,從A到G),如果在注解中有這樣的信息:

Trace Id = X

Span Id = D

Client Sent

這就表明當前span將Trace-Id設置為X,將Span-Id設置為D,同時它還表明了ClientSent事件。

spans 的parent/child關系圖形化

 

實現分析

 

  • 服務本身對traceId的處理

    Sleuth通過Filter的方式,在filter中對請求頭的處理來實現traceId的追蹤。

     

    先判斷http頭中是否存在“X-B3-TraceId”,不存在,則生成新的traceId;存在,則以頭X-B3-TraceId的值作為traceId。最后將X-B3-TraceId的值放到MDC中,以便日志輸出中帶上X-B3-TraceId。這樣使得在本服務中,用戶請求產生的日志輸出都會帶有traceId。

  • 服務間對traceId的處理

    在微服務中,服務A向服務B發起調用請求。那如何將A中的traceId傳遞給B呢?首先,先要了解服務A是如何調用服務B的。

    1、網關接收到進行,進行請求轉發

  • 網關(gateway)TraceWebFilter

  •  

    網關(zuul)ZuulFilter(TracePostZuulFilter)中將traceId添加到http頭X-B3-TraceId中,以便所轉發請求對應的服務能從頭中獲取到traceId。同時還將traceId放到MDC中,以便本應用在輸出日志時帶traceId。

    2、服務內部通過feign注解調用另一個服務

    由於feign注解的實現是通過生成Hystrix的代理類來完成請求的處理,而Hystrix在進行請求發送時是通過異步的方式調用ribbon的組件進行負載均衡,然后通過Feign.Client的execute方法來進行請求的發送。故此時需要解決以下兩個問題:

    (1)如何在異步線程中傳遞traceId。

    Sluth是通過實現HystrixConcurrencyStrategy接口來解決traceId異步傳遞的問題。Hystrix在實際調用時,會調用HystrixConcurrencyStrategy的wrapCallable方法。因此,通過實現這個接口,在wrapCallable中將traceId存放起來(具體參見SleuthHystrixConcurrencyStrategy)。

    (2)Feign如何在服務中傳遞traceId。

    Sluth通過實現Feign.Client,在execute前將traceId存放到X-B3-TraceId頭中來實現(具體參見TraceFeignClient)。

 

日志中字段說明

2019-05-20 13:56:14.921 DEBUG [user-client,fdf23ab0a44d64d9,fdf23ab0a44d64d9,true] 15208 --- [nio-8033-exec-8] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2019-05-20 13:56:14.958 DEBUG [user-client,6b7be2e8ac041461,6b7be2e8ac041461,false] 15208 --- [io-8033-exec-10] o.s.web.servlet.DispatcherServlet        : GET "/favicon.ico", parameters={}

 

注意MDC中的[appname,traceId,spanId,exportable]:

  • spanId - the id of a specific operation that took place
  • appname - the name of the application that logged the span
  • traceId - the id of the latency graph that contains the span
  • exportable - whether the log should be exported to Zipkin or not. Whenwould you like the span not to be exportable? In the case in which you want towrap some operation in a Span and have it written to the logs only. 是否應該將日志導出到Zipkin

 

 

Sleuth 支持可追蹤的組件包含:

 

 詳細實現:

 

 

 

 

常見問題:

  1. Sleuth在異步線程中丟失traceId  TraceableExecutorService 包裝 ExecutorService  http://www.saily.top/2018/12/29/sleuth-lost-traceId/

 

參考文檔:

https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.0.RELEASE/single/spring-cloud-sleuth.html#creating-spans-with-explicit-parent

https://github.com/apache/incubator-zipkin-b3-propagation#sampling-state-1

https://blog.csdn.net/yaowwwww7071/article/details/85769505

https://blog.csdn.net/xichenguan/article/details/77448288

https://blog.csdn.net/u010257992/article/details/52474639

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM