spring-cloud-2x版本-SleuthZipkin分布式链路追踪

28次阅读

共计 7768 个字符,预计需要花费 20 分钟才能阅读完成。

前言

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

本文基于前两篇文章 eureka-server、eureka-client、eureka-ribbon 和 eureka-feign 的实现。
参考

  • eureka-server
  • eureka-client
  • eureka-ribbon
  • eureka-feign

概述

现实生产环境当中,随着业务的发展,系统规模是越来越大的,各个服务之间的调用也越来越复杂,通常一个由客户端发起的请求在后端系统中会经过 N 个不同服务的来产生结果,这样就会产生一个调用链路,每一条链路都有可能出现不通的错误或者是延迟,当出现错误或者延迟的情况下,追踪问题变的非常困难,所以 Spring cloud 为我们提供了 Sleuth 分布式链路追踪,能帮忙我们快速定位问题以及相应的监控。(我这里的 demo 模块也好多,过后需要整理下,不影响小伙伴们的学习)

1. Sleuth 简单使用

1.1 在相关工程中添加 Sleuth 依赖

在 eureka-client、eureka-ribbon、eureka-feign 工作中增加 Sleuth 依赖。

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

1.2 添加日志记录

在需要输入日志的地方增加日志打印。这里只简单例举 eureka-ribbon 工程中的 controller 日志。

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,查看控制台会输出,

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 帮忙我们生成的。

  • 第一个值: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 地址


<center><font color=red>《Srping Cloud 2.X 小白教程》目录 </font></center>

  • spring cloud 2.x 版本 Eureka Server 服务注册中心教程
  • spring cloud 2.x 版本 Eureka Client 服务提供者教程
  • spring cloud 2.x 版本 Ribbon 服务发现教程(内含集成 Hystrix 熔断机制)
  • spring cloud 2.x 版本 Feign 服务发现教程(内含集成 Hystrix 熔断机制)
  • spring cloud 2.x 版本 Zuul 路由网关教程
  • spring cloud 2.x 版本 config 分布式配置中心教程
  • spring cloud 2.x 版本 Hystrix Dashboard 断路器教程
  • spring cloud 2.x 版本 Gateway 路由网关教程
  • spring cloud 2.x 版本 Gateway 自定义过滤器教程
  • spring cloud 2.x 版本 Gateway 熔断、限流教程
  • spring cloud 2.x 版本 Gateway 动态路由教程
  • spring cloud 2.x 版本 Sleuth+Zipkin 分布式链路追踪

  • 写作不易,转载请注明出处,喜欢的小伙伴可以关注公众号查看更多喜欢的文章。
  • 联系方式:4272231@163.com

正文完
 0