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})

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

在這裏插入圖片描述

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