SpringCloud Sleuth 分布式链路追踪实践指南

 更新时间:2025年11月03日 16:27:53   作者:FearlessVoyager  
SpringCloud Sleuth是一个用于分布式追踪的组件,通过为每个请求生成唯一的TraceID和SpanID,记录请求在多个微服务中的流转情况,本文重点给大家介绍SpringCloud Sleuth 分布式链路追踪的实例讲解,感兴趣的朋友跟随小编一起看看吧

一、Sleuth 概述

Sleuth 是 Spring Cloud 生态系统中的一个组件,它提供了分布式追踪的解决方案。在微服务架构中,一个请求可能会经过多个服务,Spring Cloud Sleuth 可以帮助我们跟踪这些请求,为每个请求生成一个唯一的追踪ID,并在日志中记录这些ID,从而使得我们可以轻松地追踪请求在各个微服务中的流转情况。

二、Sleuth 核心概念

  1. Trace:一次完整的分布式请求跟踪,相当于一个树状结构,从请求到第一个服务开始,到最后一个服务返回响应结束。每个 Trace 有一个唯一的 Trace ID。
  2. Span:表示一个基本的工作单元,比如一次 HTTP 请求、一次数据库调用等。每个 Span 有一个唯一的 Span ID。一个 Trace 由多个 Span 组成,这些 Span 之间具有父子关系。
  3. Annotation:用于记录事件的时间点,例如:
    • cs(Client Sent):客户端发送请求,表示开始一个 Span。
    • sr(Server Received):服务端接收请求,并开始处理。
    • ss(Server Sent):服务端发送响应,表示处理完成。
    • cr(Client Received):客户端接收响应,表示 Span 结束。

三、Sleuth 核心功能

  1. 分布式追踪:跟踪请求在微服务间的流转路径。
  2. Span 管理:记录每个服务处理单元的工作单元。
  3. Trace 上下文传播:在服务间传递追踪上下文。
  4. 与 Zipkin 集成:将追踪数据导出到 Zipkin 进行可视化分析。

四、Sleuth 实现原理

Spring Cloud Sleuth 的实现原理可以总结为:

  1. 标识与上下文: 通过 TraceId 和 SpanId 唯一标识请求链路和单元。
  2. 传播与透传: 利用 ThreadLocal 进行进程内上下文存储,并通过 HTTP 头等载体进行跨服务上下文传播。
  3. 自动化与透明: 通过自动仪器化主流框架组件,对开发者透明地完成追踪逻辑的植入。
  4. 收集与可视化: 通过 Reporter 将完成的 Span 数据上报给 Zipkin 等后端,进行聚合、存储和图形化展示。
  5. 日志增强: 通过与 MDC 集成,无缝地将追踪信息输出到应用日志中,极大方便了问题排查。

五、实现案例(Sleuth + Zipkin)

使用Spring Boot和Spring Cloud Sleuth与Zipkin来实现分布式链路追踪,主要步骤:

  1. 创建两个Spring Boot服务:一个作为服务提供者(provider),一个作为服务消费者(consumer),消费者调用提供者的服务。
  2. 引入Spring Cloud Sleuth和Zipkin的依赖。
  3. 配置Zipkin服务器地址。
  4. 通过RestTemplate或FeignClient进行服务调用,Sleuth会自动追踪。
  5. 启动Zipkin服务器来收集和展示追踪数据。

5.1 环境准备

使用 Docker 启动 Zipkin Server。

# 使用 Docker 运行 Zipkin
docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
# 或者使用命令行启动(需要 Java 环境)
# curl -sSL https://zipkin.io/quickstart.sh | bash -s
# java -jar zipkin.jar

5.2 添加依赖

在服务提供者和服务消费者服务的pom.xml文件中分别添加Sleuth和Zipkin的依赖。

<!-- Spring Cloud 版本管理 -->
<properties>
    <spring-cloud.version>2022.0.4</spring-cloud.version>
</properties>
<!-- Sleuth + Zipkin 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

5.3 配置文件

在服务提供者和服务消费者服务的application.yml配置文件中配置Zipkin服务器地址。

spring:
  application:
    name: user-service
  sleuth:
    sampler:
      probability: 1.0  # 采样率,1.0表示100%采样
  zipkin:
    base-url: http://localhost:9411  # Zipkin服务器地址
    sender:
      type: web

5.4 服务间调用追踪

当服务都启动成功后,进行服务间的调用时,Sleuth会自动在header中添加Trace信息。

@RestController
@RequestMapping("/users")
public class UserController {
    private final RestTemplate restTemplate;
    private final UserService userService;
    public UserController(RestTemplate restTemplate, UserService userService) {
        this.restTemplate = restTemplate;
        this.userService = userService;
    }
    @GetMapping("/{userId}/orders")
    public UserOrderInfo getUserOrders(@PathVariable Long userId) {
        // Sleuth会自动在header中添加Trace信息
        ResponseEntity<OrderList> orderResponse = restTemplate.exchange(
            "http://order-service/orders/user/" + userId,
            HttpMethod.GET,
            null,
            OrderList.class
        );
        User user = userService.getUserById(userId);
        return new UserOrderInfo(user, orderResponse.getBody());
    }
}

5.5 查看 Zipkin 链路追踪

访问 http://localhost:9411 查看链路追踪数据:

  1. 在 Zipkin UI 中可以看到服务间的调用关系。
  2. 查看每个请求的详细链路信息。
  3. 分析服务调用的耗时和依赖关系。

六、高级配置和自定义

6.1 自定义 Span 标签

@Service
public class UserService {
    private final Tracer tracer;
    public UserService(Tracer tracer) {
        this.tracer = tracer;
    }
    public User getUserById(Long userId) {
        // 创建自定义Span
        Span userSpan = tracer.nextSpan().name("db.user.query").start();
        try (Tracer.SpanInScope ws = tracer.withSpanInScope(userSpan)) {
            // 业务逻辑
            userSpan.tag("user.id", userId.toString());
            userSpan.event("query.user.from.database");
            // 模拟数据库查询
            return userRepository.findById(userId);
        } catch (Exception e) {
            userSpan.error(e);
            throw e;
        } finally {
            userSpan.end();
        }
    }
}

6.2 异步方法追踪

@Async
@Sleuth
public CompletableFuture<User> getUserAsync(Long userId) {
    // Sleuth会自动传递Trace上下文
    return CompletableFuture.supplyAsync(() -> userRepository.findById(userId));
}

6.3 自定义采样策略

@Configuration
public class TraceConfig {
    @Bean
    public Sampler defaultSampler() {
        // 自定义采样策略:只追踪重要接口
        return new Sampler() {
            @Override
            public boolean isSampled(TraceContext traceContext) {
                // 根据请求路径决定是否采样
                String path = getCurrentRequestPath();
                return path.startsWith("/api/") || path.startsWith("/internal/");
            }
        };
    }
}

6.4 数据库调用追踪

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        // 使用P6Spy拦截SQL语句
        P6SpyDataSource dataSource = new P6SpyDataSource(actualDataSource());
        return dataSource;
    }
}

6.5 消息队列追踪

@Component
public class MessageService {
    private final Tracer tracer;
    private final StreamBridge streamBridge;
    public void sendUserCreatedEvent(User user) {
        // 手动注入Trace信息到消息头
        Message<User> message = MessageBuilder.withPayload(user)
            .setHeader("traceId", tracer.currentSpan().context().traceId())
            .setHeader("spanId", tracer.currentSpan().context().spanId())
            .build();
        streamBridge.send("user-created-out-0", message);
    }
}

到此这篇关于SpringCloud Sleuth 分布式链路追踪的文章就介绍到这了,更多相关SpringCloud Sleuth链路追踪内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现读取不同格式的文件的示例详解

    Java实现读取不同格式的文件的示例详解

    在 Java 开发中,我们经常需要读取不同类型的文件,包括 Excel 表格文件、"doc" 等,本文将介绍如何使用 Java 读取这些不同类型的文件,需要的可以参考下
    2024-01-01
  • Java 生成图片验证码3种方法(字母、加减乘除、中文)

    Java 生成图片验证码3种方法(字母、加减乘除、中文)

    这篇文章主要介绍了Java 生成图片验证码3种方法(字母、加减乘除、中文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • 利用EasyPOI实现多sheet和列数的动态生成

    利用EasyPOI实现多sheet和列数的动态生成

    EasyPoi功能如同名字,主打的功能就是容易,让一个没见接触过poi的人员就可以方便的写出Excel导出,Excel导入等功能,本文主要来讲讲如何利用EasyPOI实现多sheet和列数的动态生成,需要的可以了解下
    2025-03-03
  • 解析Idea为什么不推荐使用@Autowired进行Field注入

    解析Idea为什么不推荐使用@Autowired进行Field注入

    这篇文章主要介绍了Idea不推荐使用@Autowired进行Field注入的原因,网上文章大部分都是介绍两者的区别,没有提到为什么,当时想了好久想出了可能的原因,今天来总结一下
    2022-05-05
  • SpringBoot整合SQLite详细过程

    SpringBoot整合SQLite详细过程

    SQLite是一个不需要服务、不需要配置、不需要外部依赖的开源SQL轻量级数据库,本文给大家介绍SpringBoot整合SQLite详细过程,感兴趣的朋友一起看看吧
    2025-06-06
  • 关于JDK15的新特性之TextBlocks文本块的引入和使用

    关于JDK15的新特性之TextBlocks文本块的引入和使用

    这篇文章主要介绍了关于JDK15的新特性之文本块的引入和使用,如果具有一种语言学机制,可以比多行文字更直观地表示字符串,而且可以跨越多行,而且不会出现转义的视觉混乱,那么这将提高广泛Java类程序的可读性和可写性,需要的朋友可以参考下
    2023-07-07
  • Spring AOP实现Redis缓存数据库查询源码

    Spring AOP实现Redis缓存数据库查询源码

    这篇文章主要介绍了Spring AOP实现Redis缓存数据库查询的相关内容,源码部分还是不错的,需要的朋友可以参考下。
    2017-09-09
  • SpringMVC如何正确接收时间的请求示例分析

    SpringMVC如何正确接收时间的请求示例分析

    这篇文章主要为大家介绍了SpringMVC如何正确接收时间的请求示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Java Spring数据单元配置过程解析

    Java Spring数据单元配置过程解析

    这篇文章主要介绍了Java Spring数据单元配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12
  • @Valid 无法校验List<E>的问题

    @Valid 无法校验List<E>的问题

    这篇文章主要介绍了@Valid 无法校验List<E>的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10

最新评论