Sleuth概述
前言
在微服務架構中,眾多的微服務之間互相調用,如何清晰地記錄服務的調用鏈路是一個需要解決的問題。同時,由於各種原因,跨進程的服務調用失敗時,運維人員希望能夠通過
查看日志和查看服務之間的調用關系來定位問題,而Spring cloud sleuth組件正是為了解決微服務跟蹤的組件。
一、背景
1、微服務的現狀?
隨着微服務架構的流行,服務按照不同的維度進行拆分,一次請求往往需要涉及到多個服務。在復雜的微服務架構系統中,幾乎每一個前端請求都會形成一個復雜的分布式服務調用
鏈路。一個請求完整調用鏈可能如下圖所示(盜圖):

隨着業務規模不斷增大、服務不斷增多以及頻繁變更的情況下,面對復雜的調用鏈路就帶來一系列問題:
如何快速發現問題?
如何判斷故障影響范圍?
如何梳理服務依賴以及依賴的合理性?
如何分析鏈路性能問題以及實時容量規划?
而鏈路追蹤的出現正是為了解決這種問題,它可以在復雜的服務調用中定位問題,除此之外,如果某個接口突然耗時增加,也不必再逐個服務查詢耗時情況,我們可以直觀地分析
出服務的性能瓶頸,方便在流量激增的情況下精准合理地擴容。
2、什么是鏈路追蹤
單純的理解鏈路追蹤,就是將一次分布式請求還原成調用鏈路,進行日志記錄,性能監控並將一次分布式請求的調用情況集中展示。比如各個服務節點上的耗時、請求具體到
達哪台機器上、每個服務節點的請求狀態等等。
3、鏈路追蹤相關產品
常見的鏈路追蹤技術有下面這些:
cat:由大眾點評開源,基於Java開發的實時應用監控平台,包括實時應用監控,業務監控 。 集成方案是通過代碼埋點的方式來實現監控,比如: 攔截器,過濾器等。 對代碼
的侵入性很大,集成成本較高。風險較大。
zipkin:由Twitter公司開源,開放源代碼分布式的跟蹤系統,用於收集服務的定時數據,以解決微服務架構中的延遲問題,包括:數據的收集、存儲、查找和展現。該產品結合
spring-cloud-sleuth使用較為簡單, 集成很方便, 但是功能較簡單。
pinpoint:Pinpoint是韓國人開源的基於字節碼注入的調用鏈分析,以及應用監控分析工具。特點是支持多種插件, UI功能強大,接入端無代碼侵入。
skywalking:本土開源的基於字節碼注入的調用鏈分析,以及應用監控分析工具。特點是支持多種插件, UI功能較強,接入端無代碼侵入。目前已加入Apache孵化器。
Sleuth:SpringCloud 提供的分布式系統中鏈路追蹤解決方案。
注意
: SpringCloud alibaba技術棧中並沒有提供自己的鏈路追蹤技術的,我們可以采用Sleuth +Zinkin來做鏈路追蹤解決方案
二、Sleuth概述
1、什么是Sleuth
Spring Cloud Sleuth 為 Spring Cloud 實現了分布式跟蹤解決方案。兼容 Zipkin,HTrace 和其他基於日志的追蹤系統,例如 ELK(Elasticsearch 、Logstash、 Kibana)。
Spring Cloud Sleuth 提供了以下功能:
鏈路追蹤
:通過 Sleuth 可以很清楚的看出一個請求都經過了那些服務,可以很方便的理清服務間的調用關系等。
性能分析
:通過 Sleuth 可以很方便的看出每個采樣請求的耗時,分析哪些服務調用耗時,當服務調用的耗時隨着請求量的增大而增大時, 可以對服務的擴容提供一定的提醒。
數據分析
,優化鏈路:對於頻繁調用一個服務,或並行調用等,可以針對業務做一些優化措施。
可視化錯誤
:對於程序未捕獲的異常,可以配合 Zipkin 查看。
2、Sleuth基本概念
Sleuth基本概念涉及到三個專業術語: span、Trace、Annotations。
span
基本工作單位,每次發送一個遠程調用服務就會產生一個 Span。Span 是一個 64 位的唯一 ID。通過計算 Span 的開始和結束時間,就可以統計每個服務調用所花費的時間。。
Trace
一系列 Span 組成的樹狀結構,一個 Trace 認為是一次完整的鏈路,內部包含 n 多個 Span。Trace 和 Span 存在一對多的關系,Span 與 Span 之間存在父子關系。
Annotations
用來及時記錄一個事件的存在,一些核心 annotations 用來定義一個請求的開始和結束。
cs - Client Sent:客戶端發起一個請求,這個 annotation 描述了這個 span 的開始;
sr - Server Received:服務端獲得請求並准備開始處理它,如果 sr 減去 cs 時間戳便可得到網絡延遲;
ss - Server Sent:請求處理完成(當請求返回客戶端),如果 ss 減去 sr 時間戳便可得到服務端處理請求需要的時間;
cr - Client Received:表示 span 結束,客戶端成功接收到服務端的回復,如果 cr 減去 cs 時間戳便可得到客戶端從服務端獲取回復的所有所需時間。
核心
為什么能夠進行整條鏈路的追蹤? 其實就是一個 Trace ID 將 一連串的 Span 信息連起來了。根據 Span 記錄的信息再進行整合就可以獲取整條鏈路的信息。
3、舉例理解Sleuth基本概念
上面這樣寫可能有點抽象,這里通過實際例子來解釋(盜圖)

1)這個圖中 從1->6 是一個完整的請求,所以這個完整的請求中有一個相同的TraceId。
2)server1->server2 可以理解是一個接口的請求,所以他們有着相同的SpanId。同樣道理 server2->server3,server2->server4 也有着相同的SpanId。同時parentid,
就是上一級的SpanId。
3)server1中的 cs cr - 分別代表請求server2的開始時間,和server1接收響應時間。(cr – cs)時間戳便可以得到整個請求所消耗的時間
4)server2中的 sr ss - 分別代表server2獲取請求並准備開始處理它的開始時間,ss (服務端發送響應)– 代表server2服務結束執行時間。
二、實現原理
這里通過圖片來循序漸進的理解Sleuth基本概念
如果想知道一個接口在哪個環節出現了問題,就必須清楚該接口調用了哪些服務,以及調用的順序,如果把這些服務串起來,看起來就像鏈條一樣,我們稱其為調用鏈。

想要實現調用鏈,就要為每次調用做個標識,然后將服務按標識大小排列,可以更清晰地看出調用順序,我們暫且將該標識命名為 spanid。

實際場景中,我們需要知道某次請求調用的情況,所以只有 spanid 還不夠,得為每次請求做個唯一標識,這樣才能根據標識查出本次請求調用的所有服務,而這個標識我們命名
為 traceid。

現在根據 spanid 可以輕易地知道被調用服務的先后順序,但無法體現調用的層級關系,正如下圖所示,多個服務可能是逐級調用的鏈條,也可能是同時被同一個服務調用。

所以應該每次都記錄下是誰調用的,我們用 parentid 作為這個標識的名字。

到現在,已經知道調用順序和層級關系了,但是接口出現問題后,還是不能找到出問題的環節,如果某個服務有問題,那個被調用執行的服務一定耗時很長,要想計算出耗時,
上述的三個標識還不夠,還需要加上時間戳,時間戳可以更精細一點,精確到微秒級。

只記錄發起調用時的時間戳還算不出耗時,要記錄下服務返回時的時間戳,有始有終才能算出時間差,既然返回的也記了,就把上述的三個標識都記一下吧,不然區分不出是
誰的時間戳。

雖然能計算出從服務調用到服務返回的總耗時,但是這個時間包含了服務的執行時間和網絡延遲,有時候我們需要區分出這兩類時間以方便做針對性優化。那如何計算網絡延遲
呢?我們可以把調用和返回的過程分為以下四個事件。
Client Sent 簡稱 cs,客戶端發起調用請求到服務端。
Server Received 簡稱 sr,指服務端接收到了客戶端的調用請求。
Server Sent 簡稱 ss,指服務端完成了處理,准備將信息返給客戶端。
Client Received 簡稱 cr,指客戶端接收到了服務端的返回信息。

假如在這四個事件發生時記錄下時間戳,就可以輕松計算出耗時,比如 `sr 減去 cs 就是調用時的網絡延遲,ss 減去 sr 就是服務執行時間,cr 減去 ss 就是服務響應的延遲,
cr 減 cs 就是整個服務調用執行的時間`。

其實 span 內除了記錄這幾個參數之外,還可以記錄一些其他信息,比如發起調用服務名稱、被調服務名稱、返回結果、IP、調用服務的名稱等,最后,我們再把相同 parentid
的 span 信息合成一個大的 span 塊,就完成了一個完整的調用鏈。
參考
Spring Cloud 系列之 Sleuth 鏈路追蹤(一)
少說多做,句句都會得到別人的重視;多說少做,句句都會受到別人的忽視。(13)