Sleuth+Zipkin 实现 SpringCloud 链路追踪

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【8月更文挑战第9天】Sleuth+Zipkin 实现 SpringCloud 链路追踪

一、前言

在 [全链路监控:方案概述与比较]一文中,我们有详细介绍过分布式链路跟踪的实现理论基础。
image.png
我们看到上图,知道在微服务架构下,系统的功能是由大量的微服务协调组成的,例如:电商下单业务就需要订单服务、库存服务、支付服务、短信通知服务逐级调用才能完成。而每个服务可能是由不同的团队进行开发,部署在成百上千台服务器上。

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

二、应用架构图

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

在具体介绍之前,我们先来看一下我们本文示例 Spring Cloud 集成 Zipkin 的应用架构,如下图所示:
image.png
从架构图中可以看到:所有的服务都注册到 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 界面中会以链路追踪图表的形式展现。
image.png
通过这个可视化 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 三个微服务工程,代码调用关系如下:
image.png

image.png

image.png
这里 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 的接口。
image.png

可以看到 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”。
image.png
点击“show”,便会出现对应的链路调用图及详细的链路。
image.png
如果点击对应的“依赖”,还可以看到更详细的拓扑关系内容。
image.png

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

如果我们主动停掉服务 C 呢,会是什么样的情况呢?
image.png
我们可以看到 Zipkin 已经在 error 里面提示故障原因了,说明服务 C 没有可用的实例导致处理失败。

七、小结

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

源码地址:

相关实践学习
基于OpenTelemetry构建全链路追踪与监控
本实验将带领您快速上手可观测链路OpenTelemetry版,包括部署并接入多语言应用、体验TraceId自动注入至日志以实现调用链与日志的关联查询、以及切换调用链透传协议以满足全链路打通的需求。
分布式链路追踪Skywalking
Skywalking是一个基于分布式跟踪的应用程序性能监控系统,用于从服务和云原生等基础设施中收集、分析、聚合以及可视化数据,提供了一种简便的方式来清晰地观测分布式系统,具有分布式追踪、性能指标分析、应用和服务依赖分析等功能。 分布式追踪系统发展很快,种类繁多,给我们带来很大的方便。但在数据采集过程中,有时需要侵入用户代码,并且不同系统的 API 并不兼容,这就导致了如果希望切换追踪系统,往往会带来较大改动。OpenTracing为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范。OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。Skywalking基于OpenTracing规范开发,具有性能好,支持多语言探针,无侵入性等优势,可以帮助我们准确快速的定位到线上故障和性能瓶颈。 在本套课程中,我们将全面的讲解Skywalking相关的知识。从APM系统、分布式调用链等基础概念的学习加深对Skywalking的理解,从0开始搭建一套完整的Skywalking环境,学会对各类应用进行监控,学习Skywalking常用插件。Skywalking原理章节中,将会对Skywalking使用的agent探针技术进行深度剖析,除此之外还会对OpenTracing规范作整体上的介绍。通过对本套课程的学习,不止能学会如何使用Skywalking,还将对其底层原理和分布式架构有更深的理解。本课程由黑马程序员提供。
目录
相关文章
|
6月前
|
Dubbo Java 应用服务中间件
微服务框架(十六)Spring Boot及Dubbo zipkin 链路追踪组件埋点
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文第一部分为调用链、OpenTracing、Zipkin和Jeager的简述;第二部分为Spring Boot及Dubbo zipkin 链路追踪组件埋点
|
1月前
|
存储 数据可视化 Java
基于MicrometerTracing门面和Zipkin实现集成springcloud2023的服务追踪
Sleuth将会停止维护,Sleuth最新版本也只支持springboot2。作为替代可以使用MicrometerTracing在微服务中作为服务追踪的工具。
103 1
|
21天前
|
存储 NoSQL 关系型数据库
微服务Zipkin链路追踪原理,图解版,一文吃透!
本文重点讲解Zipkin链路追踪的原理与使用,帮助解决微服务架构下的服务响应延迟等问题,提升系统性能与稳定性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
微服务Zipkin链路追踪原理,图解版,一文吃透!
|
4月前
|
存储 监控 Java
zipkin 与 sleuth 实现链路追踪
zipkin 与 sleuth 实现链路追踪
71 0
|
5月前
|
存储 消息中间件 Java
【分布式链路追踪技术】sleuth+zipkin
【分布式链路追踪技术】sleuth+zipkin
75 2
|
存储 监控 Java
微服务技术系列教程(42)- SpringCloud -Sleuth与Zipkin服务链路
微服务技术系列教程(42)- SpringCloud -Sleuth与Zipkin服务链路
111 0
|
6月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
1012 0
|
消息中间件 Java API
微服务技术系列教程(43)- SpringCloud -Zipkin环境集成
微服务技术系列教程(43)- SpringCloud -Zipkin环境集成
93 0
|
数据可视化 Java Docker
Sleuth微服务链路追踪整合ELK和zipkin
Sleuth微服务链路追踪整合ELK和zipkin
303 0
|
3月前
|
存储 监控 开发者
分布式链路监控系统问题之系统拆分后链路追踪技术的问题如何解决
分布式链路监控系统问题之系统拆分后链路追踪技术的问题如何解决