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,还将对其底层原理和分布式架构有更深的理解。本课程由黑马程序员提供。
目录
相关文章
|
7月前
|
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 链路追踪组件埋点
|
2月前
|
存储 数据可视化 Java
基于MicrometerTracing门面和Zipkin实现集成springcloud2023的服务追踪
Sleuth将会停止维护,Sleuth最新版本也只支持springboot2。作为替代可以使用MicrometerTracing在微服务中作为服务追踪的工具。
158 1
|
5天前
|
Java 关系型数据库 Nacos
微服务SpringCloud链路追踪之Micrometer+Zipkin
SpringCloud+Openfeign远程调用,并用Mircrometer+Zipkin进行链路追踪
69 20
|
1月前
|
存储 NoSQL 关系型数据库
微服务Zipkin链路追踪原理,图解版,一文吃透!
本文重点讲解Zipkin链路追踪的原理与使用,帮助解决微服务架构下的服务响应延迟等问题,提升系统性能与稳定性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
微服务Zipkin链路追踪原理,图解版,一文吃透!
|
5月前
|
存储 监控 Java
zipkin 与 sleuth 实现链路追踪
zipkin 与 sleuth 实现链路追踪
84 0
|
6月前
|
存储 消息中间件 Java
【分布式链路追踪技术】sleuth+zipkin
【分布式链路追踪技术】sleuth+zipkin
84 2
|
7月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
1038 0
|
消息中间件 Java API
微服务技术系列教程(43)- SpringCloud -Zipkin环境集成
微服务技术系列教程(43)- SpringCloud -Zipkin环境集成
101 0
|
3月前
|
SpringCloudAlibaba API 开发者
新版-SpringCloud+SpringCloud Alibaba
新版-SpringCloud+SpringCloud Alibaba
|
3天前
|
SpringCloudAlibaba 负载均衡 Dubbo
【SpringCloud Alibaba系列】Dubbo高级特性篇
本章我们介绍Dubbo的常用高级特性,包括序列化、地址缓存、超时与重试机制、多版本、负载均衡。集群容错、服务降级等。
【SpringCloud Alibaba系列】Dubbo高级特性篇