spring-boot-3.4+micrometer-tracing实现分布式跟踪

spring-boot-3.4+micrometer-tracing实现分布式跟踪

在微服务架构中,一次请求可能涉及多个服务间的调用,当系统出现问题时,快速定位问题变得尤为重要。分布式追踪可以帮助我们清晰地看到一个请求在各个服务间的调用链路,从而快速定位性能瓶颈或错误发生的位置。

Spring Boot 3.4结合Micrometer Tracing提供了强大的分布式追踪功能,本文将详细介绍如何在项目中集成和使用这一功能。

1、项目依赖配置

首先,在pom.xml中添加必要的依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.4.12</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-brave</artifactId>
    </dependency>
    <!-- OpenFeign dependency -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-micrometer</artifactId>
        <version>13.1</version>
    </dependency>
</dependencies>
2、配置文件设置
2.1 bootstrap.yaml配置
spring:
  application:
    name: trace

logging:
  level:
    root: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId:-},%X{spanId:-}] %logger{36} - %msg%n"
  file:
    name: E:/project/trace/logs/${spring.application.name}.log
2.2 application.yaml配置
spring:
  application:
    name: trace-service
  cloud:
    openfeign:
      micrometer:
        enabled: true # 默认值是true

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
3、核心功能实现

通过以上配置,OpenFeign调用的代码段已经可以正确输出traceId和spanId到日志中。但对于异步调用的代码段,我们需要额外处理MDC(Mapped Diagnostic Context)和Trace上下文的传递。

以下是以CompletableFuture.supplyAsync异步调用为例的实现方案:

@Autowired
private Tracer tracer;

/**
 * 包装Supplier任务,自动传递MDC和Trace上下文
 */
public <T> Supplier<T> wrapSupplier(Supplier<T> supplier) {
    // 获取当前线程的MDC上下文
    Map<String, String> mdcContext = MDC.getCopyOfContextMap();

    // 获取当前trace上下文
    TraceContext traceContext = getCurrentTraceContext();

    return () -> {
        // 在新线程中恢复MDC上下文
        if (mdcContext != null) {
            MDC.setContextMap(mdcContext);
        }

        // 在新线程中恢复Trace上下文
        if (traceContext != null) {
            try (Tracer.SpanInScope ws = tracer.withSpanInScope(tracer.toSpan(traceContext))) {
                return supplier.get();
            } finally {
                // 清理MDC上下文
                if (mdcContext != null) {
                    MDC.clear();
                }
            }
        } else {
            try {
                return supplier.get();
            } finally {
                // 清理MDC上下文
                if (mdcContext != null) {
                    MDC.clear();
                }
            }
        }
    };
}
4、使用示例

在实际使用中,可以通过以下方式应用包装好的supplier:

 CompletableFuture.supplyAsync(wrapSupplier(() -> {
     // 异步执行的业务逻辑
     return doSomething();
 }));

这样可以确保在异步执行的代码中也能正确传递追踪上下文,保证链路追踪的完整性。

5、效果展示

配置完成后,应用日志将显示traceId和spanId信息,例如:

2025-04-09 22:02:08.123 [http-nio-8080-exec-1] INFO  [traceId,spanId] com.example.service.MyService - Processing request

通过这些信息,我们可以清楚地追踪每个请求在系统中的流转过程,便于问题排查和性能分析。

6、总结

Spring Boot 3.4集成Micrometer Tracing为我们提供了强大的分布式追踪能力。通过简单的配置,我们可以轻松实现服务间的调用链追踪,特别是在使用OpenFeign进行服务间调用时。对于异步调用场景,通过手动传递MDC和Trace上下文,也可以保证追踪信息的完整性。

这使得开发者能够更好地理解系统的运行状况,快速定位问题,优化系统性能。