Spring Cloud Sleuth + Zipkin 實現服務追蹤

調用鏈監控的基礎原理

在介紹調用鏈監控工具以前,咱們首先須要知道在微服務架構系統中常常會遇到兩個問題:html

  • 跨微服務的API調用發生異常,要求快速定位(好比5分鐘之內)出問題出在哪裏,該怎麼辦?
  • 跨微服務的API調用發生性 能瓶頸,要求迅速定位(好比5分鐘之內)出系統瓶頸,該怎麼辦?

通常來講要解決這兩個問題或者與之相似的問題,就須要用到調用鏈監控工具。那麼調用鏈監控工具是怎麼實現問題的快速定位的呢?這就須要咱們理解調用鏈監控的基礎實現原理,咱們來看一張圖:
Spring Cloud Sleuth + Zipkin 實現服務追蹤java

圖中有兩個微服務分別是內容中心和用戶中心,其中內容中心的/shares/1接口會調用用戶中心的/users/1接口,這裏就產生了一個調用鏈。咱們能夠將調用的過程分爲四個階段或者說狀態,當內容中心發送調用請求時處於「client send」狀態,用戶中心接收到調用請求時處於「server receive」狀態,用戶中心處理完請求並返回結果時處於「server send」狀態,最後內容中心接收到響應結果時處於「client receive」狀態。linux

假設,調用鏈流轉每一個狀態時都會向一張數據表裏插入一些數據,以下圖所示:
Spring Cloud Sleuth + Zipkin 實現服務追蹤git

表字段說明:github

  • id:自增id
  • span_id:惟一id
  • pspan_id:父級span_id
  • service_name:服務名稱
  • api:api路徑
  • stage:階段/狀態
  • timestamp:插入數據時的時間戳

這是一張典型的自表一對多的表結構,根據這張表的數據,就能夠實現對以上所提到的兩個問題進行快速定位。首先對於第一個問題,能夠經過查詢表內的數據行數,判斷調用鏈在哪一個階段中斷了。例如表中只有uuid1和uuid2兩條數據,就能夠判斷出是user-center的接口出現了問題,沒有正常返回結果。再如表中只有uuid一、uuid2及uuid3這三條數據,就能夠判斷出content-center沒有正常接收到user-center返回的結果,以此類推。如此一來,就能夠經過表中的數據快速定位出跨微服務的API調用是在哪一個階段發生了異常。web

對於第二個問題,能夠經過計算timestamp分析哪一個調用比較耗時。例如上圖中的t2 - t1能夠得出請求的發送到請求的接收所消耗的時間,再如t3 - t2能夠得出/users/1這個接口的調用耗時,而t4 - t1則能夠得出整個調用鏈的耗時,以此類推。因此當跨微服務的API調用發生性能瓶頸時,就能夠經過分析各個調用接口的耗時,快速定位出是哪一個微服務接口拖慢了整個調用鏈耗時。spring

以上舉例簡述了實現調用鏈監控的基礎原理,雖然未必全部的調用鏈監控工具都是這麼實現的,但基本都殊途同歸,或在其之上進行了一些拓展。因此只要理解了這一部分,在學習各類調用鏈監控工具時就會比較快上手。docker


Spring Cloud Sleuth簡介

Spring Cloud Sleuth實現了一種分佈式的服務鏈路跟蹤解決方案,經過使用Sleuth可讓咱們快速定位某個服務的問題。簡單來講,Sleuth至關於調用鏈監控工具的客戶端,集成在各個微服務上,負責產生調用鏈監控數據。數據庫

官方文檔地址以下:api

http://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.0.1.RELEASE/single/spring-cloud-sleuth.html

一些概念:

  1. Span(跨度):Span是基本的工做單元。Span包括一個64位的惟一ID,一個64位trace碼,描述信息,時間戳事件,key-value 註解(tags),span處理者的ID(一般爲IP)。
    最開始的初始Span稱爲根span,此span中span id和 trace id值相同。

  2. Trance(跟蹤):包含一系列的span,它們組成了一個樹型結構

  3. Annotation(標註):用於及時記錄存在的事件。經常使用的Annotation以下:
    • CS(Client Sent 客戶端發送):客戶端發送一個請求,表示span的開始
    • SR(Server Received 服務端接收):服務端接收請求並開始處理它。(SR - CS)等於網絡的延遲
    • SS(Server Sent 服務端發送):服務端處理請求完成,開始返回結束給服務端。(SR - SS)表示服務端處理請求的時間
    • CR(Client Received 客戶端接收):客戶端完成接受返回結果,此時span結束。(CR - CS)表示客戶端接收服務端數據的時間

若是一個服務的調用關係以下:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

那麼此時將Span和Trace在一個系統中使用Zipkin註解的過程圖形化以下:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

每一個顏色的代表一個span(總計7個spans,從A到G),每一個span有相似的信息

Trace Id = X
Span Id = D
Client Sent

此span表示span的Trance Id是X,Span Id是D,同時它發送一個Client Sent事件

spans 的parent/child關係圖形化以下:
Spring Cloud Sleuth + Zipkin 實現服務追蹤


整合Spring Cloud Sleuth

瞭解完基本的一些概念後,咱們來在訂單服務和商品服務中,集成spring cloud sleuth以及zipkin。在兩個服務的pom.xml文件中,增長以下依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

爲了更詳細的查看服務通訊時的日誌信息,咱們能夠將Feign和Sleuth的日誌級別設置爲debug。在兩個項目的配置文件中,加入以下內容便可:

logging:
  level:
    org.springframework.cloud.openfeign: debug
    org.springframework.cloud.sleuth: debug

啓動訂單、商品服務項目,而後訪問建立訂單的接口,訂單服務的控制檯會輸出一段這樣的信息:

[order,6c8ecdeefb0fc723,cc4109a6e8e56d1c,false]

商品服務的控制檯也會輸出相似的信息,以下:

[product,6c8ecdeefb0fc723,40cdc34e745d59e7,false]

說明:

  • product: 看也知道是服務名稱
  • 6c8ecdeefb0fc723: 是TranceId,一條鏈路中,只有一個TranceId
  • 40cdc34e745d59e7:則是spanId,鏈路中的基本工做單元id
  • false:表示是否將數據輸出到其餘服務,true則會把信息輸出到其餘可視化的服務上觀察

Zipkin搭建與整合

經過Sleuth產生的調用鏈監控信息,讓咱們能夠得知微服務之間的調用鏈路,可是監控信息只輸出到控制檯始終不太方便查看。因此咱們須要一個圖形化的工具,這時候就輪到zipkin出場了。Zipkin是Twitter開源的分佈式跟蹤系統,主要用來收集系統的時序數據,從而追蹤系統的調用問題。zipkin官網地址以下:

https://zipkin.io/

zipkin結構圖:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

接下來咱們搭建一個zipkin服務器。

方式1,使用Zipkin官方的Shell下載,使用以下命令可下載最新版本:

[root@01server ~]#  curl -sSL https://zipkin.io/quickstart.sh | bash -s

下載下來的文件名爲 zipkin.jar

方式2,到Maven中央倉庫下載,使用瀏覽器訪問以下地址便可:

https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec

下載下來的文件名爲 zipkin-server-{版本號}-exec.jar

因爲Zipkin實際是一個Spring Boot項目,因此使用以上兩種方式下載的jar包,能夠直接使用以下命令啓動:

java jar {zipkin jar包路徑}

方式3,經過docker安裝,命令以下:

[root@01server ~]# docker run -d -p 9411:9411 openzipkin/zipkin

安裝好後,使用瀏覽器訪問9411端口,主頁面以下所示:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

而後在訂單服務中將以前的sleuth依賴替換成以下依賴:

<!-- 這個依賴包含了sleuth和zipkin -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

在配置文件中,增長zipkin相關的配置項。以下:

spring:
  ...
  zipkin:
    base-url: http://127.0.0.1:9411/  # zipkin服務器的地址
    # 關閉服務發現,不然Spring Cloud會把zipkin的url當作服務名稱       
    discoveryClientEnabled: false   
    sender:
      type: web  # 設置使用http的方式傳輸數據
  sleuth:
    sampler:
      probability: 1  # 設置抽樣採集率爲100%,默認爲0.1,即10%

配置好後重啓項目,並訪問建立訂單接口。下單成功後,到zipkin頁面上就能夠查看到order服務的鏈路信息了:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

會有紅色的信息表示有錯誤,點擊上圖中的紅色信息後,能夠進入到服務鏈路的查看頁面,在這裏能夠看到整條服務鏈路,而且能夠看到每個服務調用的耗時,也能夠看到是哪一步調用發生了錯誤:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

點擊每一行信息均可以查看其詳情信息,例如我點擊耗時46.236ms的那行信息,其詳細信息以下:
Spring Cloud Sleuth + Zipkin 實現服務追蹤


Zipkin數據持久化

Zipkin默認是將監控數據存儲在內存的,若是Zipkin掛掉或重啓的話,那麼監控數據就會丟失。因此若是想要搭建生產可用的Zipkin,就須要實現監控數據的持久化。而想要實現數據持久化,天然就是得將數據存儲至數據庫。好在Zipkin支持將數據存儲至:

  • 內存(默認)
  • MySQL
  • Elasticsearch
  • Cassandra

Zipkin數據持久化相關的官方文檔地址以下:

https://github.com/openzipkin/zipkin#storage-component

Zipkin支持的這幾種存儲方式中,內存顯然是不適用於生產的,這一點開始也說了。而使用MySQL的話,當數據量大時,查詢較爲緩慢,也不建議使用。Twitter官方使用的是Cassandra做爲Zipkin的存儲數據庫,但國內大規模用Cassandra的公司較少,並且Cassandra相關文檔也很少。

綜上,故採用Elasticsearch是個比較好的選擇,關於使用Elasticsearch做爲Zipkin的存儲數據庫的官方文檔以下:

既然選擇Elasticsearch做爲Zipkin的存儲數據庫,那麼天然首先須要搭建一個Elasticsearch服務,單節點搭建比較簡單,直接到官網下載壓縮包,而後使用以下命令解壓並啓動便可(關於ES的版本選擇需參考官方文檔,目前Zipkin支持5.x、6.x及7.x):

[root@01server ~]# tar -zxvf elasticsearch-6.5.3-linux-x86_64.tar.gz   # 解壓
[root@01server ~]# cd elasticsearch-6.5.3/bin
[root@01server ~/elasticsearch-6.5.3/bin]# ./elasticsearch  # 啓動

因爲Elasticsearch不是本文的重點,這裏不作很少的介紹,關於Elasticsearch的集羣搭建能夠參考以下文章:

搭建好Elasticsearch後,使用以下命令啓動Zipkin,Zipkin就會切換存儲類型爲Elasticsearch,而後根據指定的鏈接地址鏈接Elasticsearch並存儲數據:

STORAGE_TYPE=elasticsearch ES_HOSTS=localhost:9200 java -jar zipkin-server-2.11.3-exec.jar

Tips:

  • 其中,STORAGE_TYPEES_HOSTS是環境變量,STORAGE_TYPE用於指定Zipkin的存儲類型是啥;而ES_HOSTS 則用於指定Elasticsearch地址列表,有多個節點時使用逗號( , )分隔。

除此以外,還能夠指定其餘環境變量,參考下表:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

關於其餘環境變量,可參考官方文檔:

最後能夠根據如下測試步驟,自行測試一下Zipkin是否能正常將監控數據持久化存儲:

  1. 往Zipkin中存儲一些數據
  2. 中止Zipkin
  3. 再次啓動Zipkin,查看以前存儲的數據是否存在,若是存在說明數據已被持久化

關於依賴關係圖的問題

在上一小節中,簡單介紹了Zipkin的數據持久化,並整合了Elasticsearch做爲Zipkin的存儲數據庫。但此時會有一個問題,就是Zipkin在整合Elasticsearch後會沒法分析服務之間的依賴關係圖,由於此時數據都存儲到Elasticsearch中了,沒法再像以前那樣在內存中進行分析。

想要解決這個問題,須要下載並使用Zipkin的一個子項目:

方式1,使用官方的Shell下載,使用以下命令可下載最新版本:

[root@01server ~]# curl -sSL https://zipkin.io/quickstart.sh | bash -s io.zipkin.dependencies:zipkin-dependencies:LATEST zipkin-dependencies.jar

下載下來的文件名爲 zipkin-dependencies.jar

方式2,到Maven中央倉庫下載,使用瀏覽器訪問以下地址便可:

https://search.maven.org/remote_content?g=io.zipkin.dependencies&a=zipkin-dependencies&v=LATEST

下載下來的文件名爲 zipkin-dependencies-{版本號}.jar

下載好後,使用以下命令運行這個jar包便可分析Elasticsearch中存儲的數據:

[root@01server ~]# STORAGE_TYPE=elasticsearch ES_HOSTS=localhost:9200 java -jar zipkin-dependencies-2.3.2.jar

該jar包運行結束後,到Zipkin的界面上點開「Dependencies」就能夠正常查看到依賴關係圖了。

方式3,經過docker下載並運行,命令以下:

[root@01server ~]# docker run --env STORAGE_TYPE=elasticsearch --env ES_HOSTS=192.168.190.129:9200 openzipkin/zipkin-dependencies

Tips:

這個Zipkin Dependencies屬因而一個job,不是服務,即不會持續運行,而是每運行一次才分析數據。若想持續運行的話,須要本身寫個定時腳原本定時運行這個job

使用Elasticsearch時Zipkin Dependencies支持的環境變量:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

Zipkin Dependencies支持的其餘環境變量:

Zipkin Dependencies默認分析的是當天的數據,能夠經過以下命令讓Zipkin Dependencies分析指定日期的數據:
Spring Cloud Sleuth + Zipkin 實現服務追蹤

相關文章
相關標籤/搜索