sleuth + zipkin 链路追踪示例

Posted Ramelon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sleuth + zipkin 链路追踪示例相关的知识,希望对你有一定的参考价值。

ZipKin

简介

中文文档: https://www.bookstack.cn/read/dyingbleed-zipkin/326d459d6b9268be.md

文档2: ttps://www.springcloud.cc/spring-cloud-greenwich.html#_spring_cloud_sleuth

Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data.

Zipkin是一个分布式跟踪系统。 它帮助收集解决服务架构中的延迟问题所需的定时数据。 功能包括数据的收集和查找。

下载地址

https://repo1.maven.org/maven2/io/zipkin/zipkin-server/

运行

上一步下载对应的jar包,输入一下命令运行。

java -jar zipkin-server-2.14.1-exec.jar

打开http://localhost:9411/能看到页面即跑成功

注:如果不做持久化数据在内存中保存,具体如何持久化参考官方文档

Sleuth

依赖

<!--包含了sleuth+zipkin-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

提供者 cloud-provider-payment8001

@GetMapping("/payment/zipkin")
public String paymentZipkin()

    return "hi ,i'am paymentzipkin server fall back,welcome to my channel,O(∩_∩)O哈哈~";

# 添加的配置文件
spring:
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
    #采样率值介于 0 到 1 之间,1 则表示全部采集
    probability: 1

消费者 cloud-consumer-order80

@GetMapping("/consumer/payment/zipkin")
public String paymentZipkin()

    String result = restTemplate.getForObject("http://localhost:8001"+"/payment/zipkin/", String.class);
    return result;

# 添加的配置文件
spring:
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1

总结

再次访问:http://localhost:9411/即可以看到详细的链路追踪信息

Sleuth+Zipkin 实现 SpringCloud 链路追踪

一、前言

全链路监控:方案概述与比较 一文中,我们有详细介绍过分布式链路跟踪的实现理论基础。

我们看到上图,知道在微服务架构下,系统的功能是由大量的微服务协调组成的,例如:电商下单业务就需要订单服务、库存服务、支付服务、短信通知服务逐级调用才能完成。而每个服务可能是由不同的团队进行开发,部署在成百上千台服务器上。

如此复杂的消息传递过程,当系统发生故障的时候,我们就需要一种机制对故障点进行快速定位,确认到底是哪个服务出了问题,分布式链路追踪技术由此而生。
所谓的分布式链路追踪,就是运行时通过某种方式记录下服务之间的调用过程,在通过可视化的 UI 界面帮相关人员快速定位到故障点。分布式链路追踪,是微服务架构运维监控的底层基础设施,没有它,相关人员就像盲人摸象一样,根本无法了解服务间通信过程。

二、应用架构图

本文将会介绍如何在如何在 Spring Cloud 架构下基于 Sleuth+Zipkin 实现微服务链路追踪,主要演示HTTP 调用方式。

在具体介绍之前,我们先来看一下我们本文示例 Spring Cloud 集成 Zipkin 的应用架构,如下图所示:

从架构图中可以看到:所有的服务都注册到 Nacos 上;当客户端的请求到来之时,从 Nacos 中获取对应服务的信息,并将请求反向代理到指定的服务实例。

涉及的业务服务与组件包含以下 5 个:

  • Nacos,本地安装并启动;
  • Zipkin,本地安装并启动;
  • Spring Boot 服务A;
  • Spring Boot 服务B;
  • Spring Boot 服务C。

如果你对 Zipkin 还不熟悉,建议去看下我的这篇文章:快速了解分布式跟踪系统 Zipkin

三、快速了解 Sleuth

Sleuth 是 Spring Cloud 提供的服务治理模块,在其标准生态下内置了 Sleuth 这个组件。它通过扩展 Logging 日志的方式实现微服务的链路追踪。

在标准的微服务下日志产生的格式是:

2021-09-21 02:03:20.166  INFO [a-service,,,] 40327 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: b-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

但是当引入 Spring Cloud Sleuth 链路追踪组件后就会变成下面的格式:

2021-09-21 02:06:41.410  INFO [a-service,632f57c51af8c7a4,632f57c51af8c7a4,true] 40415 --- [nio-7000-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: b-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

⽇志输出格式是固定的,包含以下四部分:

 [appname,traceId,spanId,exportable]
  • appname,说明日志是由哪个微服务产生的。
  • TraceId,轨迹编号。一次完整的业务处理过程被称为轨迹,例如:实现登录功能需要从服务 A 调用服务 B,服务B再调用服务 C,那这一次登录处理的过程就是一个轨迹,从前端应用发来请求到接收到响应,每一次完整的业务功能处理过程都对应唯一的 TraceId。
  • SpanId,步骤编号。刚才要实现登录功能需要从服务 A 到服务 C 涉及 3 个微服务处理,按处理前后顺序,每一个微服务处理时日志都被赋予不同的 SpanId。一个 TraceId 拥有多个 SpanId,而 SpanId 只能隶属于某一个 TraceId。
  • 导出标识,当前这个日志是否被导出,该值为 true 的时候说明当前轨迹数据允许被其他链路追踪可视化服务收集展现。

我们模拟了服务 A -> B -> C 的调用链路,分别产生的日志如下:

2021-09-21 02:18:36.494 DEBUG [a-service,14aa6f21d700f377,14aa6f21d700f377,true] 40619 --- [nio-7000-exec-7] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2021-09-21 02:18:36.524 DEBUG [b-service,14aa6f21d700f377,828df12c1c851367,true] 40622 --- [nio-8000-exec-6] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2021-09-21 02:18:36.571 DEBUG [c-service,14aa6f21d700f377,ebd9892f8756801d,true] 40626 --- [nio-9000-exec-7] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8

可以发现,按调用时间先后顺序分别是 A 到 C 依次出现。因为是一次完整业务处理,TraceId 都是相同的,SpanId 却各不相同,这些日志都已经被 Sleuth 导出,正常被 ZipKin 收集展示。

Zipkin 是 推特的一个开源分布式链路跟踪系统,它能收集各个服务实例上的链路追踪数据并可视化展现。刚才 ABC 服务控制台产生的日志在 ZipKin 的 UI 界面中会以链路追踪图表的形式展现。

通过这个可视化 UI 可以非常直观的了解业务处理过程中服务间的依赖关系与处理时间、处理状态等信息,是故障分析的必要的工具。
说到这,想必大家已经对微服务链路追踪与 Sleuth+Zipkin 组合已经有了初步认识,下面咱们通过实例讲解如何在微服务架构中进行链路追踪改造。

这个过程分为两大部分:

  • 在服务中加入 Spring Cloud Sleuth 生成链路追踪日志;
  • 通过 ZipKin 收集链路最终日志,生产可视化UI。

四、准备工作

1、搭建 Zipkin 单机环境

这里我们使用 docker 快速启动 zipkin 演示实例。

#获取镜像
sudo docker pull openzipkin/zipkin

#运⾏镜像
sudo docker run -d  -p 9411:9411 --name zipkin openzipkin/zipkin

2、搭建 naocos 单机环境

这里我们使用 docker 快速启动 nacos 演示实例。

#获取镜像
sudo docker pull nacos/nacos-server

#运⾏镜像
sudo docker run -d -p 8848:8848 --env MODE=standalone  --name nacos  nacos/nacos-server

五、微服务整合 Sleuth

这里创建 a、b、c 三个微服务工程,代码调用关系如下:


这里 A -> B -> C 服务间通过 Fegin 实现远程调用。

1、创建 SpringBoot 工程

首先创建创建 A、B、C 三个 Spring Boot 工程。

A、B 服务 pom.xml 依赖如下:

        <!--Spring Web应用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Nacos 客户端 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--服务间通信组件OpenFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
        <!--添加Sleuth依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>


C服务 pom.xml 依赖如下:

				<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--添加Sleuth依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

因为调用关系是服务 A -> B -> C,所以在 A、B 两个服务中需要额外依赖 OpenFeign 实现服务间通信。

2、配置文件

然后,我们配置各服务的 application.yml,这三个配置文件除了服务名称与端口不同外,其他都一致。

server:
  port: 7000
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
  application:
    name: a-service
  sleuth:
    web: #Spring Cloud Sleuth 针对 Web 组件的配置项,例如说 SpringMVC
      enabled: true
logging:
  level:
    root: debug #为演示需要,开启debug级别日志

3、实现核心代码

首先实现服务 C 的控制器:

@RestController
public class SampleController 
    @GetMapping("/c")
    public String methodC()
        String result = " -> Service C";
        return result;
    


实现 methodC 方法产生响应字符串 “-> Service C”,方法映射地址 “/c”。

然后实现服务 B 的 CServiceFeignClient 通过 Feign 实现了 C 服务的通信客户端,方法名为 methodC。

@FeignClient("c-service")
public interface CServiceFeignClient 
    @GetMapping("/c")
    public String methodC();

控制器通过 methodB 方法调用 methodC 的同时为响应附加的字符串“-> Service B”,方法映射地址“/b”。

@Controller
public class SampleController 
    @Resource
    private CServiceFeignClient cService;
    @GetMapping("/b")
    @ResponseBody
    public String methodB()
        String result = cService.methodC();
        result = " -> Service B" + result;
        return result;
    

最后,我们然后实现服务 A 的 BServiceFeignClient 通过 Feign 实现了 B 服务的通信客户端,方法名为 methodB。

@FeignClient("b-service")
public interface BServiceFeignClient 
    @GetMapping("/b")
    public String methodB();

控制器通过 methodA 方法调用 methodB 的同时,成为响应附加的字符串“-> Service A”,方法映射地址“/a”。


@RestController
public class SampleController 
    @Resource
    private BServiceFeignClient bService;

    @GetMapping("/a")
    public String methodA()
        String result = bService.methodB();
        result = "-> Service A" + result;
        return result;
    

这样我们的核心链路已经实现了,接下来我们做个测试验证下。

使用 Postman 请求下服务 A 的接口。

可以看到 ABC 三个服务按前后顺序依次产生结果,但在日志包含任何链路追踪数据。

2021-09-21 02:18:36.494 DEBUG [a-service,14aa6f21d700f377,14aa6f21d700f377,true] 40619 --- [nio-7000-exec-7] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2021-09-21 02:18:36.524 DEBUG [b-service,14aa6f21d700f377,828df12c1c851367,true] 40622 --- [nio-8000-exec-6] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2021-09-21 02:18:36.571 DEBUG [c-service,14aa6f21d700f377,ebd9892f8756801d,true] 40626 --- [nio-9000-exec-7] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8

虽然链路日志已产生,但如果在生产环境靠人工统计链路日志显然不现实,我们还需要部署分布式链路跟踪系统 Zipkin 来简化这个过程。

六、集成 Zipkin

Zipkin 服务端部署非常简单,可以通过官网快速上手。前面我们已经通过 docker 部署了一个演示实例。

1、引入客户端

首先我们需要每个服务集成 Zipkin 的客户端。

        <!--Zipkin 客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

2、配置文件

然后,我们需要每个服务的 application.yml 配置 Zipkin 通信地址以及采样率。

server:
  port: 7000
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
  application:
    name: a-service
  sleuth:
    sampler: #采样器
      probability: 1.0 #采样率,采样率是采集Trace的比率,默认0.1
      rate: 10000 #每秒数据采集量,最多n条/秒Trace
    web: #Spring Cloud Sleuth 针对 Web 组件的配置项,例如说 SpringMVC
      enabled: true
  zipkin: #设置zipkin服务端地址
    base-url: http://127.0.0.1:9411
logging:
  level:
    root: debug #为演示需要

注意配置项:

  • spring.sleuth.sampler.probability 是指采样率,假设在过去的 1 秒服务产生了 10 个 Trace,如果采用默认采样率 0.1 则代表只有其中1条会被发送到 Zipkin 服务端进行分析整理,如果设为 1,则 10 条 Trace 都会被发送到服务端进行处理。
  • spring.sleuth.sampler.rate 指每秒最多采集量,说明每条最多允许采集多少条 Trace,超出部分将直接抛弃。

3、运行效果

服务都设置好后,启动应用,重新测试服务 A 接口,然后打开 Zipkin 服务端 UI 界面 http://localhost:9411,查看调用链路。

点击“Run Query”。

点击“show”,便会出现对应的链路调用图及详细的链路。

如果点击对应的“依赖”,还可以看到更详细的拓扑关系内容。


点击对应的服务节点,可以查看服务调用的统计信息。

如果我们主动停掉服务 C 呢,会是什么样的情况呢?

我们可以看到 Zipkin 已经在 error 里面提示故障原因了,说明服务 C 没有可用的实例导致处理失败。

七、小结

这一课时我们进行了案例实战,选择当前流行微服务框架 SpringCloud 作为示例,演示如何在微服务中集成 Sleuth + Zipkin,同时模拟了异常情况。

源码地址:

以上是关于sleuth + zipkin 链路追踪示例的主要内容,如果未能解决你的问题,请参考以下文章

Sleuth+Zipkin 实现 SpringCloud 链路追踪

Sleuth+Zipkin 实现 SpringCloud 链路追踪

Sleuth+Zipkin 服务链路追踪

Sleuth+Zipkin 服务链路追踪

链路追踪(zipkin+sleuth+kafka+mysql+ELK+filebeats)

SpringCloud H版 Sleuth+Zipkin 服务链路监控与追踪