Spring Boot 2.x时代,我们靠Spring Cloud Sleuth做链路追踪,靠Micrometer做指标。到了3.x,Sleuth被废弃,取而代之的是Micrometer Tracing + OpenTelemetry的统一方案。这不是简单的"换名字"——而是从"各管各的"到"三位一体"(Metrics+Traces+Logs)的架构升级。这篇讲清楚3.x的可观测性体系怎么搭,以及那些踩过的坑。

一、为什么需要统一的可观测性?

在微服务架构下,一个请求可能经过:

Gateway → Order Service → Payment Service → Inventory Service

当用户说"支付失败"时,你需要回答:

  1. 哪个环节慢了?(Metrics)
  2. 请求经过了哪些服务?(Traces)
  3. 具体报了什么错?(Logs)

在传统架构下,这三者分散在不同的系统里——Prometheus看指标、Jaeger看链路、ELK看日志。Spring Boot 3.x的目标是让这三者在同一个上下文中关联起来。

二、核心组件演进

2.1 Micrometer:指标的抽象层

<!-- Spring Boot 3.x 默认依赖 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>

关键变化

维度 Spring Boot 2.x Spring Boot 3.x
指标注册 MeterRegistry MeterRegistry(不变)
链路追踪 Spring Cloud Sleuth Micrometer Tracing
导出后端 各自配置 统一通过ObservationRegistry

2.2 Micrometer Tracing:替代Sleuth

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>

为什么选OpenTelemetry

  • Sleuth是Spring生态专属,OTel是CNCF标准
  • OTel支持更多语言(Java/Go/Python/Node.js)
  • 社区活跃度更高,云厂商原生支持

2.3 Observation API:统一的入口

// Spring Boot 3.x 新增的Observation API
Observation observation = Observation.start("order.process", registry);
try {
    // 业务逻辑
    orderService.create(order);
} finally {
    observation.stop();
}

Observation的作用:它同时记录指标和链路信息,确保两者使用同一个traceId。

三、实战配置

3.1 基础配置

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  metrics:
    export:
      prometheus:
        enabled: true
  tracing:
    sampling:
      probability: 1.0  # 采样率(生产环境建议0.1)
    propagation:
      type: w3c  # W3C Trace Context标准

3.2 自定义Observation

@Component
public class OrderService {
    
    private final ObservationRegistry registry;
    
    public OrderService(ObservationRegistry registry) {
        this.registry = registry;
    }
    
    public Order createOrder(OrderRequest request) {
        return Observation.createNotStarted("order.create", registry)
            .contextualName("create-order")
            .lowCardinalityKeyValue("order.type", request.getType())
            .highCardinalityKeyValue("order.id", request.getId())
            .observe(() -> {
                // 业务逻辑
                return orderRepository.save(request.toEntity());
            });
    }
}

关键点

  • lowCardinalityKeyValue:用于聚合的标签(如order.type),基数低
  • highCardinalityKeyValue:用于调试的标签(如order.id),基数高,不会出现在Prometheus指标中

3.3 链路传播

// RestTemplate自动携带traceId
RestTemplate restTemplate = new RestTemplate();
// Spring Boot 3.x 自动配置了ObservationRestTemplateCustomizer

// WebClient同理
WebClient client = WebClient.builder()
    .filter(new ObservationWebClientFilter(registry))
    .build();

四、日志与链路的关联

4.1 Logback配置

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 添加traceId和spanId -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %X{traceId:-} %X{spanId:-} %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
</configuration>

输出示例

2026-07-07 14:30:01 [http-nio-8080-exec-1] a1b2c3d4e5f6 g7h8i9j0 INFO  c.e.OrderService - Order created: 10086

4.2 MDC自动填充

Spring Boot 3.x 自动将traceId/spanId放入MDC,无需手动设置:

// 不需要这样写了
MDC.put("traceId", traceId);

// 直接在logback pattern里用%X{traceId}即可

五、常见陷阱

5.1 采样率设置不当

# ❌ 生产环境设为1.0会导致存储爆炸
tracing:
  sampling:
    probability: 1.0

# ✅ 根据流量调整
tracing:
  sampling:
    probability: 0.1  # 10%的请求被采样

5.2 高基数标签污染Prometheus

// ❌ 错误:把orderId作为lowCardinalityKeyValue
Observation.createNotStarted("order.create", registry)
    .lowCardinalityKeyValue("order.id", orderId)  // 每个orderId都是新标签
    .observe(...);

// ✅ 正确:orderId用highCardinalityKeyValue
Observation.createNotStarted("order.create", registry)
    .highCardinalityKeyValue("order.id", orderId)  // 只出现在链路中
    .lowCardinalityKeyValue("order.type", "vip")   // 出现在Prometheus
    .observe(...);

5.3 异步线程丢失traceId

// ❌ 普通线程池不传播traceId
executor.submit(() -> {
    log.info("async task");  // traceId为空
});

// ✅ 使用ObservationAwareExecutor
ObservationAwareExecutor executor = new ObservationAwareExecutor(
    Executors.newFixedThreadPool(10), registry);

六、监控看板示例

6.1 Grafana面板

# HTTP请求延迟P99
histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, uri))

# 错误率
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) 
/ 
sum(rate(http_server_requests_seconds_count[5m]))

6.2 Jaeger/Zipkin链路查看

访问 http://localhost:9411/zipkin/ 查看链路拓扑。

七、总结

  1. Spring Boot 3.x用Micrometer Tracing替代Sleuth,底层基于OpenTelemetry
  2. Observation API是统一的入口,同时记录指标和链路
  3. 低基数标签用于Prometheus聚合,高基数标签用于链路调试
  4. 日志自动关联traceId,无需手动设置MDC
  5. 异步场景要用ObservationAwareExecutor,否则traceId丢失
  6. 采样率在生产环境要调低(0.1或更低),避免存储爆炸
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐