spring cloud sleuth的使用,與ziplin整合及解決由於springboot版本(1.x和2.x)問題引入的zipkin版本bug

1.介紹

由於微服務很複雜,當服務多了之後,就需要有一個東西去記錄服務之間的調用,這樣可以快速定位問題,且最好能同時記錄服務之間的調用時長等信息,方便優化系統。spring cloud sleuth就有這樣的作用。我們稱這種技術叫做服務鏈路追蹤

2. sleuth

sleuth記錄服務鏈路主要是依靠日誌

2020-05-08 14:39:31.429  INFO [sleuth-track2,8f38aeed036ff375,21f05063bd635c35,false] 9236 --- [nio-8083-exec-1] c.t.c.s.controller.Controller            : hello track2

我在上面隨便打印了一條它追蹤日誌,它在打印日誌時,主要有這麼幾個組成部分:

第一個值:sleuth-track2,它記錄了應用的名稱,即spring.application.name

第二個值:8f38aeed036ff375,spring cloud sleuth生成的一個id,成爲trace Id,它用來標識一條請求鏈路,一條請求鏈路包含一個Track Id,多個Span Id。一條服務鏈路上的track id是相同的

第三個值:21f05063bd635c35,spring cloud sleuth生成的另外一個id,成爲span id,它表示一個基本的工作單元,比如發送一個http請求

第四個值:false ,表示是否要將該信息輸出到Zipkin等服務中來收集和展示

3. 整合Spring Cloud Sleuth

創建3個項目:服務註冊中心,sleuth-track1,sleuth-track2

服務註冊中心就不說了,大致思路就是sleuth-track1使用feign調用sleuth-track2,然後我們打印個日誌看下,服務之間的調用部分也不展示了

3.1 引入依賴

給sleuth-track1,sleuth-track2添加如下依賴即可

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

3.2 調用

調用sleuth-track1中的controller接口,然後該接口會使用feign調用sleuth-track2的接口,

注意:打印信息一定要使用log,不能用System.out.print,因爲sleuth是基於log日誌才操作的

3.3 結果

sleuth-track1:

2020-05-08 15:22:42.515  INFO [sleuth-track1,2c1215ce5b940d18,2c1215ce5b940d18,false] 14632 --- [nio-8082-exec-3] c.t.c.sleuthtack1.controller.Controller  : hello track1

sleuth-track2:

2020-05-08 15:22:42.553  INFO [sleuth-track2,2c1215ce5b940d18,2900b3e2e12a1326,false] 9236 --- [nio-8083-exec-6] c.t.c.s.controller.Controller            : hello track2

會發現他們的track id是相同的,span id是不同的

4. 追蹤原理

主要包括兩個關鍵點

  • 爲了實現請求追蹤,當請求發送到分佈式系統的入口時,服務追蹤框架即sleuth會爲該請求創建一個唯一的跟蹤標識,在分佈式系統內部流轉時,sleuth會始終保持該標識的唯一,知道返回給請求方。這個標識就是track id
  • 爲了統計各處理單元的事件延遲,當請求到達某個組件時或處理邏輯到達某個狀態時,也通過一個唯一標識來標記它的開始,具體過程以及結束。該標識就是span id,它具有開始和結束兩個節點,通過記錄開始span和結束span的時間戳,就能統計出該span的事件延遲,除了時間戳外,它還可以包含一些其他元數據,如事件名稱,請求信息等

在spring boot應用中,通過在工程中引入spring-cloud-starter-sleuth依賴後,它會自動爲當前應用構建各通信通道的追蹤機制

比如:

  • rabbitmq,kafka傳遞的請求(或其他任何spring cloud stream綁定器實現的消息中間件)
  • 通過zuul代理傳遞的請求
  • 通過RestTemplate發起的請求

實現追蹤就是在請求的請求頭上添加實現追蹤需要的重要信息。

5. 與Zipkin整合

zipkin分爲服務端和客戶端,zipkin server負責接受client傳過來的數據,然後進行數據的處理與展示

zipkin client就是發送數據的

這裏我們使用spring boot 1.5.8.RELEASE,spring cloud Dalston.SR4版本來寫項目,版本問題引發的bug會在下面說明

5.1 創建Zipkin Server

5.1.1 創建一個spring cloud 工程,並引入下列依賴:

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>

 

5.1.2  添加註解

在啓動類上添加註解@EnableZipkinServer

5.1.3 配置文件

server:
  port: 9411
spring:
  application:
    name: zipkin-server

5.1.4 啓動並訪問

啓動項目,並訪問http://localhost:9411/

5.2 zipkin client 

這個其實就是能產生追蹤日誌的客戶端,spring cloud 的項目基本上都算是zipkin client,比如我們上面創建的sleuth-track1和sleuth-track2。

5.2.1 添加依賴

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

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

5.2.2 配置文件

#指定zipkin服務器的url地址
spring:
  zipkin:
    base-url: http://localhost:9411

5.2.3 修改配置

在第2節的時候,其中有個屬性打印出來是false,該屬性是表示是否要將該信息輸出到Zipkin等服務中來收集和展示。

該屬性的作用是抽樣收集:理論上講我們收集的追蹤信息是越多越好,但是在高併發的分佈式系統中,大量的請求調用會產生海量的追蹤日誌信息,如果過多的收集這些信息,會對整個系統的性能造成一定影響。所以我們要指定抽樣收集

可通過配置來修改你的收集百分比:

spring.sleuth.sampler.percentage=0.1

默認值就是0.1,代表收集10%的請求追蹤信息。

當我們本地調試時,可以設置爲1,表示收集全部的追蹤信息

5.2.4 新增bootstrap.yml

要確保您的應用程序名稱在Zipkin中正確顯示,請在bootstrap.yml中設置spring.application.name屬性

5.2.5 啓動項目,請求,查看 zipkin server

6. zipkin server和client版本不同而引起的bug

我一開始使用的spring cloud 版本:Hoxton.SR3,springboot版本:2.2.6.RELEASE,通過父pom中進行版本管理的,zipkin server和zipkin client都是其子模塊。

zipkin server端:

當我引入zipkin-server和zipkin-autoconfigure-ui依賴時,pom文件直接報錯,說找不到依賴,我一開始以爲是沒有指定zipkin版本的問題(我看書上寫的也沒指定版本),所以我就引入了zipkin的當前最高的一個版本號,就沒有報錯了,

接着啓動,啓動報錯說是log框架太多了,導致啓動失敗,然後我查看了以下版本依賴,spring boot 默認使用的是log back,而zipkin默認使用的是log4j,然後我就在zipkin server的依賴中去除了它自己的日誌框架。

再次啓動,還是報錯,說是tomcat embed什麼玩意又不對了,然後搞了半天(主要是想降低tomcat版本,結果boot2.x降版本不好搞,會出問題),還是沒搞對,我就放棄了。

但是,終究還是要搞的,我就只能按照書上的版本試,重新創建了一個項目(之前我是通過maven的父pom來繼承的)降低springboot(1.5.22.RELEASE)和springcloud(Brixton.SR5)版本,再次引入zipkin的依賴,發現就算不寫版本號都沒啥問題了。

zipkin client 端:

注意我的zipkin client是繼承的父pom文件,依賴的高版本的springboot和spring cloud

zipkin-client是按官方文檔要求搞的:依賴的spring-cloud-starter-zipkin包,並進行正常配置。啓動沒有報錯,但是在zipkin client向zipkin server自動發送數據請求時,報錯了:大致就是說訪問/api/v2/spans接口時報404。我分析一下報錯原因:

zipkin server方面由於是沒有指定zipkin版本號(跟着spring boot 的版本走的),所以它自動導入的版本是io.zipkin.java:zipkin:1.28.0(注意這個serer項目的springboot版本是低於2的)

zipkin client方面:由於我這個項目跟着父pom走的,所以spring boot版本是大於2的,這樣導致了我在依賴的時候並不是像boot2以前的版本那樣去依賴spring-cloud-starter-sleuth和spring-cloud-sleuth-zipkin包來激活zipkin,而是通過spring-cloud-starter-zipkin依賴包來激活zipkin的。

而spring-cloud-starter-zipkin這個包它依賴的zipkin的版本是:io.zipkin.zipkin2:zipkin:2.19.3,仔細觀察下綠色的字的不同,會發現,zipkin server這個springboot2以前版本依賴的zipkin包相比於springboot2之後依賴的zipkin包少了個2,關鍵就在這裏了。

io.zipkin.java:zipkin:1.28.0因爲沒有2所以我們簡稱v1版本,io.zipkin.zipkin2:zipkin:2.19.3我們簡稱v2版本。

導入v1版本的zipkin後,通過項目啓動的mapping映射關係可以看出它裏面的api都是/api/v1。。。

導入v2版本的zipkin可以發現,它裏面的api是/api/v2。。。

所以結果就出來了,由於zipkin server依賴的zipkin和zipkin client依賴的zipkin 大版本是不一樣的,所以就出現了404的問題。

解決:

宗旨就是讓zipkin server和zipkin client的zipkin大版本要相同,要麼都是io.zipkin.java,要麼都是io.zipkin.zipkin2

如果你的項目是spring boot1.x  (<2):

  • 那麼你就照我上面寫的步驟去搞就行

如果你的項目是spring boot 2.x (>2):

  • zipkin server: 自己在本地搭建一個zipkin server,不使用java構建。類似redis,rabbitmq那樣在本地安裝即可。同時也要注意一下你下的zipkin安裝包的版本,一定要是大於2的,例如2.x.x (springboot 在2.0後就不推薦創建springboot項目啓動zipkin server了,推薦自己搭建zipkin server,因爲你會發現spring boot 2.0 之後,你在引入依賴時必須要指定zipkin-server的版本號,而自己指定版本號會出現非常多的問題)
  • zipkin client:需要引入spring-cloud-starter-zipkin依賴包,而不是spring-cloud-starter-sleuth和spring-cloud-sleuth-zipkin了,然後其他正常操作即可。

不要試圖通過降低zipkin client 端的spring-cloud-starter-sleuth和spring-cloud-sleuth-zipkin依賴包的版本來解決這個bug,因爲這些我都試過了,不起作用,會出現其他bug

 

注意spring cloud版本要和spring boot版本對應,否則會出現很多問題:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章