分布式进阶-链路追踪SpringCloudSleuth、Zipkin【实战篇】

一、前言

我们在使用微服务的时候,往往设计到各个微服务之间的调用,肯定会存在深度的调用链路,如果出现BUG或者异常,就会让问题定位和处理效率非常低。
有了Sleuth ,就可以帮助我们记录、跟踪应用程序中的请求和操作。
通常与 Zipkin 配合使用,从而提供更全面的可视化应用程序跟踪和分析功能。

就像ElasticSearch和Kibana一样!

复杂的链路调用如下图所示:

在这里插入图片描述

在继续往下看的同时,需要你具备Springboot整合Nacos构建一个聚合项目的能力。

当然如果不想自己来,小编也给大家准备好了。大家可以下载运行一下,开始下面的实战!

防止Github访问不了,这里把代码提交到了Gitee。

cloud-sleuth-zipkin-demo代码下载地址

二、Spring Cloud Sleuth 介绍

1. 简介

Spring Cloud Sleuth 是 Spring Cloud 生态系统的一部分,它是一个分布式追踪解决方案,用于监视微服务架构中的请求流程,并帮助开发者跟踪请求在不同微服务之间的传播路径。

Sleuth主要用于解决微服务架构中的分布式系统跟踪和调试问题。

官网文档

2. 核心概念

我们可以看一下官网的图片:

简单名词介绍:

cs客户端发送,客户已提出请求。该注释指示跨度的开始。
sr服务器已接收,服务器端收到请求并开始处理。从此时间戳中减去cs时间戳即可得出网络延迟。
ss服务器发送,在请求处理完成时(当响应发送回客户端时)进行注释。从这个时间戳中减去sr时间戳就可以得出服务器端处理请求所需的时间。
cr客户端已收到,表示跨度的结束。客户端已成功收到服务器端的响应。从此时间戳中减去cs时间戳即可得出客户端从服务器接收响应所需的整个时间。

在这里插入图片描述

详细信息可以看官网介绍,总结一下:

名词翻译解释
Trace追踪Trace 是一个请求的整体追踪。它代表了从请求的起始点到结束点的完整路径,经过多个微服务。每个 Trace 都有一个唯一的 Trace ID。
Span跨度Span 是 Trace 中的一个小段,它代表了请求在某个特定微服务上的处理过程。Spans 之间有父子关系,它们可以形成一个层次结构,以表示请求的处理路径。
Trace ID追踪标识Trace ID 是唯一标识一个 Trace 的标识符。它在整个 Trace 中保持不变,用于将不同的 Span 关联到同一个 Trace 上。
Span ID跨度标识Span ID 是唯一标识一个 Span 的标识符。它用于在不同 Span 之间建立父子关系。
Parent Span ID父 Span 标识父 Span ID 是标识一个 Span 的父 Span 的标识符。它用于建立 Span 之间的关系。
Annotations注解Annotations 是关于 Span 的额外信息,通常用于记录 Span 的开始和结束时间、操作名称、以及其他相关信息。Annotations 可以帮助你更好地理解请求的处理过程。
Binary Annotations二进制注解Binary Annotations 是键值对形式的信息,用于记录与 Span 相关的自定义信息,例如请求的状态、错误信息等。
Collector收集器Collector 是用于收集追踪信息的组件,它将追踪数据发送到后端存储或可视化工具(如Zipkin或Jaeger)。Collector 可以将 Span 数据持久化,以供分析和监视使用。
Sampler采样器Sampler 用于确定是否对一个请求进行追踪。它决定是否为请求创建一个 Trace。Sampler 可以根据策略决定是否记录某个请求的 Trace 数据,以避免记录过多的追踪信息,从而降低性能开销。

官网的图,每一个代表一个组件,他们之间进行调用,画的少了Trace Id,加上就好了。

每个组件都会生成一个 Trace Id(全局唯一),还会有 Span Id、Parent Id 三部分组成。链路上的所有组件组成一个完整的 Trace。

注意:

头链路Parent Id = null,其余的都指向上一个组件的Span Id,从而形成链路。

一次链路调用所有的组件Trace Id都是一样的。

这里说的组件就是一个个的微服务!

在这里插入图片描述

三、 Zipkin介绍和搭建

1. 定义

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

Zipkin官网地址

2. 核心概念

名词翻译解释
Trace追踪Trace 代表整个请求的追踪路径,跨越不同的服务。
Span跨度Span 是基本工作单位,代表了请求在单个服务中的处理过程。
Trace ID追踪标识Trace ID 是唯一标识一个 Trace 的标识符,用于将不同的 Span 关联到同一个 Trace 上。
Annotations注解Annotations 用于记录 Span 的关键事件,通常包括开始和结束时间、操作名称等。
Binary Annotations二进制注解Binary Annotations 用于记录额外的自定义信息,例如请求状态、错误信息等。
Collector收集器Collector 负责接收和存储从不同服务发送的 Span 数据,以便后续的检查和分析。
Query and Visualization查询和可视化提供了查询和可视化界面,允许用户查看和分析跟踪数据,以帮助故障排查和性能优化。

尽管Sleuth 和 Zipkin有些术语和概念中有相似之处,但它们是两个不同的工具,各自有自己的实现和用途。

Spring Cloud Sleuth 用于生成和传播跟踪信息,而 Zipkin 用于收集、存储、查询和可视化这些信息。它们可以协同工作,但也可以独立使用。

在这里插入图片描述

3. docker搭建

官方有三种方式搭建,推荐使用:如果您熟悉 Docker,这是首选的启动方法。

Docker Zipkin项目能够构建 docker 镜像、提供脚本和docker-compose.yml 用于启动预构建镜像的脚本。最快的启动方式是直接运行最新的镜像:

docker run -d -p 9411:9411 openzipkin/zipkin

在这里插入图片描述

我们启动成功,在Windows下访问看是否成功!

http://192.168.239.130:9411/zipkin/

在这里插入图片描述

注意:

Zipkin默认将追踪数据信息保存到内存,重启服务后追踪数据丢失,Zipkin支持将追踪数据持久化到MySQL或ES。

可以直接使用docker-componse运行:

docker-componse运行脚本

可以自行试一下,这里就不带大家演示了!

四、Springboot整合

今天我们来进行简单的链路模拟:

service-order模块调用service-stock模块调用service-message模块

通信我们使用openFeign来进行调用,三个模块统一使用nacos进行注册

大家可以下载一下项目体验一下,可以自己搭建,就是一个聚合项目!

结构如下:

在这里插入图片描述

1. 导入依赖

这是父依赖

<properties>
    <spring.boot.version>2.7.3</spring.boot.version>
    <spring.cloud.dependencies.version>2021.0.1</spring.cloud.dependencies.version>
    <spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <org.projectlombok.lombok>1.18.26</org.projectlombok.lombok>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring.cloud.dependencies.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring.cloud.alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.lombok}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

spring-cloud-dependencies里包含了sleuth、zipkin的依赖,父不需要在定义管理版本。

子依赖要比父依赖多了sleuth、zipkin两个,还有openFeign的包!

<!-- Sleuth依赖项 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

<!--Zipkin 依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

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

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

2. yml配置

三份自己改一下端口和应用名称:service-order、service-stock、service-message;端口分别为:9000、9001、9002

server:
  port: 9000

spring:
  application:
    # 应用名称
    name: service-order
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: localhost:8848
  zipkin:
    base-url: http://192.168.239.130:9411
    sender:
      type: web # 设置使用 http 的方式传输数据

3. 详细代码

记得在启动类上添加注解:@EnableFeignClients,表示开启feign调用

完整的结构如下:

在这里插入图片描述
下面把具体代码给大家:
OrderController :

/**
 * @author wangzhenjun
 * @date 2023/10/31 14:25
 */
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/order")
@RestController
public class OrderController {

    private final RemoteStockFeignService remoteStockFeignService;
    /**
     * 模拟下单流程
     * @param userId
     * @param productId
     * @return
     */
    @GetMapping("/createOrder")
    public String createOrder(@RequestParam("userId") Integer userId, @RequestParam("productId") Integer productId) {
        log.info("====>订单模块<========");
        // 调用库存服务进行库存扣减
        String stockResult = remoteStockFeignService.subtractStock(userId,productId,1);
        log.info("扣减库存结果:{}", stockResult);
        // 还有其他。。。。。

        return "下单成功!";
    }
}

RemoteStockFeignService :

/**
 * @author wangzhenjun
 * @date 2023/10/31 14:29
 */
@FeignClient(value = "service-stock")
public interface RemoteStockFeignService {

    @GetMapping(value = "/stock/subtractStock")
    String subtractStock(@RequestParam(value = "userId") Integer userId,@RequestParam(value = "productId") Integer productId,@RequestParam(value = "num") Integer num);
}

StockController :

/**
 * @author wangzhenjun
 * @date 2023/10/31 14:40
 */
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/stock")
@RestController
public class StockController {

    private final RemoteMessageFeignService remoteMessageFeignService;

    @GetMapping(value = "/subtractStock")
    public String subtractStock(@RequestParam(value = "userId") Integer userId,@RequestParam(value = "productId") Integer productId, @RequestParam(value = "num") Integer num) {
        log.info("====>库存模块<========");
        if (productId < 1) {
            throw new RuntimeException("商品不存在,请重新请求!");
        }
        // 调用短信模块给用户发下单成功短信
        String messageResult = remoteMessageFeignService.sendMessage(userId);
        log.info("发送短信结果:{}", messageResult);
        return "扣减库存成功!";
    }
}

RemoteMessageFeignService:

/**
 * @author wangzhenjun
 * @date 2023/10/31 14:29
 */
@FeignClient(value = "service-message")
public interface RemoteMessageFeignService {

    @GetMapping(value = "/message/sendMessage/{userId}")
    String sendMessage(@PathVariable(value = "userId") Integer userId);
}

MessageController :

/**
 * @author wangzhenjun
 * @date 2023/10/31 14:40
 */
@Slf4j
@RequestMapping("/message")
@RestController
public class MessageController {


    @GetMapping(value = "/sendMessage/{userId}")
    public String sendMessage(@PathVariable(value = "userId") Integer userId) {
        log.info("====>短信模块<========");
        if (userId < 1 || userId > 999999) {
            throw new RuntimeException("用户不存在,请重新请求!");
        }
        return "发送短信成功!";
    }
}

4. 启动nacos

Windows下启动nacos,找到nacos下的bin目录执行命令:

startup.cmd -m standalone

在这里插入图片描述

找到地址,访问。用户名密码都是nacos。可以在配置文件中修改!

在这里插入图片描述

5. 注册成功

我们把三个模块进行启动!nacos上已经可以看到我们的服务注册上了,可以通过服务名进行调用了!

在这里插入图片描述

五、调试

我们以订单模块为入扣进行链路调用:

http://localhost:9000/order/createOrder?userId=2&productId=89

1. 查看日志

我们看一下订单模块的日志。

可以总结出Sleuth 日志格式:

[service-order,e36ebe859a7473e7,e36ebe859a7473e7]

[服务名称,Trace ID,Span ID]

在最开始的链路上,Trace ID 和 Span ID 的值通常是相同的,这是因为它们都代表了整个请求的追踪。

一条链路使用一个相同的Trace ID。

在日志没有提现出Parent Span ID,不过不应该,我们可以通过Zipkin来看链路!

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. Zipkin查看

前面我们已经进入了Zipkin页面了,只需要刷新一下就可以看到每次链路的记录了!

在这里插入图片描述

点击SHOW按钮,可以看到详细链路信息:

耗时,深度,Trance ID 还是挺好的。

在这里插入图片描述

3. 模拟异常

我们来把商品修改一下:

http://localhost:9000/order/createOrder?userId=2&productId=-89

此时是库存服务出现的问题,就不会展示下一个消息模块,自然而然的找到了出现问题的链路和根源!

在这里插入图片描述

在模拟一个三级错误的,就会看到链路的最后一级!

在这里插入图片描述
下面还可以查询依赖关系:

在这里插入图片描述

点击节点,可以查看汇总,调用次数和失败次数的统计分析!

在这里插入图片描述

六、总结

分布式链路追踪已经成为现代微服务架构中不可或缺的工具之一。

通过它,我们可以清晰地跟踪请求的调用路径,了解系统的性能,诊断潜在问题,并不断优化我们的应用程序。

Spring Cloud Sleuth让我们轻松生成和传播跟踪信息,使我们的微服务能够协同工作,无缝地捕捉每个请求的处理路径。

Zipkin作为一个流行的分布式追踪系统,为我们提供了可视化界面,使我们能够以图形化的方式查看和分析跟踪数据。

当然简单系统上这个大材小用,但是我们可以在项目中试试,加了也不会影响程序的正常运行,做一个简单的知识储备!


看到这里了,还请动一下您的发财小手,关注一下公众号哈!!谢谢您的关注!!文章首发看!!!

建了一个IT交流群,欢迎大家加入,过期加我拉你们进哈!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/176278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++:哈希表的模拟实现

文章目录 哈希哈希冲突哈希函数 解决哈希冲突闭散列&#xff1a;开散列 哈希 在顺序结构和平衡树中&#xff0c;元素的Key和存储位置之间没有必然的联系&#xff0c;在进行查找的时候&#xff0c;要不断的进行比较&#xff0c;时间复杂度是O(N)或O(logN) 而有没有这样一种方案…

数据库基本操作-----数据库用户管理和授权

一、数据库用户管理 1&#xff0e;新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码];‘用户名’&#xff1a;指定将创建的用户名 ‘来源地址’&#xff1a;指定新创建的用户可在哪些主机上登录&#xff0c;可使用IP地址、网段、主机名的形式&#xff0c…

linux下流媒体压力测试工具的使用

前言 因为领导要求做linux的推拉流时服务器压力测试&#xff0c;于是在网上找了找。一顿操作下来&#xff0c;发现很多软件盗用一款名为srs-bench的开源软件。 该代码仓库有详细的使用说明&#xff0c;而且可以在issues中找到可能会遇到的问题的解决办法 需要下载该仓库的源…

C# Onnx 百度PaddleSeg发布的实时人像抠图PP-MattingV2

目录 效果 模型信息 项目 代码 下载 效果 图片源自网络侵删 模型信息 Inputs ------------------------- name&#xff1a;img tensor&#xff1a;Float[1, 3, 480, 640] --------------------------------------------------------------- Outputs -----------------…

ZLMediaKit安装配置和推拉流

一、ZLMediaKit 库简介 ZLMediaKit 是一个基于 C11 的高性能运营级流媒体服务框架 官方写的项目特点&#xff1a; 基于 C11 开发&#xff0c;避免使用裸指针&#xff0c;代码稳定可靠&#xff0c;性能优越。 支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV/GB28181/MP…

栈的生长方向不总是向下

据我了解&#xff0c;栈的生长方向向下&#xff0c;内存地址由高到低 测试 windows下&#xff1a; 符合上述情况 测试Linux下&#xff1a; 由此可见&#xff0c;栈在不同操作系统环境下&#xff0c;生长方向不总是向下

【Python】Vscode解决Python中制表符和空格混用导致的缩进问题

【Python】Vscode解决Python中制表符和空格混用导致的缩进问题 文章目录 【Python】Vscode解决Python中制表符和空格混用导致的缩进问题1. 问题来源2. 解决Reference 1. 问题来源 在python中使用缩进来进行代码块的分区&#xff0c;通常来说python的一个缩进包含4个空格&#…

不存在类型变量 A, T 的实例,使 Collector<T, A, List<T>> 符合 Supplier<R>

报错信息 原因: 不存在类型变量 A, T 的实例&#xff0c;使 Collector<T, A, List<\T>> 符合 Supplier<\R> 来源 测试Stream流的map方法&#xff0c;做算法习惯基本类型定义数组。 map方法:Stream API的一部分。允许以一种声明式的方式处理数据&#xff0c…

nodejs搭建本地服务

前端开发时想自己有个本地服务如下操作直接上干货 1.在桌面上直接在powerShell 输入命令行 npm install -g express-generator 然后 npm install -g express 然后新建一个例如server的文件夹 在powerShell执行 express myStudy -e 端口号默认是3000 直接在地址栏输入 http://…

Windows 7 连接 Windows 10 共享打印机,Windows 无法连接打印机,操作失败,错误为0x0000011b 的终极解决办法

Windows 7 连接 Windows 10 共享打印机出现错误 0x000001b&#xff0c;建议不要通过卸载Windows10系统的KB5005565安全更新来解决该问题&#xff08;犹如削足适履&#xff09;&#xff0c;正确的处理方法是手工添加一个本地打印机&#xff0c;本方法是安全可靠的。本文详述了该…

枚举 蓝桥oj DNA序列修正

题目详情&#xff1a; 简单翻译&#xff1a; 主要思路&#xff1a; 1 本题采用贪心思路&#xff0c;要使调整次数最少&#xff0c;就是尽量交换两个碱基对&#xff0c;而不是单个替换&#xff0c;因为本题已经说明只能每个碱基对只能交换一次&#xff0c;所以不考虑A与B交换再…

NC65 修改元数据字段长度

NC65 修改元数据字段长度&#xff0c;执行下面sql&#xff0c;执行完后需要重启NC服务才生效。 --属性 update md_property set attrlength 200 where name fphm and classidece96dd8-bdf8-4db3-a112-9d2f636d388f ;--列 update md_column set columnlength 200 where tab…

远程命令执行漏洞原理,以及防护绕过方式

一、背景 RCE(Remote Command /Code Execute) 远程代码执行漏洞 通过PHP代码注入、Java代码注入等方式连接程序中预留的后门或接口从而进行远程命令执行&#xff0c;达到对服务器的控制。 为什么会出现远程代码执行漏洞呢&#xff1f; Web应用有时需要调用执行一些系统命令函数…

YOLOv5 环境搭建

YOLOv5 环境搭建 flyfish 环境 Ubuntu20.04 驱动、CUDA Toolkit、cuDNN、PyTorch版本对应 1 NVIDIA驱动安装 在[附加驱动界]面安装驱动时&#xff0c;需要输入安全密码&#xff0c;需要记下&#xff0c;后面还需要输入这个密码 重启之后有的机器会出现 perform mok manage…

C2039 编译clr工程报错

在编译clr工程的时候出现错误 错误提示如下 出现上述情况的代码文件 crl头文件VideoPlayerCLRDLL.h 被crl引用的头文件PlayerEnterPort.h 在上述情况下&#xff0c;编译clr工程会编译opengl_player.h头文件中的内容&#xff0c;但在clr工程中不认识std::mutex&#xff0c…

设计模式篇---外观模式

文章目录 概念结构实例总结 概念 外观模式&#xff1a;为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 外观模式引入了一个新的外观类&#xff0c;它为多个业务类的调用提供了一个统一的入口。主要优点…

Leetcode—8.字符串转换整数(atoi)【中等】

2023每日刷题&#xff08;三十七&#xff09; Leetcode—8.字符串转换整数&#xff08;atoi&#xff09; 算法思想 参考k神的题解 实现代码 int myAtoi(char* s) {int len strlen(s);if(len 0) {return 0;}int boundary INT_MAX / 10;int i 0, ans 0;while(s[i] ) …

Java异常处理机制

Java异常处理机制 一、异常概述与异常体系结构异常概述Error示例代码&#xff1a;Exception示例代码&#xff1a;异常体系结构Error和Exception的区别:异常分类检查异常非检查异常Why:为什么有非检查异常&#xff1f;Where:非检查异常有哪些&#xff1f;Exception异常划分运行时…

京东商品详情数据接口(JD.item_get)

京东商品详情数据接口是京东开放平台提供的一种API接口&#xff0c;通过调用该接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息。该接口的主要作用是帮助开发者获取商品的详细数据&#xff0c;从而更好地了解和分析…

【顺序表的应用-通讯录的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、顺序表的应用 1. 基于动态顺序表实现通讯录 1、功能要求 2、代码实现 二、通讯录的代码实现 1.通讯录的底层结构(顺序表) (1)思路展示 (2)底层代码实现(顺序表…