1. 程式人生 > 實用技巧 >Feign 服務呼叫使用 Zipkin 鏈路追蹤

Feign 服務呼叫使用 Zipkin 鏈路追蹤

@

目錄

0、介紹

分散式微服務時代,方便了業務的快速增長和服務的穩定,但是系統出現問題後,面對同業務多服務排查起來令人頭大。這時候領導就想著整合分散式追蹤系統。Zipkin 是 Twitter 的一個開源專案,基於 Google Dapper 實現。可以使用它來收集各個伺服器上請求鏈路的跟蹤資料,並通過它提供的 REST API 介面來輔助我們查詢跟蹤資料以實現對分散式系統的監控程式,從而及時地發現系統中出現的延遲升高問題並找出系統性能瓶頸的根源。除了面向開發的 API 介面之外,它也提供了方便的 UI 元件幫助我們直觀的搜尋跟蹤資訊和分析請求鏈路明細,比如:可以查詢某段時間內各使用者請求的處理時間等。

1、環境準備

Zipkin 服務依賴環境

Centos 7
Mysql 8

Zipkin 客戶端專案版本

Springboot 2.2.5.RELEASE
Springcloudalibaba 2.2.1.RELEASE

2、Zipkin 服務安裝

2.1、Docker 安裝

#拉取映象
docker pull openzipkin/zipkin

#1、Web 連線方式啟動 
docker run --name zipkin-web -d -p 9411:9411 openzipkin/zipkin

#2、Rabbit 連線方式啟動 注意 RABBIT_ADDRESSES 的 Ip 要實際 Ip 
docker run -d --name zipkin-rabbitmq -p 9411:9411 -e RABBIT_ADDRESSES=192.168.1.105:5672 -e RABBIT_USER=guest -e RABBIT_PASSWORD=guest openzipkin/zipkin

#3、Rabbit 連線方式啟動,儲存介質由記憶體改為 Mysql (暫時有問題)
 docker run -d --name zipkin-rabbit-mysql -p 9411:9411 -e RABBIT_ADDRESSES=192.168.1.105:5672 -e RABBIT_USER=guest -e RABBIT_PASSWORD=guest -e STORAGE_TYPE=mysql -e MYSQL_HOST=192.168.1.105 -e MYSQL_TCP_PORT=13306 -e MYSQL_USER=root -e MYSQL_PASS=123456 -e MYSQL_DB=zipkin openzipkin/zipkin

2.2、Jar 安裝

官方說明 如果伺服器安裝了 JDK8 以及更高的,那麼 Jar 包方式啟動是最快的入門方式。

可以本地下載好 Jar 然後上傳伺服器再執行,也可以伺服器直接下載再執行

  1. 下載最新 Jar 包,地址
  2. 伺服器下載命令
curl -sSL https://zipkin.io/quickstart.sh | bash -s

Jar 服務啟動

#1、Web 連線方式啟動  
java -jar zipkin.jar

#2、Rabbit 連線方式啟動 
java -jar zipkin-server-2.23.1-exec.jar --zipkin.collector.rabbitmq.addresses=localhost
#後面的 --zipkin.collector.rabbitmq.addresses=localhost 就是 RabbitMQ 的配置,這是預設的,如果要自己指定的使用者名稱和密碼可以參考下面的啟動命令:
nohup java -jar zipkin-server-2.23.1-exec.jar > zipkin.log --zipkin.collector.rabbitmq.addresses=localhost:5672 --zipkin.collector.rabbitmq.username=guest --zipkin.collector.rabbitmq.password=guest 2>&1 &

#3、Rabbit 連線方式啟動,修改儲存介質,預設為記憶體,現在改為 Mysql,也可以使用 Elasticsearch 持久化
nohup java -jar zipkin-server-2.23.1-exec.jar > zipkin.log \
       --zipkin.collector.rabbitmq.addresses=localhost:5672 \
       --zipkin.collector.rabbitmq.username=guest \
       --zipkin.collector.rabbitmq.password=guest  \
       --zipkin.storage.type=mysql \
       --zipkin.storage.mysql.host=localhost \
       --zipkin.storage.mysql.port=3306 \
       --zipkin.storage.mysql.username=root \
       --zipkin.storage.mysql.password=root \
       --zipkin.storage.mysql.db=zipkin \
       2>&1 &

其他環境變數引數配置

屬性 環境變數 描述
zipkin.collector.rabbitmq.concurrency RABBIT_CONCURRENCY 併發消費者數量,預設為 1
zipkin.collector.rabbitmq.connection-timeout RABBIT_CONNECTION_TIMEOUT 建立連線時的超時時間,預設為 60000 毫秒,即 1 分鐘
zipkinzipkin.collector.rabbitmq.queue RABBIT_QUEUE 從中獲取 span 資訊的佇列,預設為 zipkin
zipkin.collector.rabbitmq.uri RABBIT_URI 符合 RabbitMQ URI 規範 的 URI,例如 amqp://user:pass@host:10000/vhost

如果設定了 URL,則以下屬性將被忽略

屬性 環境變數 描述
zipkin.collector.rabbitmq.addresses RABBIT_ADDRESSES 用逗號分隔的 RabbitMQ 地址列表,例如 localhost:5672,localhost:5673
zipkin.collector.rabbitmq.password RABBIT_PASSWORD 連線到 RabbitMQ 時使用的密碼,預設為 guest
zipkinzipkinzipkin.collector.rabbitmq.username RABBIT_USER 連線到 RabbitMQ 時使用的使用者名稱,預設為 guest
zipkin.collector.rabbitmq.virtual-host RABBIT_VIRTUAL_HOST 使用的 RabbitMQ virtual host,預設為 /
zipkin.collector.rabbitmq.use-ssl RABBIT_USE_SSL 設定為 true 則用 SSL 的方式與 RabbitMQ 建立連結

摘抄自 地址

注意: 儲存介質由預設的記憶體改為 Mysql,需要先建資料庫 Zipkin,然後匯入 zipkin 的預設庫,建完庫後執行如下內容即可

https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql

3、專案整合 zipkin

專案整合使用 2 模組來說明,模組名為 consumer 和 provider。主要以 Rabbit 連線方式來介紹,也會註釋說下 Web 的方式

3.1、模組工程分別引入 pom

<!-- 包含 Sleuth 和 Zipkin 依賴,看下圖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

<!-- 使用 Rabbit 連線方式啟動才需要下面依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

3.2、application.yml 新增配置

consumer

spring:
  zipkin:
#    base-url: http://192.168.1.105:9411 #Web 連線方式使用
    service:
      name: consumer
    sender:
#      type: web #Web 連線方式使用
      type: rabbit # 還有 activemq、kafka
  sleuth:
    sampler:
      probability: 1 #跟蹤資訊收集取樣比例,預設 0.1,為 1 即 100%,收集所有 注意之前的版本是 percentage 新版本中更換為 probability
#      rate: 50 # 每秒速率,即每秒最多能跟蹤的請求,rate 優先
    
  #Sleuth 使用 Rabbitmq 來向 Zipkin 傳送資料
  rabbitmq:
    host: 192.168.1.105
    port: 5672
    username: guest
    password: guest

provider

spring:
  zipkin:
#    base-url: http://192.168.1.105:9411 #Web 連線方式使用
    service:
      name: provider
    sender:
#      type: web #Web 連線方式使用
      type: rabbit # 還有 activemq、kafka
  sleuth:
    sampler:
      probability: 1 #跟蹤資訊收集取樣比例,預設 0.1,為 1 即 100%,收集所有 注意之前的版本是 percentage 新版本中更換為 probability
#      rate: 50 # 每秒速率,即每秒最多能跟蹤的請求,rate 優先
    
  #Sleuth 使用 Rabbitmq 來向 Zipkin 傳送資料
  rabbitmq:
    host: 192.168.1.105
    port: 5672
    username: guest
    password: guest

4、測試

4.1、啟動服務

分別啟動 consumer、provider,然後瀏覽器呼叫 consumer 的測試介面

http://localhost:8081/consumer1?name=1111

4.2、看日誌

#consumer
2021-01-03 13:18:48.647  INFO [consumer,dd07a4eaac415456,dd07a4eaac415456,true] 6556 --- [nio-8081-exec-8] cn.songo.controller.ConsumerController   : consumer111>>>>>>:port:8081,age:25

#provider
2021-01-03 13:18:48.652  INFO [provider,dd07a4eaac415456,75c232c4616558ce,true] 596 --- [io-18080-exec-6] cn.songo.controller.ProviderController   : send---->age:261,port:18080

來看下上面的日誌資訊,[consumer,dd07a4eaac415456,dd07a4eaac415456,true]
,含義為[專案名, TraceId(相同視為一請求), SpanId(每個服務節點唯一), 是否被 Zipkin 收錄]

這裡使用的是 Springboot 自帶的日誌框架 Logback,如果使用 Log4j2,則需要修改 Pattern 新增鏈路資訊,參考如下內容。

%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%logger{50}:%L] [%X{X-B3-TraceId},%X{X-B3-ParentSpanId},%X{X-B3-SpanId},%X{X-Span-Export}] - %msg%n

4.3、Zipkin UI 檢視

瀏覽器位址列訪問

http://192.168.1.105:9411


可以看出來一個請求鏈路順序為 consumer->provider,還可以看到呼叫花費的時間,到此就算配置成功了。

5、與 Seata 整合的衝突問題

5.1、問題詳情

spring-cloud-alibaba-seata 2.2.0.RELEASE
seata-spring-boot-starter 1.4.0

如果微服務中使用分散式事務 Seata,那整合 Zipkin 後, 就會出現問題服務呼叫服務失敗的問題如下

com.netflix.client.ClientException: Load balancer does not have available server for client:ip

主要原因是 pom 引入的 Zipkin 包含 Sleuth,而 Sleuth 的配置類 TraceFeignClientAutoConfiguration 和 Seata 的配置類 SeataFeignClientAutoConfiguration 都建立了 Bean:feignHystrixBuilder,衝突導致上面的錯誤。

5.2、問題解決

每個服務工程配置 Seata 攔截器類 SetSeataInterceptor ,以攔截器的方式傳遞 XID

import com.bpmaxx.common.utils.StringUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

/**
 * @Description: 解決 seata 與 zipkin 整合時因 SeataFeignClientAutoConfiguration 和 TraceFeignClientAutoConfiguration 都建立 Bean:feignHystrixBuilder 衝突問題
 */
@Component
@ConditionalOnClass({RequestInterceptor.class,GlobalTransactional.class})
public class SetSeataInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate request) {
        String xid = RootContext.getXID();
        if (StringUtils.isNotEmpty(xid)) {
            request.header(RootContext.KEY_XID, xid);
        }
    }
}

啟動類排除 SeataFeignClientAutoConfiguration.class

@SpringBootApplication(exclude = {SeataFeignClientAutoConfiguration.class})

記錄如有不對煩請指出,先行感謝