Spring Cloud Sleuth + Zipkin 實(shí)現(xiàn)服務(wù)追蹤

1. 什么是調(diào)用鏈

一個(gè)業(yè)務(wù)功能可能需要多個(gè)服務(wù)協(xié)作才能實(shí)現(xiàn),一個(gè)請(qǐng)求到達(dá)服務(wù)A,服務(wù)A需要依賴服務(wù)B,服務(wù)B又依賴服務(wù)C,甚至C仍需依賴其他服務(wù),形成一個(gè)調(diào)用鏈條,即調(diào)用鏈。

2. 為什么要監(jiān)控調(diào)用鏈

image

上圖傳遞了一個(gè)信息,就是微服務(wù)的復(fù)雜性

  • 出現(xiàn)問題后,定位困難,需要對(duì)整個(gè)調(diào)用鏈路有個(gè)完善的監(jiān)控
  • 鏈路復(fù)雜,需要清晰的鏈路圖譜反映服務(wù)之間的依賴、調(diào)用關(guān)系
  • 整體系統(tǒng)性能及運(yùn)行情況,需要明確的體現(xiàn),才能根據(jù)實(shí)際情況調(diào)整資源

3. 要監(jiān)控哪些方面

  • 圖形化展示整個(gè)調(diào)用鏈路
  • 系統(tǒng)的性能指標(biāo)
  • 健康狀況
  • 基礎(chǔ)告警

4. 調(diào)用鏈監(jiān)控的基礎(chǔ)原理

在介紹調(diào)用鏈監(jiān)控工具之前,我們首先需要知道在微服務(wù)架構(gòu)系統(tǒng)中經(jīng)常會(huì)遇到兩個(gè)問題:

  • 跨微服務(wù)的API調(diào)用發(fā)生異常,要求快速定位(比如5分鐘以內(nèi))出問題出在哪里,該怎么辦?
  • 跨微服務(wù)的API調(diào)用發(fā)生性 能瓶頸,要求迅速定位(比如5分鐘以內(nèi))出系統(tǒng)瓶頸,該怎么辦?

一般來說要解決這兩個(gè)問題或者與之類似的問題,就需要用到調(diào)用鏈監(jiān)控工具。那么調(diào)用鏈監(jiān)控工具是怎么實(shí)現(xiàn)問題的快速定位的呢?這就需要我們理解調(diào)用鏈監(jiān)控的基礎(chǔ)實(shí)現(xiàn)原理,我們來看一張圖:

image

圖中有兩個(gè)微服務(wù)分別是內(nèi)容中心和用戶中心,其中內(nèi)容中心的/shares/1接口會(huì)調(diào)用用戶中心的/users/1接口,這里就產(chǎn)生了一個(gè)調(diào)用鏈。我們可以將調(diào)用的過程分為四個(gè)階段或者說狀態(tài),當(dāng)內(nèi)容中心發(fā)送調(diào)用請(qǐng)求時(shí)處于“client send”狀態(tài),用戶中心接收到調(diào)用請(qǐng)求時(shí)處于“server receive”狀態(tài),用戶中心處理完請(qǐng)求并返回結(jié)果時(shí)處于“server send”狀態(tài),最后內(nèi)容中心接收到響應(yīng)結(jié)果時(shí)處于“client receive”狀態(tài)。

假設(shè),調(diào)用鏈流轉(zhuǎn)每個(gè)狀態(tài)時(shí)都會(huì)向一張數(shù)據(jù)表里插入一些數(shù)據(jù),如下圖所示:

image

表字段說明:

  • id:自增id
  • span_id:唯一id
  • pspan_id:父級(jí)span_id
  • service_name:服務(wù)名稱
  • api:api路徑
  • stage:階段/狀態(tài)
  • timestamp:插入數(shù)據(jù)時(shí)的時(shí)間戳

這是一張典型的自表一對(duì)多的表結(jié)構(gòu),根據(jù)這張表的數(shù)據(jù),就可以實(shí)現(xiàn)對(duì)以上所提到的兩個(gè)問題進(jìn)行快速定位。首先對(duì)于第一個(gè)問題,可以通過查詢表內(nèi)的數(shù)據(jù)行數(shù),判斷調(diào)用鏈在哪個(gè)階段中斷了。例如表中只有uuid1和uuid2兩條數(shù)據(jù),就可以判斷出是user-center的接口出現(xiàn)了問題,沒有正常返回結(jié)果。再如表中只有uuid1、uuid2及uuid3這三條數(shù)據(jù),就可以判斷出content-center沒有正常接收到user-center返回的結(jié)果,以此類推。如此一來,就可以通過表中的數(shù)據(jù)快速定位出跨微服務(wù)的API調(diào)用是在哪個(gè)階段發(fā)生了異常。

對(duì)于第二個(gè)問題,可以通過計(jì)算timestamp分析哪個(gè)調(diào)用比較耗時(shí)。例如上圖中的t2 - t1可以得出請(qǐng)求的發(fā)送到請(qǐng)求的接收所消耗的時(shí)間,再如t3 - t2可以得出/users/1這個(gè)接口的調(diào)用耗時(shí),而t4 - t1則可以得出整個(gè)調(diào)用鏈的耗時(shí),以此類推。所以當(dāng)跨微服務(wù)的API調(diào)用發(fā)生性能瓶頸時(shí),就可以通過分析各個(gè)調(diào)用接口的耗時(shí),快速定位出是哪個(gè)微服務(wù)接口拖慢了整個(gè)調(diào)用鏈耗時(shí)。

以上舉例簡(jiǎn)述了實(shí)現(xiàn)調(diào)用鏈監(jiān)控的基礎(chǔ)原理,雖然未必所有的調(diào)用鏈監(jiān)控工具都是這么實(shí)現(xiàn)的,但基本都異曲同工,或在其之上進(jìn)行了一些拓展。所以只要理解了這一部分,在學(xué)習(xí)各種調(diào)用鏈監(jiān)控工具時(shí)就會(huì)比較快上手。


5. Spring Cloud Sleuth簡(jiǎn)介

Spring Cloud Sleuth實(shí)現(xiàn)了一種分布式的服務(wù)鏈路跟蹤解決方案,通過使用Sleuth可以讓我們快速定位某個(gè)服務(wù)的問題。簡(jiǎn)單來說,Sleuth相當(dāng)于調(diào)用鏈監(jiān)控工具的客戶端,集成在各個(gè)微服務(wù)上,負(fù)責(zé)產(chǎn)生調(diào)用鏈監(jiān)控?cái)?shù)據(jù)。

官方文檔地址如下:

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

一些概念:

  1. Span(跨度):Span是基本的工作單元。Span包括一個(gè)64位的唯一ID,一個(gè)64位trace碼,描述信息,時(shí)間戳事件,key-value 注解(tags),span處理者的ID(通常為IP)。
    最開始的初始Span稱為根span,此span中span id和 trace id值相同。

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

  3. Annotation(標(biāo)注):用于及時(shí)記錄存在的事件。常用的Annotation如下:

    • CS(Client Sent 客戶端發(fā)送):客戶端發(fā)送一個(gè)請(qǐng)求,表示span的開始
    • SR(Server Received 服務(wù)端接收):服務(wù)端接收請(qǐng)求并開始處理它。(SR - CS)等于網(wǎng)絡(luò)的延遲
    • SS(Server Sent 服務(wù)端發(fā)送):服務(wù)端處理請(qǐng)求完成,開始返回結(jié)束給服務(wù)端。(SR - SS)表示服務(wù)端處理請(qǐng)求的時(shí)間
    • CR(Client Received 客戶端接收):客戶端完成接受返回結(jié)果,此時(shí)span結(jié)束。(CR - CS)表示客戶端接收服務(wù)端數(shù)據(jù)的時(shí)間

如果一個(gè)服務(wù)的調(diào)用關(guān)系如下:

image

那么此時(shí)將Span和Trace在一個(gè)系統(tǒng)中使用Zipkin注解的過程圖形化如下:

image

每個(gè)顏色的表明一個(gè)span(總計(jì)7個(gè)spans,從A到G),每個(gè)span有類似的信息

Trace Id = X
Span Id = D
Client Sent

此span表示span的Trance Id是X,Span Id是D,同時(shí)它發(fā)送一個(gè)Client Sent事件

spans 的parent/child關(guān)系圖形化如下:

image

6. 整合Spring Cloud Sleuth

了解完基本的一些概念后,我們來在訂單服務(wù)和商品服務(wù)中,集成spring cloud sleuth以及zipkin。在兩個(gè)服務(wù)的pom.xml文件中,增加如下依賴:

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

為了更詳細(xì)的查看服務(wù)通信時(shí)的日志信息,我們可以將Feign和Sleuth的日志級(jí)別設(shè)置為debug。在兩個(gè)項(xiàng)目的配置文件中,加入如下內(nèi)容即可:

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

啟動(dòng)訂單、商品服務(wù)項(xiàng)目,然后訪問創(chuàng)建訂單的接口,訂單服務(wù)的控制臺(tái)會(huì)輸出一段這樣的信息:

[order,6c8ecdeefb0fc723,cc4109a6e8e56d1c,false]

商品服務(wù)的控制臺(tái)也會(huì)輸出類似的信息,如下:

[product,6c8ecdeefb0fc723,40cdc34e745d59e7,false]

說明:

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

7. Zipkin搭建與整合

通過Sleuth產(chǎn)生的調(diào)用鏈監(jiān)控信息,讓我們可以得知微服務(wù)之間的調(diào)用鏈路,但是監(jiān)控信息只輸出到控制臺(tái)始終不太方便查看。所以我們需要一個(gè)圖形化的工具,這時(shí)候就輪到zipkin出場(chǎng)了。

Zipkin是一款開源的分布式實(shí)時(shí)數(shù)據(jù)追蹤系統(tǒng)(Distributed Tracking System),基于 Google Dapper的論文設(shè)計(jì)而來,由 Twitter 公司開發(fā)貢獻(xiàn)。其主要功能是聚集來自各個(gè)異構(gòu)系統(tǒng)的實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)。分布式跟蹤系統(tǒng)還有其他比較成熟的實(shí)現(xiàn),例如:Naver的Pinpoint、Apache的HTrace、阿里的鷹眼Tracing、京東的Hydra、新浪的Watchman,美團(tuán)點(diǎn)評(píng)的CAT,skywalking等。

zipkin官網(wǎng)地址如下:

https://zipkin.io/

ZipKin可以分為兩部分,一部分是zipkin server,用來作為數(shù)據(jù)的采集存儲(chǔ)、數(shù)據(jù)分析與展示;zipkin client是zipkin基于不同的語(yǔ)言及框架封裝的一些列客戶端工具,這些工具完成了追蹤數(shù)據(jù)的生成與上報(bào)功能,架構(gòu)如下:

image

Zipkin Server主要包括四個(gè)模塊:
(1)Collector 接收或收集各應(yīng)用傳輸?shù)臄?shù)據(jù)
(2)Storage 存儲(chǔ)接受或收集過來的數(shù)據(jù),當(dāng)前支持Memory,MySQL,Cassandra,ElasticSearch等,默認(rèn)存儲(chǔ)在內(nèi)存中。
(3)API(Query) 負(fù)責(zé)查詢Storage中存儲(chǔ)的數(shù)據(jù),提供簡(jiǎn)單的JSON API獲取數(shù)據(jù),主要提供給web UI使用
(4)Web 提供簡(jiǎn)單的web界面

ZipKin幾個(gè)概念
在追蹤日志中,有幾個(gè)基本概念spanId、traceId、parentId

  • traceId:用來確定一個(gè)追蹤鏈的16字符長(zhǎng)度的字符串,在某個(gè)追蹤鏈中保持不變。
  • spanId:區(qū)域Id,在一個(gè)追蹤鏈中spanId可能存在多個(gè),每個(gè)spanId用于表明在某個(gè)服務(wù)中的身份,也是16字符長(zhǎng)度的字符串。
  • parentId:在跨服務(wù)調(diào)用者的spanId會(huì)傳遞給被調(diào)用者,被調(diào)用者會(huì)將調(diào)用者的spanId作為自己的parentId,然后自己再生成spanId。

如下圖:
剛發(fā)起調(diào)用時(shí)traceId和spanId是一致,parentId不存在。

image

被調(diào)用者的traceId和調(diào)用者的traceId時(shí)一致的,被調(diào)用者會(huì)產(chǎn)生自己的spanId,并且被調(diào)用者的parentId是調(diào)用者的spanId

image

接下來我們搭建一個(gè)zipkin服務(wù)器。

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

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

下載下來的文件名為 zipkin.jar
方式2,到Maven中央倉(cāng)庫(kù)下載,使用瀏覽器訪問如下地址即可:

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

下載下來的文件名為 zipkin-server-{版本號(hào)}-exec.jar

由于Zipkin實(shí)際是一個(gè)Spring Boot項(xiàng)目,所以使用以上兩種方式下載的jar包,可以直接使用如下命令啟動(dòng):

java jar {zipkin jar包路徑}

方式3,通過docker安裝,命令如下:

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

安裝好后,使用瀏覽器訪問9411端口,主頁(yè)面如下所示:

image

然后在訂單服務(wù)中將之前的sleuth依賴替換成如下依賴:

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

在配置文件中,增加zipkin相關(guān)的配置項(xiàng)。如下:

spring:
  ...
  zipkin:
    base-url: http://127.0.0.1:9411/  # zipkin服務(wù)器的地址
    # 關(guān)閉服務(wù)發(fā)現(xiàn),否則Spring Cloud會(huì)把zipkin的url當(dāng)做服務(wù)名稱       
    discoveryClientEnabled: false   
    sender:
      type: web  # 設(shè)置使用http的方式傳輸數(shù)據(jù)
  sleuth:
    sampler:
      probability: 1  # 設(shè)置抽樣采集率為100%,默認(rèn)為0.1,即10%      

配置好后重啟項(xiàng)目,并訪問創(chuàng)建訂單接口。下單成功后,到zipkin頁(yè)面上就可以查看到order服務(wù)的鏈路信息了:

image

會(huì)有紅色的信息表示有錯(cuò)誤,點(diǎn)擊上圖中的紅色信息后,可以進(jìn)入到服務(wù)鏈路的查看頁(yè)面,在這里可以看到整條服務(wù)鏈路,并且可以看到每一個(gè)服務(wù)調(diào)用的耗時(shí),也可以看到是哪一步調(diào)用發(fā)生了錯(cuò)誤:

image

點(diǎn)擊每一行信息都可以查看其詳情信息,例如我點(diǎn)擊耗時(shí)46.236ms的那行信息,其詳細(xì)信息如下:

image

8. Zipkin數(shù)據(jù)持久化

Zipkin默認(rèn)是將監(jiān)控?cái)?shù)據(jù)存儲(chǔ)在內(nèi)存的,如果Zipkin掛掉或重啟的話,那么監(jiān)控?cái)?shù)據(jù)就會(huì)丟失。所以如果想要搭建生產(chǎn)可用的Zipkin,就需要實(shí)現(xiàn)監(jiān)控?cái)?shù)據(jù)的持久化。而想要實(shí)現(xiàn)數(shù)據(jù)持久化,自然就是得將數(shù)據(jù)存儲(chǔ)至數(shù)據(jù)庫(kù)。好在Zipkin支持將數(shù)據(jù)存儲(chǔ)至:

  • 內(nèi)存(默認(rèn))
  • MySQL
  • Elasticsearch
  • Cassandra
    Zipkin數(shù)據(jù)持久化相關(guān)的官方文檔地址如下:

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

Zipkin支持的這幾種存儲(chǔ)方式中,內(nèi)存顯然是不適用于生產(chǎn)的,這一點(diǎn)開始也說了。而使用MySQL的話,當(dāng)數(shù)據(jù)量大時(shí),查詢較為緩慢,也不建議使用。Twitter官方使用的是Cassandra作為Zipkin的存儲(chǔ)數(shù)據(jù)庫(kù),但國(guó)內(nèi)大規(guī)模用Cassandra的公司較少,而且Cassandra相關(guān)文檔也不多。

綜上,故采用Elasticsearch是個(gè)比較好的選擇,關(guān)于使用Elasticsearch作為Zipkin的存儲(chǔ)數(shù)據(jù)庫(kù)的官方文檔如下:

既然選擇Elasticsearch作為Zipkin的存儲(chǔ)數(shù)據(jù)庫(kù),那么自然首先需要搭建一個(gè)Elasticsearch服務(wù),單節(jié)點(diǎn)搭建比較簡(jiǎn)單,直接到官網(wǎng)下載壓縮包,然后使用如下命令解壓并啟動(dòng)即可(關(guān)于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  # 啟動(dòng)

由于Elasticsearch不是本文的重點(diǎn),這里不做不多的介紹,關(guān)于Elasticsearch的集群搭建可以參考如下文章:

搭建好Elasticsearch后,使用如下命令啟動(dòng)Zipkin,Zipkin就會(huì)切換存儲(chǔ)類型為Elasticsearch,然后根據(jù)指定的連接地址連接Elasticsearch并存儲(chǔ)數(shù)據(jù):

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

Tips:

  • 其中,STORAGE_TYPEES_HOSTS是環(huán)境變量,STORAGE_TYPE用于指定Zipkin的存儲(chǔ)類型是啥;而ES_HOSTS 則用于指定Elasticsearch地址列表,有多個(gè)節(jié)點(diǎn)時(shí)使用逗號(hào)( , )分隔。
    除此之外,還可以指定其他環(huán)境變量,參考下表:

    image

關(guān)于其他環(huán)境變量,可參考官方文檔:

最后可以根據(jù)以下測(cè)試步驟,自行測(cè)試一下Zipkin是否能正常將監(jiān)控?cái)?shù)據(jù)持久化存儲(chǔ):

  1. 往Zipkin中存儲(chǔ)一些數(shù)據(jù)
  2. 停止Zipkin
  3. 再次啟動(dòng)Zipkin,查看之前存儲(chǔ)的數(shù)據(jù)是否存在,如果存在說明數(shù)據(jù)已被持久化

關(guān)于依賴關(guān)系圖的問題

在上一小節(jié)中,簡(jiǎn)單介紹了Zipkin的數(shù)據(jù)持久化,并整合了Elasticsearch作為Zipkin的存儲(chǔ)數(shù)據(jù)庫(kù)。但此時(shí)會(huì)有一個(gè)問題,就是Zipkin在整合Elasticsearch后會(huì)無(wú)法分析服務(wù)之間的依賴關(guān)系圖,因?yàn)榇藭r(shí)數(shù)據(jù)都存儲(chǔ)到Elasticsearch中了,無(wú)法再像之前那樣在內(nèi)存中進(jìn)行分析。

想要解決這個(gè)問題,需要下載并使用Zipkin的一個(gè)子項(xiàng)目:

方式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中央倉(cāng)庫(kù)下載,使用瀏覽器訪問如下地址即可:

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

下載下來的文件名為 zipkin-dependencies-{版本號(hào)}.jar

下載好后,使用如下命令運(yùn)行這個(gè)jar包即可分析Elasticsearch中存儲(chǔ)的數(shù)據(jù):

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

該jar包運(yùn)行結(jié)束后,到Zipkin的界面上點(diǎn)開“Dependencies”就可以正常查看到依賴關(guān)系圖了。

方式3,通過docker下載并運(yùn)行,命令如下:

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

Tips:

這個(gè)Zipkin Dependencies屬于是一個(gè)job,不是服務(wù),即不會(huì)持續(xù)運(yùn)行,而是每運(yùn)行一次才分析數(shù)據(jù)。若想持續(xù)運(yùn)行的話,需要自己寫個(gè)定時(shí)腳本來定時(shí)運(yùn)行這個(gè)job

使用Elasticsearch時(shí)Zipkin Dependencies支持的環(huán)境變量:

image

Zipkin Dependencies支持的其他環(huán)境變量:

Zipkin Dependencies默認(rèn)分析的是當(dāng)天的數(shù)據(jù),可以通過如下命令讓Zipkin Dependencies分析指定日期的數(shù)據(jù):

image

參考原文:https://blog.51cto.com/zero01/2173394

鏈接:http://www.itdecent.cn/p/622a7924f2e3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容