為什么需要Spring Cloud Sleuth
微服務(wù)架構(gòu)是一個(gè)分布式架構(gòu),它按業(yè)務(wù)劃分服務(wù)單元,一個(gè)分布式系統(tǒng)往往有很多個(gè)服務(wù)單元。
由于服務(wù)單元數(shù)量眾多,業(yè)務(wù)的復(fù)雜性,如果出現(xiàn)了錯(cuò)誤和異常,很難去定位。
主要體現(xiàn)在,一個(gè)請(qǐng)求可能需要調(diào)用很多個(gè)服務(wù),而內(nèi)部服務(wù)的調(diào)用復(fù)雜性,決定了問(wèn)題難以定位。
所以微服務(wù)架構(gòu)中,必須實(shí)現(xiàn)分布式鏈路追蹤,去跟進(jìn)一個(gè)請(qǐng)求到底有哪些服務(wù)參與,參與的順序又是怎樣的,從而達(dá)到每個(gè)請(qǐng)求的步驟清晰可見(jiàn),出了問(wèn)題,很快定位。
舉個(gè)例子,在微服務(wù)系統(tǒng)中,一個(gè)來(lái)自用戶(hù)的請(qǐng)求,請(qǐng)求先達(dá)到前端A(如前端界面),然后通過(guò)遠(yuǎn)程調(diào)用,達(dá)到系統(tǒng)的中間件B、C(如負(fù)載均衡、網(wǎng)關(guān)等),最后達(dá)到后端服務(wù)D、E,后端經(jīng)過(guò)一系列的業(yè)務(wù)邏輯計(jì)算最后將數(shù)據(jù)返回給用戶(hù)。對(duì)于這樣一個(gè)請(qǐng)求,經(jīng)歷了這么多個(gè)服務(wù),怎么樣將它的請(qǐng)求過(guò)程的數(shù)據(jù)記錄下來(lái)呢?這就需要用到服務(wù)鏈路追蹤。
基本術(shù)語(yǔ)
Spring Cloud Sleuth采用的是Google的開(kāi)源項(xiàng)目Dapper的專(zhuān)業(yè)術(shù)語(yǔ)。
Span:基本工作單元,發(fā)送一個(gè)遠(yuǎn)程調(diào)度任務(wù) 就會(huì)產(chǎn)生一個(gè)Span,Span是一個(gè)64位ID唯一標(biāo)識(shí)的,Trace是用另一個(gè)64位ID唯一標(biāo)識(shí)的,Span還有其他數(shù)據(jù)信息,比如摘要、時(shí)間戳事件、Span的ID、以及進(jìn)度ID。
Trace:一系列Span組成的一個(gè)樹(shù)狀結(jié)構(gòu)。請(qǐng)求一個(gè)微服務(wù)系統(tǒng)的API接口,這個(gè)API接口,需要調(diào)用多個(gè)微服務(wù),調(diào)用每個(gè)微服務(wù)都會(huì)產(chǎn)生一個(gè)新的Span,所有由這個(gè)請(qǐng)求產(chǎn)生的Span組成了這個(gè)Trace。
Annotation:用來(lái)及時(shí)記錄一個(gè)事件的,一些核心注解用來(lái)定義一個(gè)請(qǐng)求的開(kāi)始和結(jié)束 。這些注解包括以下:
1?? cs - Client Sent -客戶(hù)端發(fā)送一個(gè)請(qǐng)求,這個(gè)注解描述了這個(gè)Span的開(kāi)始
2?? sr - Server Received -服務(wù)端獲得請(qǐng)求并準(zhǔn)備開(kāi)始處理它,如果將其sr減去cs時(shí)間戳便可得到網(wǎng)絡(luò)傳輸?shù)臅r(shí)間。
3?? ss - Server Sent (服務(wù)端發(fā)送響應(yīng))–該注解表明請(qǐng)求處理的完成(當(dāng)請(qǐng)求返回客戶(hù)端),如果ss的時(shí)間戳減去sr時(shí)間戳,就可以得到服務(wù)器請(qǐng)求的時(shí)間。
4?? cr - Client Received (客戶(hù)端接收響應(yīng))-此時(shí)Span的結(jié)束,如果cr的時(shí)間戳減去cs時(shí)間戳便可以得到整個(gè)請(qǐng)求所消耗的時(shí)間。
案例實(shí)戰(zhàn)
本文案例一共四個(gè)工程采用多Module形式

目錄結(jié)構(gòu)
需要新建一個(gè)主Maven工程,主要指定了Spring Boot的版本為1.5.3,Spring Cloud版本為Dalston.RELEASE
1?? 包含了eureka-server工程,作為服務(wù)注冊(cè)中心 eureka-server的創(chuàng)建過(guò)程這里不重復(fù)
2?? zipkin-server作為鏈路追蹤服務(wù)中心,負(fù)責(zé)存儲(chǔ)鏈路數(shù)據(jù)
3?? gateway-service作為服務(wù)網(wǎng)關(guān)工程,負(fù)責(zé)請(qǐng)求的轉(zhuǎn)發(fā),同時(shí)它也作為鏈路追蹤客戶(hù)端,負(fù)責(zé)產(chǎn)生數(shù)據(jù),并上傳給zipkin-service
4?? user-service為一個(gè)應(yīng)用服務(wù),對(duì)外暴露API接口,同時(shí)它也作為鏈路追蹤客戶(hù)端,負(fù)責(zé)產(chǎn)生數(shù)據(jù)
主maven pom文件

構(gòu)建zipkin-server工程
目錄結(jié)構(gòu)

pom文件

配置文件

代碼

構(gòu)建user-service
目錄結(jié)構(gòu)

pom文件

代碼


配置文件

構(gòu)建gateway-service
目錄結(jié)構(gòu)

配置文件

代碼

pom文件

項(xiàng)目演示
依次啟動(dòng)eureka-server、zipkin-server、user-service、gateway-service
瀏覽器訪(fǎng)問(wèn) http://localhost:5000/user-api/user/hi

http://localhost:9411,即訪(fǎng)問(wèn)Zipkin的展示界面

這個(gè)界面主要用來(lái)查找服務(wù)的調(diào)用情況,可以根據(jù)服務(wù)名、開(kāi)始時(shí)間、結(jié)束時(shí)間、請(qǐng)求消耗的時(shí)間等條件來(lái)查找。點(diǎn)擊“Find Trackes”按鈕,界面如圖所示。從圖可知服務(wù)的調(diào)用情況,比如服務(wù)調(diào)用時(shí)間、服務(wù)的消耗時(shí)間,服務(wù)調(diào)用的鏈路情況。

點(diǎn)擊Dependences按鈕,可以查看服務(wù)的依賴(lài)關(guān)系,在本案例中,gateway-service將請(qǐng)求轉(zhuǎn)發(fā)到了user-service,它們的依賴(lài)關(guān)系如圖:

怎么在鏈路數(shù)據(jù)中添加自定義數(shù)據(jù)
需要在gateway-service上實(shí)現(xiàn)。建一個(gè)ZuulFilter過(guò)濾器,它的類(lèi)型為“post”,order為900,開(kāi)啟攔截。在攔截邏輯方法里,通過(guò)Tracer的addTag方法加上自定義的數(shù)據(jù),比如本案例中加入了鏈路的操作人。另外也可以在這個(gè)過(guò)濾器中獲取當(dāng)前鏈路的traceId信息,traceId作為鏈路數(shù)據(jù)的唯一標(biāo)識(shí),可以存儲(chǔ)在log日志中,方便后續(xù)查找。

使用spring-cloud-starter-stream-rabbit進(jìn)行鏈路通訊
在上述的案例中,最終gateway-service收集的數(shù)據(jù),是通過(guò)Http上傳給zip-server的,在Spring Cloud Sleuth中支持消息組件來(lái)通訊的
首先安裝rabbitmq
docker run -d --name myrabbitmq -p 5672:5672 -p 15672:15672 docker.io/rabbitmq:management

訪(fǎng)問(wèn) http://127.0.0.1:15672/#/

改造zipkin-server
pom改造

配置文件

啟動(dòng)類(lèi)

改造 Zipkin Client(包括gateway-service、user-service)




啟動(dòng)方式和訪(fǎng)問(wèn)方式如上
訪(fǎng)問(wèn)rabbitmq頁(yè)面
這樣,就將鏈路的上傳數(shù)據(jù)從Http改了為用消息代組件RabbitMQ。

將鏈路數(shù)據(jù)存儲(chǔ)在Mysql數(shù)據(jù)庫(kù)
在上述的例子中,Zipkin Server是將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,一旦程序重啟,之前的鏈路數(shù)據(jù)全部丟失,那么怎么將鏈路數(shù)據(jù)存儲(chǔ)起來(lái)呢?Zipkin支持Mysql、Elasticsearch、Cassandra存儲(chǔ)
改造 zipkin-server
pom 文件

``
備注:mysql-connector-java 依賴(lài)版本號(hào)要和數(shù)據(jù)庫(kù)保持一致
比如數(shù)據(jù)庫(kù)版本號(hào)是8.0.19 那么依賴(lài) mysql-connector-java的版本號(hào)也需要是8.0.19
``
配置文件

數(shù)據(jù)庫(kù)


啟動(dòng)服務(wù)、訪(fǎng)問(wèn)接口(同上)
查看數(shù)據(jù)庫(kù)記錄


將數(shù)據(jù)存儲(chǔ)在es中
使用Mysql存儲(chǔ)鏈路數(shù)據(jù),在并發(fā)高的情況下,顯然不合理,這時(shí)可以選擇使用ElasticSearch存儲(chǔ)。
安裝 ES、kibana
可參考我之前寫(xiě)的文章《ELK環(huán)境部署》
啟動(dòng) ES

啟動(dòng) Kibana

訪(fǎng)問(wèn) Kibana
1?? 查看本地IP ifconfig

2?? 訪(fǎng)問(wèn) http://172.16.2.197:5601
它默認(rèn)會(huì)向本地的9200端口的ElasticSearch讀取數(shù)據(jù),它默認(rèn)的端口為5601

在zipkin中配置 ES
添加依賴(lài)

配置

啟動(dòng)服務(wù) 訪(fǎng)問(wèn)接口 (同上)
啟動(dòng)zipkin報(bào)錯(cuò)
異常:IllegalStateException(Elasticsearch 2.x and 5.x are supported, was: 7.5.1)
原因 我安裝的ES版本太高7.5.1 需要安裝低版本的ES
查看es版本

版本說(shuō)明

換成這個(gè)版本啟動(dòng)不會(huì)報(bào)錯(cuò) 但還是使用不了ES 所以不要使用新版本的ES 因?yàn)閦ipkin還未做兼容

安裝好了ES 6.X或更低版本
訪(fǎng)問(wèn) kibana 添加index zipkin

在Kibana中查看鏈路數(shù)據(jù)和使用圖標(biāo)顯示數(shù)據(jù)
這里不在重復(fù)了 感興趣的童鞋可以看我之前寫(xiě)的ELK部署的文章有詳細(xì)的介紹
源碼資源
https://gitee.com/pingfanrenbiji/SpringCloudLearning.git
參考文獻(xiàn)
https://juejin.im/post/59872ba96fb9a03c400ea11c