Micrometer Tracing 分布式链路追踪技术文档(完整版)
Spring Boot 3.x 官方推荐的分布式追踪方案
替代 Spring Cloud Sleuth,集成 OpenTelemetry,零侵入、轻量级、高性能
一、Micrometer Tracing 是什么?
Micrometer Tracing 是 Spring Boot 3.x 内置的分布式追踪解决方案,基于 Micrometer 观测框架,提供:
- 自动追踪:HTTP、消息队列、数据库、异步任务等
- 上下文传播:Trace ID、Span ID 跨线程、服务、消息传播
- 灵活导出:支持 Zipkin、Jaeger、OTLP(OpenTelemetry Protocol)
- 零侵入:无需修改业务代码
官方声明 :Spring Cloud Sleuth 已于 2023 年正式弃用,所有新项目必须使用 Micrometer Tracing。
二、核心概念
| 概念 | 说明 | 示例 |
|---|---|---|
| Trace ID | 整个请求链路的唯一标识 | a1b2c3d4e5f67890 |
| Span ID | 单次操作的标识 | 12345678 |
| Span | 一次操作(如 HTTP 请求、DB 查询) | GET /api/order |
| Observation | Micrometer 的追踪抽象 | Observation.createNotStarted() |
| Tracer | 底层追踪实现(如 Brave、OpenTelemetry) | io.micrometer.tracing.Tracer |
| Baggage | 跨服务传递额外数据 | user-id=alice |
三、快速开始(3 分钟上手)
1. 添加依赖(Maven)
xml
<dependencies>
<!-- 核心:Actuator 包含 Micrometer Tracing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</d>
</dependency>
<!-- 桥接:选择 OpenTelemetry(推荐)或 Brave -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<!-- 导出:Zipkin(最常用) -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
<!-- 可选:Jaeger 用 OTLP -->
<!--
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
-->
</dependencies>
2. 配置 application.yml
yaml
spring:
application:
name: order-service # 必须!用于 Zipkin 显示服务名
management:
tracing:
sampling:
probability: 1.0 # 100% 采样(调试用,生产建议 0.1)
propagation:
type: W3C # 推荐:W3C Trace Context
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans
logging:
pattern:
level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}] %c - %m%n"
3. 启动 Zipkin
bash
docker run -d -p 9411:9411 openzipkin/zipkin
4. 访问接口 → 查看效果
java
@RestController
public class OrderController {
@GetMapping("/order")
public String createOrder() {
return "Order created!";
}
}
日志输出:
yaml
logging:
pattern:
level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}] %c - %m%n"
INFO [order-service,a1b2c3d4e5f67890,12345678] OrderController - createOrder
Zipkin UI (http://localhost:9411):
order-service → GET /order (200ms)
四、自动追踪支持(开箱即用)
| 技术栈 | 是否支持 | 配置 |
|---|---|---|
| Spring Web MVC | Yes | 自动 |
| Spring WebFlux | Yes | 自动 |
| RestTemplate | Yes | 自动 |
| WebClient | Yes | 自动 |
| Feign | Yes | 自动 |
| JDBC | Yes | 自动 |
| JPA / Hibernate | Yes | 自动 |
| MongoDB | Yes | 自动 |
| Redis (Lettuce) | Yes | 自动 |
| Kafka | Yes | 自动 |
| RabbitMQ | Yes | 自动 |
| @Async / ThreadPool | Yes | 需 TaskDecorator |
五、高级使用:手动创建 Observation
1. 注入 ObservationRegistry
java
@Service
public class PaymentService {
private final ObservationRegistry registry;
public PaymentService(ObservationRegistry registry) {
this.registry = registry;
}
public void processPayment() {
Observation.createNotStarted("payment.process", registry)
.lowCardinalityKeyValue("payment.method", "credit_card")
.observe(() -> {
log.info("处理支付...");
// 模拟耗时
try { Thread.sleep(500); } catch (Exception e) {}
});
}
}
2. 使用 @Observed 注解(Spring Boot 3.2+)
java
@Observed(name = "user.login", contextualName = "login")
@Service
public class AuthService {
public void login(String username) {
log.info("用户登录: {}", username);
}
}
六、上下文传播(关键!)
1. 异步任务传播
java
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor(ObservationRegistry registry) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setTaskDecorator(new ObservationTaskDecorator(registry));
executor.initialize();
return executor;
}
}
// 传播 Observation 上下文
class ObservationTaskDecorator implements TaskDecorator {
private final ObservationRegistry registry;
public ObservationTaskDecorator(ObservationRegistry registry) {
this.registry = registry;
}
@Override
public Runnable decorate(Runnable runnable) {
Observation current = Observation.current();
if (current == null) return runnable;
return () -> {
try (Observation.Scope scope = current.openScope()) {
runnable.run();
}
};
}
}
2. 自定义线程传播
java
ExecutorService executor = Executors.newFixedThreadPool(5);
Observation current = Observation.current();
executor.submit(() -> {
try (Observation.Scope scope = current.openScope()) {
log.info("子线程任务"); // 能打印 traceId!
}
});
七、Baggage:跨服务传递额外数据
1. 配置远程字段
yaml
management:
tracing:
baggage:
remote-fields: [user-id, tenant-id]
2. 设置和获取
java
// 设置
BaggageField.getByName("user-id").updateValue("alice");
// 获取
String userId = BaggageField.getByName("user-id").getValue();
用途:在 Zipkin 中查看用户行为、AB 测试分组等。
八、导出器配置
1. Zipkin(推荐)
yaml
management:
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans
2. Jaeger(OTLP)
xml
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
yaml
management:
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
3. 自定义导出器
java
@Bean
public SpanHandler customHandler() {
return new SpanHandler() {
@Override
public boolean supports(Span span) { return true; }
@Override
public Span handle(Span span) {
System.out.println("Custom span: " + span);
return span;
}
};
}
九、生产环境最佳实践
| 项目 | 推荐配置 |
|---|---|
| 采样率 | 0.1(10%) |
| 服务名 | spring.application.name 必须设置 |
| 日志 | 包含 %X{traceId} |
| Baggage | 仅传递关键字段 |
| 监控 | 结合 Prometheus + Grafana |
yaml
management:
tracing:
sampling:
probability: 0.1
metrics:
export:
prometheus:
enabled: true
十、常见问题(FAQ)
| 问题 | 解决方案 |
|---|---|
| 没有 traceId | 检查 spring.application.name 是否设置 |
| 日志没 traceId | 检查 logging.pattern.level |
| 异步任务丢追踪 | 使用 ObservationTaskDecorator |
| Kafka 消息没传播 | 确保使用 micrometer-tracing-bridge-otel |
| 性能问题 | 调低采样率,生产环境 ≤ 0.1 |
十一、完整示例项目结构
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── OrderController.java
│ │ ├── PaymentService.java
│ │ ├── AsyncConfig.java
│ │ └── TracingConfig.java
│ └── resources/
│ └── application.yml
pom.xml
十二、参考文档
总结:一句话记住
Micrometer Tracing = Spring Boot 3.x 的 Sleuth 替代品
开箱即用 + 灵活配置 + OpenTelemetry 标准 = 未来可期!
立即行动:
- 升级到 Spring Boot 3.x
- 添加
micrometer-tracing-bridge-otel - 启动 Zipkin
- 打开
http://localhost:9411→ 看到你的链路!