spring cloud 2.x版本 Sleuth+Zipkin分佈式鏈路追蹤

前言

本文采用Spring cloud本文爲2.1.8RELEASE,version=Greenwich.SR3

本文基於前兩篇文章eureka-server、eureka-client、eureka-ribbon和eureka-feign的實現。
參考java

概述

現實生產環境當中,隨着業務的發展,系統規模是愈來愈大的,各個服務之間的調用也愈來愈複雜,一般一個由客戶端發起的請求在後端系統中會通過N個不一樣服務的來產生結果,這樣就會產生一個調用鏈路,每一條鏈路都有可能出現不通的錯誤或者是延遲,當出現錯誤或者延遲的狀況下,追蹤問題變的很是困難,因此Spring cloud爲咱們提供了Sleuth分佈式鏈路追蹤,能幫忙咱們快速定位問題以及相應的監控。(我這裏的demo模塊也好多,事後須要整理下,不影響小夥伴們的學習)web

1. Sleuth簡單使用

1.1 在相關工程中添加Sleuth依賴

在eureka-client、eureka-ribbon、eureka-feign工做中增長Sleuth依賴。spring

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

1.2 添加日誌記錄

在須要輸入日誌的地方增長日誌打印。這裏只簡單例舉eureka-ribbon工程中的controller日誌。json

package spring.cloud.demo.eurekaribbon.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import spring.cloud.demo.eurekaribbon.service.EurekaRibbonService;

/**
 * @auther: maomao
 * @DateT: 2019-09-17
 */
@RestController
@Slf4j
public class EurekaRibbonConntroller {

    @Autowired
    private EurekaRibbonService eurekaRibbonService;

    @RequestMapping("/sayHello")
    public String syaHello() {
        log.info("eureka-ribbon server......");
        String message = eurekaRibbonService.sayHello();
        log.info("[eureka-ribbon][EurekaRibbonConntroller][syaHello], message={}", message);
        return "ribbon result: " + message;
    }
}

1.3 啓動服務

準備工做已經完成,這時候咱們按順序啓動全部服務。而後咱們訪問http://localhost:8901/sayHello,查看控制檯會輸出,bootstrap

2019-11-06 19:48:48.058  INFO [eureka-ribbon,086a3ab9cf8d31a8,086a3ab9cf8d31a8,false] 59750 --- [nio-8901-exec-9] s.c.d.e.c.EurekaRibbonConntroller        : ribbon request, server=eureka-ribbon
調用 服務 eureka-client/info
服務 eureka-client/info 返回信息:http://eureka1.client.com:8801/info
調用 服務 eureka-client/info success
2019-11-06 19:48:48.351  INFO [eureka-ribbon,086a3ab9cf8d31a8,f06ab1e22c04430a,false] 59750 --- [ibbonService-10] s.c.d.e.service.EurekaRibbonService      : ribbon->EurekaRibbonService->sayHello->調用 服務 eureka-client/info 返回信息:message=http://eureka1.client.com:8801/info
2019-11-06 19:48:48.351  INFO [eureka-ribbon,086a3ab9cf8d31a8,086a3ab9cf8d31a8,false] 59750 --- [nio-8901-exec-9] s.c.d.e.c.EurekaRibbonConntroller        : ribbon request, server=eureka-ribbon, message=http://eureka1.client.com:8801/info

日誌說明:後端

咱們在控制檯中能夠查看到相似這樣的日誌:[eureka-ribbon,086a3ab9cf8d31a8,f06ab1e22c04430a,false],這些就是Sleuth幫忙咱們生成的。app

  • 第一個值:eureka-ribbon,表明咱們的應用名稱。
  • 第二個值:086a3ab9cf8d31a8,TraceID, 用來標識一條請求鏈路。
  • 第三個值:f06ab1e22c04430a,SpanID,用來標識一個基本的工做單元。
  • 第四個值:false,表示是否將該信息輸出到其餘日誌收集服務中,例如:Zipkin。

TraceID和SpanID關係:一個鏈路對應多個基本工做單元,也就是一個TraceID對應多個SpanID。分佈式

我這裏例舉的eureka-ribbon工程中的控制檯輸出的日誌內容,同理咱們能夠查看eureka-client工程的控制檯輸出,也會用相似的日誌輸出。

1.4 小結

至此,Spring cloud Sleuth分佈式鏈路追蹤就初步搭建完成,由此咱們能夠總結出,Sleuth的核心就是生成的TraceID和SpanID,一條鏈路的日誌信息是由TraceID串聯起來的。

2. 整合Logstash

有了日誌輸出還不夠,咱們還須要日誌收集,官方文檔使用的是Logstash,接下來咱們開始整和Logstash。

2.1 加入Logstash依賴

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>6.2</version>
</dependency>

這裏加入的是最新的logback依賴包,低版本的和Spring cloud 2.x版本不兼容。

2.2 增長logback-spring.xml

在eureka-client和eureka-ribbon中加入logback-spring.xml,這裏須要注意的是,logback-spring.xml加載在application.yml配置以前,因此要新建bootstrap.yml,這樣logback-spring.xml才能獲取到對應的應用名稱。

bootstrap.yml設置:

spring:
  application:
    name: eureka-ribbon
server:
  port: 8901

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    
    <springProperty scope="context" name="springAppName" source="spring.application.name"/>
    <!-- Example for logging into the build folder of your project -->
    <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/>​

    <!-- You can override this to have a custom pattern -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

    <!-- Appender to log to console -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- Minimum logging level to be presented in the console logs-->
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- Appender to log to file in a JSON format -->
    <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}.json</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        "severity": "%level",
                        "service": "${springAppName:-}",
                        "trace": "%X{X-B3-TraceId:-}",
                        "span": "%X{X-B3-SpanId:-}",
                        "parent": "%X{X-B3-ParentSpanId:-}",
                        "exportable": "%X{X-Span-Export:-}",
                        "pid": "${PID:-}",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "rest": "%message"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="console"/>
        <!-- uncomment this to have also JSON logs -->
        <appender-ref ref="logstash"/>
        <!--<appender-ref ref="flatfile"/>-->
    </root>
</configuration>

2.3 重啓相關服務

從新啓動相關服務,並訪問http://localhost:8901/sayHello,在相應的控制檯中能夠看到相似日誌,

2019-11-07 11:14:21.136  INFO [eureka-ribbon,0983491b6471be0f,48598b8942c2c814,false] 3288 --- [RibbonService-1] s.c.d.e.service.EurekaRibbonService      : ribbon->EurekaRibbonService->sayHello->調用 服務 eureka-client/info 返回信息:message=http://eureka1.client.com:8801/info
2019-11-07 11:14:21.139  INFO [eureka-ribbon,0983491b6471be0f,0983491b6471be0f,false] 3288 --- [nio-8901-exec-1] s.c.d.e.c.EurekaRibbonConntroller        : >>>traceId=null, spanId=null
2019-11-07 11:14:21.140  INFO [eureka-ribbon,0983491b6471be0f,0983491b6471be0f,false] 3288 --- [nio-8901-exec-1] s.c.d.e.c.EurekaRibbonConntroller        : [eureka-ribbon][EurekaRibbonConntroller][syaHello], message=http://eureka1.client.com:8801/info, traceId=0983491b6471be0f

日誌內容以前已經進行過詳細的說明,這裏就不在說明,這時咱們能夠在工程目錄外發現有一個build的目錄,咱們進入這個build目錄能夠看到已應用名稱開頭的.json文件,該文件就是logback-spring.xml中配置的logstash的appender輸出的日誌文件。

2.3 小結

logstash的日誌配置咱們就完成了,logstash除了能夠經過上面的方式生成json日誌文件以外,還可使用LogstashTcpSocketAppender將日誌內容直接輸出到logstash的服務端,這裏就不過多說明,感興趣的小夥伴能夠自行研究。

3 整合Zipkin

在Spring cloud D版本之後,zipkin-server是經過引入依賴的方式構建的,到了E版本以後,官方就是開始啓用了jar的形式來運行zipkin-server。因此咱們先到zipkin的官網下載最新的zipkin.jar。

3.1 修改要跟蹤的工程應用

在eureka-client、eureka-ribbon、spring-gateway增長相關依賴。

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

3.2 修改application.yml配置

在eureka-client、eureka-ribbon、spring-gateway應用的application.yml增長一下配置:

spring:
  sleuth:
    sampler:
      probability: 1  #採樣頻率
    web:
      enabled: true
    zipkin:
      base-url: http://localhost:9411/  #zipkin服務地址

3.3 啓動服務

啓動eureka-client、eureka-ribbon、spring-gateway應用服務。

zipkin啓動方式:java -jar zipkin.jar

運行zipkin.jar之後,我訪問http://localhost:9411/zipkin,這時候咱們能夠看到以下圖顯示:

而後咱們在訪問http://localhost:8100/ribbon/sayHello?token=xxx地址(這個地址的請求鏈路是spring-gateway:eureka-ribbion:eureka-client),而後咱們點擊zipkin的查詢按鈕,咱們能夠看到以下顯示:

而後能夠點擊單個鏈路信息查看詳細信息,以下圖顯示:

由這張圖就可查看到詳細鏈路追蹤信息。

3.4 小結

至此,整合zipkin就完成了,這種默認的方式是http收集,咱們還能夠採用消息中間件來收集日誌信息,感興趣的小夥伴能夠自行研究。

總結

本文重點講述了Spring Cloud經過Sleuth+Zipkin實現了服務的跟蹤,後續我會補充一篇結合ELK的日誌收集。經過這篇文章咱們也簡單的瞭解了鏈路追蹤的原理,就是經過traceId將整個過程串聯起來,而後經過spanID來計算各個環節的時間延遲。

代碼地址

gitHub地址


《Srping Cloud 2.X小白教程》目錄
相關文章
相關標籤/搜索