欢迎光临
我们一直在努力

Spring Boot 3.x Observability实战:Micrometer、Tracing与OpenTelemetry全栈监控指南

在微服务架构日益普及的今天,可观测性(Observability)已经成为分布式系统不可或缺的核心能力。Spring Boot 3.x 借助 Micrometer 和 OpenTelemetry 两大生态,构建了从指标采集、链路追踪到日志聚合的全栈可观测性方案。本文将深入剖析 Spring Boot 3.x 的 Observability 体系,结合实际代码演示如何快速搭建生产级的监控系统。

系统监控仪表盘

一、从 Spring Boot 2.x 到 3.x:可观测性架构的演进

在 Spring Boot 2.x 时代,可观测性主要依赖 Spring Cloud Sleuth(分布式追踪)和 Micrometer(指标采集)。Sleuth 通过自动注入 TraceId 和 SpanId 实现了请求链路的跟踪,Micrometer 则提供了统一的指标门面,对接 Prometheus、Datadog、Graphite 等多种监控后端。但这种架构存在两个根本性问题:一是追踪和指标体系割裂,二是缺乏标准的上下文传播机制。

Spring Boot 3.x 联合 Micrometer Tracing 彻底重构了可观测性层。主要的架构变化包括:

能力 Spring Boot 2.x Spring Boot 3.x
分布式追踪 Spring Cloud Sleuth + Brave Micrometer Tracing(基于 OpenTelemetry)
指标采集 Micrometer 1.x Micrometer 1.10+
上下文传播 自定义 Header 传播 W3C TraceContext 标准(traceparent/tracestate)
日志关联 需手动配置 MDC 自动 MDC 注入

Sleuth 已被官方标记为维护模式,这意味着所有新项目都应该直接使用 Micrometer Tracing。Spring Boot 3.2 开始内置对 OpenTelemetry 协议(OTLP)的原生支持,进一步降低了接入门槛。

二、快速集成:三步搭建可观测性基础设施

2.1 添加依赖

在 pom.xml 中添加以下核心依赖。Spring Boot 3.x 通过 Micrometer Tracing 提供了对 Brave(Zipkin)、OpenTelemetry 和 Wavefront 三种追踪后端的开箱支持:

<!-- Spring Boot Actuator — 提供 /actuator/* 端点 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- Micrometer Tracing 桥接 OpenTelemetry -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>

<!-- OpenTelemetry 导出器 — OTLP 协议 -->
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>

<!-- Micrometer 注册表 — Prometheus 指标导出 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- 可选:Zipkin 导出器(替代 OTLP) -->
<!--
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
</dependency>
-->

2.2 配置 application.yml

关键配置项如下。其中 management.tracing 和 management.otlp 是 Spring Boot 3.x 新增的可观测性专用命名空间:

spring:
  application:
    name: order-service  # 服务名称,将作为 Trace 的 service.name 属性

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,prometheus,loggers
  tracing:
    sampling:
      probability: 1.0   # 生产环境建议设为 0.1 ~ 0.5
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces  # OpenTelemetry Collector 地址
  metrics:
    tags:
      application: ${spring.application.name}
    export:
      prometheus:
        enabled: true
        rsocket:
          enabled: false

logging:
  pattern:
    # 自动注入 traceId 和 spanId 到日志
    level: '%5p [%X{traceId:-},%X{spanId:-}]'
    console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %clr(%5p) %clr(${PID:-}){magenta} %clr([%X{traceId:-}]){cyan} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){blue} %clr(:){faint} %m%n'

2.3 启动基础设施组件

使用 Docker Compose 快速启动 OpenTelemetry Collector 和 Prometheus:

version: '3.8'
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    ports:
      - "4317:4317"   # gRPC
      - "4318:4318"   # HTTP
    volumes:
      - ./otel-config.yaml:/etc/otel/config.yaml
    command: ["--config=/etc/otel/config.yaml"]

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

otel-config.yaml 中配置 Pipeline 将 Trace 和 Metrics 分别转发到 Jaeger 和 Prometheus:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

exporters:
  jaeger:
    endpoint: jaeger:14250
    tls:
      insecure: true
  prometheus:
    endpoint: "0.0.0.0:8889"

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [jaeger]
    metrics:
      receivers: [otlp]
      exporters: [prometheus]

可观测性架构图

三、自定义指标与高级追踪

3.1 使用 MeterRegistry 自定义业务指标

Micrometer 提供了五种核心指标类型:Counter(计数器)、Gauge(仪表盘)、Timer(计时器)、DistributionSummary(分布摘要)和 LongTaskTimer(长任务计时器)。以下示例展示了如何统计订单创建的成功/失败次数和耗时分布:

@Service
@RequiredArgsConstructor
public class OrderMetricsService {

    private final MeterRegistry meterRegistry;

    @PostConstruct
    public void init() {
        meterRegistry.config().commonTags("service", "order-service");
    }

    public void recordOrderCreate(boolean success, long durationMs) {
        meterRegistry.counter("order.create.total",
            "status", success ? "success" : "failure"
        ).increment();

        meterRegistry.timer("order.create.duration",
            "status", success ? "success" : "failure"
        ).record(Duration.ofMillis(durationMs));
    }

    public void monitorQueueDepth(Queue<Order> queue) {
        Gauge.builder("order.queue.depth", queue, Collection::size)
            .description("Current order processing queue depth")
            .register(meterRegistry);
    }
}

3.2 @Observed 注解与自定义 Span

Micrometer Tracing 提供了 @Observed 注解,可以零侵入地为任意方法添加追踪:

@Service
@Observed  // 类级别:所有公有方法都自动追踪
public class PaymentService {

    private static final Tracer tracer = GlobalOpenTelemetry.getTracer("payment-service");

    @Observed(
        name = "payment.process",
        contextualName = "process-payment",
        lowCardinalityKeyValues = {
            @Observed.KeyValue(key = "payment.type", value = "credit_card")
        }
    )
    public PaymentResult processPayment(PaymentRequest request) {
        Span span = tracer.spanBuilder("payment.charge")
            .setAttribute("payment.amount", request.getAmount())
            .setAttribute("payment.currency", request.getCurrency())
            .startSpan();

        try (Scope scope = span.makeCurrent()) {
            PaymentResult result = charge(request);
            span.setStatus(StatusCode.OK);
            return result;
        } catch (Exception e) {
            span.recordException(e);
            span.setStatus(StatusCode.ERROR);
            throw e;
        } finally {
            span.end();
        }
    }
}

Micrometer Tracing 会自动传播 TraceContext 到跨服务的 HTTP 调用(RestTemplate、WebClient)和消息队列(Kafka、RabbitMQ),无需额外配置。每个 Span 都会自动记录以下标准属性:

  • thread.idthread.name — 执行线程信息
  • classmethod — 被追踪的方法签名
  • exception.typeexception.message — 异常堆栈(如果有)
  • http.methodhttp.url — HTTP 请求信息(对于 Controller 方法)

3.3 自定义 ObservationHandler

从 Spring Boot 3.0 开始,Observation 取代了传统的 Meter 和 Span 分离模式。通过实现 ObservationHandler 可以在指标和追踪之上叠加自定义逻辑:

@Component
public class CustomObservationHandler implements ObservationHandler<Observation.Context> {

    private static final Logger log = LoggerFactory.getLogger(CustomObservationHandler.class);

    @Override
    public void onStart(Observation.Context context) {
        log.info("Observation [{}] started with tags: {}",
            context.getName(), context.getLowCardinalityKeyValues());
    }

    @Override
    public void onStop(Observation.Context context) {
        log.info("Observation [{}] stopped. Duration: {}ms",
            context.getName(),
            context.getTimeSinceStart().toMillis());

        if (context.getTimeSinceStart().toMillis() > 1000) {
            sendSlowOperationAlert(context);
        }
    }

    @Override
    public boolean supportsContext(Observation.Context context) {
        return context.getName().startsWith("order.") ||
               context.getName().startsWith("payment.");
    }

    private void sendSlowOperationAlert(Observation.Context context) {
        // 发送告警通知逻辑
    }
}

代码与监控

四、日志与追踪的关联:告别”查问题大海捞针”

可观测性最被低估的能力是日志与追踪的关联。通过 MDC(Mapped Diagnostic Context),每个日志行都自动携带 traceId 和 spanId。当使用 Elasticsearch + Kibana(ELK)或 Grafana Loki 作为日志存储时,直接点击 traceId 就能跳转到 Jaeger 或 Grafana Tempo 查看完整的调用链路。

2026-06-29 10:15:23.456 INFO [traceId=abc123def456,spanId=789ghi] --- [http-nio-8080-exec-3] c.e.o.OrderService : 处理订单 #ORD-20260629-001,用户ID=12345
2026-06-29 10:15:23.789 ERROR [traceId=abc123def456,spanId=789ghi] --- [http-nio-8080-exec-3] c.e.o.PaymentService : 扣款失败:余额不足
2026-06-29 10:15:24.012 WARN  [traceId=abc123def456,spanId=012jkl] --- [http-nio-8080-exec-3] c.e.o.InventoryService : 商品 #SKU-98765 库存不足,当前可用=2,请求=5

具体配置方式:

<!-- logback-spring.xml 中自动注入 traceId -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%X{traceId:-},%X{spanId:-}] --- [%t] %logger{36} : %m%n</pattern>
    </encoder>
</appender>

<appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
    <http class="com.github.loki4j.logback.ApacheHttpSender">
        <url>http://localhost:3100/loki/api/v1/push</url>
    </http>
    <format>
        <label>
            <pattern>app=order-service,traceId=%X{traceId},level=%level</pattern>
        </label>
        <message>
            <pattern>%m</pattern>
        </message>
    </format>
</appender>

五、生产环境最佳实践

5.1 采样策略的选择

全量采样(sampling.probability=1.0)在低流量环境可行,但生产环境每秒数万请求时成本太高。推荐策略:

  • 基于固定概率的采样:设置 0.1~0.5,适合大部分服务。Micrometer Tracing 的默认实现是 RateLimitingSampler,每秒最多采样 10 条 Trace。
  • 基于错误率的自适应采样:所有错误请求全量采样 + 正常请求低比例采样。可以通过实现 Sampler 接口自定义:
@Bean
public Sampler customSampler() {
    return new Sampler() {
        private final Sampler fallback = Sampler.create(0.1);

        @Override
        public SamplingResult shouldSample(
                SpanContext parentContext, TraceId traceId,
                String name, SpanKind spanKind,
                Attributes attributes, Context parentLinks) {

            if (attributes.get(SemanticAttributes.HTTP_STATUS_CODE) != null
                && attributes.get(SemanticAttributes.HTTP_STATUS_CODE) >= 400) {
                return SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE);
            }
            return fallback.shouldSample(parentContext, traceId,
                name, spanKind, attributes, parentLinks);
        }

        @Override
        public String getDescription() {
            return "ErrorFullSampler";
        }
    };
}

5.2 指标维度爆炸的治理

高基数(High Cardinality)标签是 Prometheus 最头疼的问题。例如用 userId 或 orderId 作为标签值会导致指标基数爆炸。以下是治理原则:

  • Cardinality < 100:标签值有限(如 HTTP 方法 GET/POST/PUT/DELETE)→ 安全
  • Cardinality < 10000:如 URL 路径、状态码、区域 → 需要关注,建议限制
  • Cardinality > 10000:如 userId、ip、requestId → 绝对禁止!使用日志或 Tracing 替代

5.3 健康检查与告警规则

Spring Boot Actuator 的 /actuator/health 端点支持 Readiness 和 Liveness 探针。配合 Prometheus Alertmanager 可以设置以下关键告警:

groups:
  - name: spring-boot-alerts
    rules:
      - alert: HighErrorRate
        expr: |
          rate(http_server_requests_seconds_count{status=~"5.."}[5m])
          /
          rate(http_server_requests_seconds_count[5m]) > 0.05
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "服务 {{ $labels.application }} 错误率超过 5%"

      - alert: SlowResponses
        expr: |
          histogram_quantile(0.99,
            rate(http_server_requests_seconds_bucket[5m])
          ) > 3
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "服务 {{ $labels.application }} P99 延迟超过 3 秒"

      - alert: InstanceDown
        expr: up{application="order-service"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "订单服务实例 {{ $labels.instance }} 已下线"

Grafana监控仪表盘

六、常见问题排查指南

6.1 Trace 信息未出现在日志中

确认以下配置是否正确:

  • 检查 logging.pattern 中是否包含 [%X{traceId:-}]
  • 确认添加了 micrometer-tracing-bridge-otel 依赖(不要遗漏 bridge)
  • 验证是否使用了异步日志框架(如 Log4j2 Async Appender),MDC 在异步线程中默认不会传播,需要显式设置:
@Bean
public Executor traceAwareExecutor() {
    return new TraceAwareExecutor();
}

@Bean(name = "taskExecutor")
public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
    return executor;
}

6.2 OTLP 导出失败

如果 OpenTelemetry Collector 不可达,Spring Boot 默认会静默丢弃 Span 以避免影响业务逻辑。排查步骤:

  1. 检查 Collector 的端口是否开放:curl http://localhost:4318/v1/traces
  2. 确认 Collector 的 Pipeline 配置正确:需要包含 traces Pipeline
  3. 开启调试日志:logging.level.io.opentelemetry=DEBUG
  4. 使用 SimpleSpanProcessor 替代 BatchSpanProcessor 进行本地验证(生产环境不要用)

总结

Spring Boot 3.x 的 Observability 体系是一次彻底的架构升级。从 Spring Cloud Sleuth 到 Micrometer Tracing + OpenTelemetry,不仅是库的替换,更是从”指标和追踪各自为战”到”统一 Observation 模型”的理念变革。通过本文介绍的集成方案,你可以在 30 分钟内搭建起包含指标采集、分布式追踪、日志关联的全栈可观测性平台。

最后,记住可观测性的核心原则:

  • 三大支柱缺一不可:指标(Metrics)回答”发生了什么”,追踪(Tracing)回答”为什么会发生”,日志(Logging)回答”具体发生了什么”
  • 标准化优于自定义:优先使用 W3C TraceContext、OTLP 协议等开放标准
  • 高基数标签是灾难:避免将 userId、orderId 等值作为指标标签
  • 从第一天就建立可观测性:事后补课的成本是指数级增长的

希望本文能帮助你快速上手 Spring Boot 3.x 的可观测性体系。如果你在生产环境中遇到任何问题,欢迎在评论区交流讨论。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » Spring Boot 3.x Observability实战:Micrometer、Tracing与OpenTelemetry全栈监控指南
分享到: 更多 (0)