ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Spring 中的可观测性:集成 Micrometer、OpenTelemetry 与 Tracing

2026/9/14 21:46:19 拓冰建站 浏览量
Spring 中的可观测性:集成 Micrometer、OpenTelemetry 与 Tracing Spring 中的可观测性集成 Micrometer、OpenTelemetry 与 Tracing1. 一次线上事故慢调用为何查不出根源假设你在电商公司负责订单服务。一天下午用户反馈“提交订单很慢”你打开监控大盘看到订单接口的平均响应时间从 200ms 涨到了 2 秒。但你面对三个割裂的系统监控大盘显示CPU、内存、QPS但看不到具体是哪个环节变慢。日志系统里有报错但每条日志都是独立的像散落的拼图无法串联起一次请求的完整路径。你尝试用 Arthas 在线排查但生产环境不允许随意 attach。你花了两个小时最终发现是下游的“库存服务”在高峰期出现了慢 SQL。但如果当时就能看到一条完整链路——从“订单接口”到“库存服务”再到“MySQL”每个环节耗时一目了然问题会在一分钟内暴露。这正是可观测性要解决的问题。它不是某一个工具而是一种能力让我们能从系统外部通过指标Metrics、日志Logs和追踪Traces这三个维度重建系统内部发生的事。2. 先记住一个最小模型三个支柱与一条链路2.1 一句话模型可以把可观测性理解为给每一次外部请求发一张“体检表”同时在每个服务门口装上“计数器”。“体检表”记录请求经过的每个节点以及耗时追踪计数器统计 QPS、错误率等指标而日志则是“体检表”上的详细备注。2.2 三个维度如何分工维度回答的问题典型工具指标 (Metrics)系统整体健康如何QPS、延迟、错误率Micrometer、Prometheus日志 (Logs)具体某条记录说过什么错误堆栈Logback、ELK追踪 (Traces)一次请求内部经过哪些服务哪里慢OpenTelemetry、Jaeger、Zipkin2.3 拆解角色谁负责什么要把观测能力集成进 Spring 应用你需要四个角色应用代码你的 Spring Boot 服务是数据的源头。监控 SDKMicrometer负责在应用内采集指标数据暴露出一个/actuator/metrics端点。追踪 SDKOpenTelemetry负责生成、传播 trace ID 和 span ID并把这些数据发送给后端存储。后端系统Prometheus、Jaeger、日志系统负责存储、查询、展示数据。2.4 一次请求会怎样流转先看一个文本时序图感受一下完整流程用户 -- Spring Boot 应用 1. 用户发起 /order 请求 2. 应用入口Controller被拦截OpenTelemetry 生成 traceIdabc, spanId001 3. 应用调用 RestTemplate 请求库存服务SDK 自动注入 trace 头 4. 库存服务收到请求解析 trace 头创建子 span 5. 应用内部执行逻辑Micrometer 定时记录耗时到内存 6. 请求返回SDK 把 span 数据异步发送到 Jaeger 7. 运维从 Prometheus 拉取 /actuator/metrics 获取指标数据3. 整体结构从 Micrometer 到 OpenTelemetry 的演进3.1 为什么先提 MicrometerMicrometer 是 Spring Boot 默认的指标门面。它就像 SLF4J 之于日志提供一套统一的 API底层可以对接 Prometheus、Datadog 等数十种监控系统。在 Spring Boot 2.x 和 3.x 中spring-boot-starter-actuator已经集成了 Micrometer你只需要添加一个注册表如micrometer-registry-prometheus就能暴露 Prometheus 格式的指标。3.2 OpenTelemetry 为什么出现Micrometer 只管指标不管追踪。当微服务规模变大你需要跨服务的追踪能力。OpenTelemetry 是一个合并了 OpenTracing 和 OpenCensus 的统一标准它提供了 API、SDK 和协议OTLP支持指标、日志、追踪三种信号。更重要的是它支持自动注入通过 Java Agent可以无侵入地拦截常见的 HTTP 客户端、数据库调用等。3.3 两者如何配合? 并非二选一在 Spring Boot 应用中你完全可以同时使用Micrometer负责记录业务指标如订单数量、库存余量。OpenTelemetry负责生成追踪数据并利用其“指标桥接”能力将 Micrometer 指标通过 OTel 协议导出实现统一投递。4. 核心机制一Micrometer 如何记录指标4.1 核心概念Meter、Registry、TagMicrometer 的基本单元是 Meter可以是一个计数器Counter、一个直方图Timer或一个分布总结DistributionSummary。每个 Meter 都属于一个 Registry注册表Meter 的名字和一组 Tag维度唯一确定一个序列。4.2 Spring Boot 自动装配当你引入spring-boot-starter-actuator和micrometer-registry-prometheus后Spring Boot 自动创建了一个PrometheusMeterRegistry的 Bean并为每个 HTTP 请求自动记录http.server.requests指标。4.3 实际场景为订单接口添加自定义计数器目标统计“创建订单”的成功次数和失败次数并按终端类型App/Web区分。前置环境一个 Spring Boot 3.2 项目已引入 web、actuator、prometheus。完整示例 1计数器importio.micrometer.core.instrument.Counter;importio.micrometer.core.instrument.MeterRegistry;importorg.springframework.web.bind.annotation.*;RestControllerpublicclassOrderController{privatefinalCounterorderSuccess;privatefinalCounterorderFailure;publicOrderController(MeterRegistryregistry){this.orderSuccessCounter.builder(order.create.success).description(number of successful orders).tag(terminal,app).register(registry);this.orderFailureCounter.builder(order.create.failure).description(number of failed orders).tag(terminal,app).register(registry);}PostMapping(/order)publicStringcreateOrder(RequestParamStringuserId){try{// 模拟订单创建逻辑Thread.sleep(100);orderSuccess.increment();returnok;}catch(Exceptione){orderFailure.increment();thrownewRuntimeException(e);}}}关键步骤与预期输出启动应用后请求/order?userId123然后访问http://localhost:8080/actuator/prometheus你会看到类似order_create_success_total{terminalapp,} 1.0。适用场景与易错点计数器适合只增不减的量。这里的错误是把计数器用在需要清零的场景如队列长度应该用 Gauge。另一个易错点是忘记为不同维度分别注册 Meter导致 tag 被覆盖。5. 核心机制二OpenTelemetry 如何实现分布式追踪5.1 核心概念Trace、Span、Context分布式追踪的核心是Trace一次请求的总体链路由多个Span一个具体操作如 HTTP 调用、数据库查询组成。每个 Span 有 ID通过 Trace ID 串联。Context是一个包含 Trace ID 和 Span ID 的上下文随请求在服务间传播。5.2 Spring Boot 集成方式使用 OpenTelemetry Java Agentopentelemetry-javaagent.jar是最简单的集成方式。只需要在 JVM 启动参数中添加-javaagent:path/to/opentelemetry-javaagent.jar并配置导出器如 OTLPAgent 会自动检测 Spring MVC RestTemplate 等库注入追踪。5.3 实际场景手动创建 Span 记录重要业务步骤目标在一个下单接口中手动创建一个 Span 来包裹“扣减库存”的 RPC 调用以观察该步骤耗时。前置环境Spring Boot 3.2引入opentelemetry-api和opentelemetry-sdk并启用自动配置可用 Agent 或 SDK。完整示例 2手动 Spanimportio.opentelemetry.api.trace.Span;importio.opentelemetry.api.trace.Tracer;importorg.springframework.web.bind.annotation.*;RestControllerpublicclassTraceController{privatefinalTracertracer;publicTraceController(Tracertracer){this.tracertracer;}GetMapping(/trace-order)publicStringtraceOrder(RequestParamStringorderId){// 创建手动 spanSpanspantracer.spanBuilder(deduct-inventory).setAttribute(order.id,orderId).startSpan();try(Scopescopespan.makeCurrent()){// 模拟 RPC 调用库存服务Thread.sleep(200);returndone;}catch(InterruptedExceptione){span.recordException(e);thrownewRuntimeException(e);}finally{span.end();}}}关键步骤与预期输出运行应用需配置 OTLP 导出器如本地 Jaeger访问接口后在 Jaeger UI 中你可以看到一条包含deduct-inventoryspan 的 trace耗时约 200ms。适用场景与易错点手动 Span 适合需要细粒度记录业务步骤的场景。易错点忘记try-with-resources关闭 Scope导致上下文泄漏以及异常时不调用recordException导致错误丢失。6. 核心机制三日志关联 — 把日志与 Trace ID 绑定6.1 为什么需要关联没有关联时你只能根据时间模糊地找日志。如果每条日志都自动带上 traceId 和 spanId就能按调用链筛选快速定位问题节点。6.2 MDC 与自动注入在 Spring Boot 中最常见的做法是利用MDCMapped Diagnostic Context。OpenTelemetry 提供了opentelemetry-extension-logback可以把 traceId 注入到 Logback 的 MDC。6.3 实际场景让日志自动携带 traceId目标在 Logback 配置中添加 traceId 到输出模式。前置环境使用 OpenTelemetry Java Agent或在代码中配置MDC处理器。完整示例 3Logback 关联 traceIdconfigurationappendernameCONSOLEclassch.qos.logback.core.ConsoleAppenderencoderpattern%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId%X{trace_id} spanId%X{span_id} - %msg%n/pattern/encoder/appenderrootlevelinfoappender-refrefCONSOLE//root/configuration但要让trace_id出现在 MDC 中需要配置 OpenTelemetry 的 Logback Mdc。步骤如下首先添加依赖(Maven)dependencygroupIdio.opentelemetry.instrumentation/groupIdartifactIdopentelemetry-logback-mdc-1.0/artifactIdversion1.32.0/version/dependency然后在应用启动时配置或通过 Agent 自动配置// 伪代码Agent 会处理此处仅为说明关键步骤与预期输出当你启动应用并访问带追踪的接口控制台日志会出现traceIdabcd1234 spanIdef567890。这样就能在日志平台中按 traceId 搜索。适用场景与易错点这是生产环境排查问题的关键。易错点若无 Agent 或未正确引入扩展MDC 不会自动填充需确认依赖添加位置运行时依赖。7. 完整过程让一次请求走遍三个系统7.1 环境准备为了演示我们准备两个 Spring Boot 应用order-service和inventory-service通过 OpenTelemetry Agent 启动并连接到本地 Jaeger 和 Prometheus。7.2 调用链时序图[order-service] /order/create -- span: HTTP POST /inventory/deduct |-- RestTemplate (自动 span) | |-- DNS解析,连接 -- | |-- 发送HTTP请求 | | 含 trace headers (traceparent) v [inventory-service] 接收请求 -- 解析 trace header生成子span |-- span: 数据库操作 (JDBC) |-- 返回结果 [order-service] -- 记录指标: order.create.success -- 发送日志含 traceId 返回响应给用户7.3 伪代码展示跨服务传播// order-service 中调用 inventory 服务OpenTelemetry 自动注入 headerStringresponserestTemplate.postForObject(http://inventory-service/inventory/deduct,request,String.class);Agent 会在发送请求时自动加入traceparent头而在inventory-service中Agent 自动解析它并创建子 span。8. 设计取舍在指标与追踪间做权衡8.1 用指标还是追踪当你需要长期趋势、告警规则时用指标。当你需要定位单个请求的详细路径时用追踪。指标会牺牲细节换存储量追踪会保留细节但成本更高。8.2 哪个更适合你的场景场景推荐理由服务整体健康监控指标低采样率可长期存储定位慢调用具体节点追踪保留调用链错误率突升指标日志指标告警日志定位具体错误8.3 常见的选择误区“追踪一定会拖垮性能”——事实上0.1%采样率能有可忽略的额外开销且 Agent 自动注册的拦截器很轻量。9. 工程使用从示例到生产9.1 如何配置采样率?生产环境建议设置合理的采样率例如 10% 的流量采样。在 OpenTelemetry SDK 中你可以调整otel.traces.sampler。配置示例JVM 启动参数-javaagent:opentelemetry-javaagent.jar\-Dotel.traces.exporterotlp\-Dotel.exporter.otlp.endpointhttp://jaeger:4317\-Dotel.traces.samplerparentbased_traceidratio\-Dotel.traces.sampler.arg0.19.2 指标与日志平台的整合策略推荐架构应用 - Prometheus (指标) 应用 - Jaeger (追踪) 应用 - ELK/Loki (日志) 通过 traceId 关联查询9.3 生产实践建议为每个应用配置统一的 service.name便于检索。日志中始终保留 traceId便于关联。对关键业务指标设置告警而非只有基础设施指标。定期审查采样率和存储成本。10. 常见误区误区一可观测性就是加一个监控大盘。实际上指标只占三分之一需要日志与追踪配合。误区二指标和追踪用同一套数据就行。它们存储和查询模型不同。误区三只有微服务才需要追踪。单体应用同样可以用追踪定位数据库慢查询。误区四OpenTelemetry 与 Micrometer 只能二选一。它们合作能减少运维复杂度。11. 生产实践建议11.1 分步骤落地路线图先接入 Micrometer 暴露 HTTP 指标配置 Prometheus 监控报警。用 OpenTelemetry Agent 接入追踪先在测试环境验证。引入日志关联把 traceId 打印到日志。逐步接入自定义指标和手动 Span。11.2 工具选型对比功能点MicrometerOpenTelemetry信号类型指标指标、日志、追踪Spring 集成度高高Agent生态对接Prometheus 等OTLP 协议兼容 Jaeger、Zipkin12. 排障清单现象指标端点无法访问 → 检查 actuator 是否暴露 metrics。现象追踪数据为空 → 检查 Agent 是否正确配置导出器查看控制台是否有 OTLP 报错。现象日志无 traceId → 检查是否添加了 Logback 扩展依赖并配置 MDC。现象trace 跨服务分裂 → 检查是否使用了带外请求如 MQ需手动传播。13. 面试/复盘问题说说 Micrometer 与 OpenTelemetry 的关系与区别。如何在 Spring Boot 中集成 OpenTelemetry Agent如何让日志包含 traceId当线上响应变慢时如何利用可观测性快速定位什么是 span什么是 trace14. 总结在 Spring 生态中集成可观测性并不复杂。Micrometer 负责指标OpenTelemetry 负责追踪Logback 等负责日志三者通过 traceId 关联形成完整的观测视图。关键不在于堆砌工具而在于理解每个维度解决的问题并合理运用到自己的架构中。参考资料Spring Boot Actuator 官方文档: https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.htmlMicrometer 官方文档: https://micrometer.io/docsOpenTelemetry Java 文档: https://opentelemetry.io/docs/languages/java/OpenTelemetry Java Agent: https://github.com/open-telemetry/opentelemetry-java-instrumentationLogback 官方文档: https://logback.qos.ch/documentation.html