在微服务架构日益普及的今天,可观测性(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.id和thread.name— 执行线程信息class和method— 被追踪的方法签名exception.type和exception.message— 异常堆栈(如果有)http.method和http.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 }} 已下线"

六、常见问题排查指南
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 以避免影响业务逻辑。排查步骤:
- 检查 Collector 的端口是否开放:
curl http://localhost:4318/v1/traces - 确认 Collector 的 Pipeline 配置正确:需要包含 traces Pipeline
- 开启调试日志:
logging.level.io.opentelemetry=DEBUG - 使用 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 的可观测性体系。如果你在生产环境中遇到任何问题,欢迎在评论区交流讨论。
汤不热吧