Day20 Spring Boot Actuator监控体系:生产可观测性标配 专栏《Java后端工程师进阶之路》从CRUD到AI工程师的完整跃迁路径Day 20/ 90从服务挂了才发现到服务还没挂就知道差的不是运气是一套像样的监控。场景再现线上交易系统响应超时CPU飙到90%。jstack抓了一堆线程快最后发现是一个第三方回调接口挂了线程池全堵在那儿等超时。答案很扎心——系统没有暴露任何可观测的指标。就像一个黑箱外面的人只能通过坏了没来判断好坏。后来全面接入了 Spring Boot Actuator配合 Prometheus Grafana 搭了一套监控体系。从那以后服务还没挂钉钉上就先弹告警了。二、Actuator 到底是个什么东西Actuator 是 Spring Boot 官方提供的生产级监控模块。它用一句话概括就是给你的 Spring Boot 应用装上各种传感器把 JVM、Web 容器、数据库连接、自定义业务指标全部暴露出来供外部监控系统消费。一句话记住它的定位Actuator 不是监控系统它是被监控的那一端。它负责生产数据Prometheus 负责采集数据Grafana 负责展示数据。2.1 快速接入Spring Boot 2.x / 3.x 项目加一个依赖就够了!-- pom.xml -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency什么配置都不写启动项目访问 http://localhost:8080/actuator你会看到所有默认暴露的端点{ _links: { self: { href: http://localhost:8080/actuator, templated: false }, health: { href: http://localhost:8080/actuator/health, templated: false }, health-path: { href: http://localhost:8080/actuator/health/{*path}, templated: true } } }默认只暴露了health这一个端点——这是 Spring Boot 的安全策略细节信息不能随便给人看。2.2 端点全家福Actuator 自带了 20 个内置端点我挑几个你一定会用到的端点作用一句话讲清楚/health健康检查服务还活着吗数据库连得上吗Redis通吗/metrics指标体系JVM内存用了多少HTTP请求QPS多少/info应用信息版本号、构建时间、Git Commit Hash/env环境变量当前生效的配置项有哪些值是多少/loggers日志级别不重启就能调日志级别/threaddump线程转储等同于jstack在线看线程状态/heapdump堆转储等同于jmap下载.hprof文件分析/beansBean清单所有Spring Bean以及它们的依赖关系/mappings请求映射所有RequestMapping的路由信息这些端点咋一看像是调试工具合集但当你把它们接入监控系统之后价值就完全不一样了。三、实战一健康检查——不只是活没活着很多团队把/actuator/health配在 K8s 的 Liveness Probe 上返回 200 就认为服务健康。但这远远不够。看一个真实场景你的服务启动正常HTTP 端口也在监听但 Redis 连接池因为网络抖动全部断开。这时候/health如果只返回{status: UP}你的负载均衡器会继续把流量打过来然后所有需要 Redis 的请求全部报错。正确的做法启用详细健康检查。# application.yml management: endpoint: health: show-details: always # 生产环境建议用 when-authorized show-components: always endpoints: web: exposure: include: health,metrics,prometheus然后在项目中引入对应的 HealthIndicator// 这是 Spring Boot 自带的引入 starter-data-redis 后自动注册 // 你也可以自定义 import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; Component public class PaymentGatewayHealthIndicator implements HealthIndicator { Override public Health health() { // 模拟检查第三方支付网关连通性 boolean reachable checkPaymentGateway(); if (reachable) { return Health.up() .withDetail(gateway, alipay) .withDetail(latency_ms, 120) .build(); } return Health.down() .withDetail(gateway, alipay) .withDetail(error, Connection timeout after 5000ms) .build(); } private boolean checkPaymentGateway() { // 实际项目中这里发一个 HTTP HEAD 请求探测 return true; } }接入后/actuator/health的返回就会是这样{ status: UP, components: { db: { status: UP, details: { database: MySQL, validationQuery: isValid() } }, redis: { status: UP, details: { version: 7.0.15 } }, paymentGateway: { status: UP, details: { gateway: alipay, latency_ms: 120 } }, diskSpace: { status: UP, details: { total: 500123123712, free: 320456789012 } } } }这下运维同事就不用来问你Redis 是不是挂了——看一眼健康检查页面哪个组件出了问题一目了然。关键知识点show-details: always在生产环境有安全风险暴露内部组件细节建议用when-authorized配合 Spring Security 做身份校验自定义 HealthIndicator 一定要快速返回 1秒不要在健康检查里做耗时操作K8s Readiness Probe 比 Liveness Probe 更适合依赖健康检查——服务活着但暂时不能接流量四、实战二Metrics 指标——给系统装上仪表盘/actuator/metrics是 Actuator 最值钱的功能。它基于Micrometer这个门面框架屏蔽了下游监控系统的差异——你用 Prometheus、InfluxDB、Datadog 还是 Graphite代码完全不用改。4.1 看一眼默认指标访问/actuator/metrics会列出所有指标名称不直接显示值。要查看具体某个指标需要加名字GET /actuator/metrics/jvm.memory.used返回{ name: jvm.memory.used, measurements: [ { statistic: VALUE, value: 2.3846912E8 } ], availableTags: [ { tag: area, values: [heap, nonheap] }, { tag: id, values: [G1 Survivor Space, G1 Eden Space, ...] } ] }这里插一句JVM 领域的几个核心指标你心里要有数指标前缀关注什么告警阈值建议jvm.memory.used/jvm.memory.max堆内存使用率 85% 告警jvm.gc.pauseGC 暂停时间P99 200ms 告警jvm.threads.live活跃线程数持续增长 500 排查http.server.requestsHTTP 请求延迟/错误率P99 1s 或错误率 1%tomcat.threads.busyTomcat 工作线程繁忙度 80% 准备扩容4.2 自定义业务指标系统指标看完你自己的业务指标更重要。比如支付接口的调用量、成功率、耗时。import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.web.bind.annotation.*; import java.util.concurrent.TimeUnit; RestController RequestMapping(/api/payment) public class PaymentController { private final MeterRegistry meterRegistry; private final Timer paymentTimer; private final Counter paymentSuccessCounter; private final Counter paymentFailCounter; public PaymentController(MeterRegistry meterRegistry) { this.meterRegistry meterRegistry; // Timer 自动记录调用次数、总耗时、最大耗时 this.paymentTimer Timer.builder(business.payment.request) .description(支付接口请求耗时) .publishPercentileHistogram(true) // 启用直方图支持 P50/P90/P99 .register(meterRegistry); // Counter 只增不减 this.paymentSuccessCounter Counter.builder(business.payment.result) .tag(status, success) .register(meterRegistry); this.paymentFailCounter Counter.builder(business.payment.result) .tag(status, fail) .register(meterRegistry); } PostMapping(/pay) public String pay(RequestBody PayRequest request) { return paymentTimer.record(() - { try { // 业务逻辑... String result doActualPayment(request); paymentSuccessCounter.increment(); return result; } catch (Exception e) { paymentFailCounter.increment(); throw e; } }); } private String doActualPayment(PayRequest request) { // 实际支付逻辑 return success; } }这里有三个常用的 Micrometer 指标类型你必须掌握Counter只增不减的计数器。适合计次——请求量、错误数、成功数Gauge瞬时值可升可降。当前连接数、队列长度、缓存命中率Timer记录耗时 调用次数。接口延迟、数据库查询耗时// Gauge 示例监控线程池队列长度 Gauge.builder(threadpool.queue.size, threadPoolExecutor, ThreadPoolExecutor::getQueueSize) .register(meterRegistry);4.3 关键配置别让指标成为性能瓶颈Actuator 默认配置不一定适合生产环境下面这个配置我每个项目都会调management: metrics: export: prometheus: enabled: true step: 30s # 指标推送间隔默认1分钟 distribution: percentiles-histogram: http.server.requests: true # 开启 HTTP 请求延迟直方图 slo: http.server.requests: 50ms, 100ms, 200ms, 500ms, 1s # 自定义延迟分桶 endpoints: web: exposure: include: health,metrics,prometheus几个踩过的坑percentiles-histogram会大幅度增加指标数据的基数每个分桶值都产生一套数据Prometheus 存储压力会上去。如果指标量太大建议用slo指定有限分桶而不是全开step设太短如 5sPrometheus 抓取频率跟不上会导致数据重复或丢失不要把 Actuator 端口直接暴露到公网至少加一层 Spring Security 或独立管理端口五、实战三Prometheus Grafana 构建监控大屏Actuator 暴露指标只是第一步真正让数据活起来的是 Prometheus Grafana。5.1 接入 Prometheusdependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /dependency然后访问/actuator/prometheus你会看到标准 Prometheus 格式的指标数据# HELP jvm_memory_used_bytes The number of used bytes # TYPE jvm_memory_used_bytes gauge jvm_memory_used_bytes{areaheap,idG1 Eden Space,} 1.2345678E8 jvm_memory_used_bytes{areaheap,idG1 Survivor Space,} 1.048576E7 ... # HELP business_payment_request_seconds_max # TYPE business_payment_request_seconds_max gauge business_payment_request_seconds_max{applicationpayment-service,} 0.5235.2 Prometheus 抓取配置# prometheus.yml scrape_configs: - job_name: payment-service metrics_path: /actuator/prometheus scrape_interval: 30s static_configs: - targets: [localhost:8080] labels: application: payment-service env: production5.3 Grafana 大屏Grafana 里导入 JVM 监控模板Dashboard ID: 4701 或者 1285610分钟就能搭出这样的效果用文字描述左上服务实例数、运行时长、CPU使用率、堆内存使用率数字面板中间GC 暂停时间趋势图、GC 次数/频率下排HTTP QPS P99延迟曲线、错误率趋势右侧自定义业务指标支付量、成功率5.4 告警规则光看不够还要配告警。Prometheus 告警规则示例# alerts.yml groups: - name: spring-boot-alerts rules: - alert: HighHeapMemoryUsage expr: sum(jvm_memory_used_bytes{areaheap}) / sum(jvm_memory_max_bytes{areaheap}) 0.85 for: 5m labels: severity: warning annotations: summary: 堆内存使用率超过85% - alert: HighErrorRate expr: rate(http_server_requests_seconds_count{status~5..}[5m]) / rate(http_server_requests_seconds_count[5m]) 0.01 for: 3m labels: severity: critical annotations: summary: HTTP 5xx 错误率超过1%再配合 Alertmanager 把告警推到钉钉/企业微信/飞书这样凌晨三点的电话就换成了一条消息推送。六、实战四自定义 Endpoint——暴露你想要的任何信息Actuator 不仅提供了 20 个内置端点还允许你自定义端点。比如你想暴露当前系统的业务配置快照import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.stereotype.Component; import java.util.Map; Component Endpoint(id businessConfig) public class BusinessConfigEndpoint { ReadOperation public MapString, Object getConfig() { return Map.of( maxOrderAmount, 50000, supportedPaymentMethods, new String[]{alipay, wechat, unionpay}, maintenanceMode, false, currentVersion, 3.2.1 ); } }别忘了在配置里暴露它management: endpoints: web: exposure: include: health,metrics,prometheus,businessConfig现在访问/actuator/businessConfig直接拿到业务配置快照。这个能力在排查问题时特别有用——不用翻代码、不用查数据库一个 HTTP 请求就知道当前系统以什么参数在运行。Endpoint还支持WriteOperation和DeleteOperation可以实现运行时动态调整参数。比如你做了一个特性开关线上出了问题需要紧急关闭某个功能直接调端点就行不用重启。七、生产环境 Checklist这套监控体系上线前对照下面这个清单逐项检查1. 安全防护生产环境不要用show-details: always改用when-authorizedActuator 端点加 Spring Security 认证或者配置独立管理端口management.server.port: 8081/heapdump和/threaddump生产环境单独鉴权不要和/health混在一起2. 性能考量percentiles-histogram按需开启不要为了好看全开——Prometheus 的时序数据量会暴涨自定义 HealthIndicator 的方法必须快速返回 1s不要在里面做 HTTP 调用等阻塞操作。如果必须检查远程服务用异步 缓存结果检查/actuator/metrics返回的指标列表删除不需要的指标以减少内存占用3. 运维配套Grafana 大屏至少包含JVM 堆内存、GC 暂停、HTTP QPS/P99、5xx 错误率、自定义核心业务指标告警规则至少覆盖堆内存 85%、错误率 1%、实例宕机编写运维 Runbook每个告警对应的排查步骤好比堆内存高 →jmap -histo查大对象 → 定位代码很多团队把监控当成锦上添花的东西项目赶进度的时候最先砍掉的就是它。但我的经验是你花在监控上的每一分钟都会在凌晨三点加倍还给你。Actuator 的接入成本极低——加一个依赖、写几行配置、挂一个 Grafana 模板半天就能搞定。但它带来的价值是持续性的你不再靠用户投诉来发现故障不再靠猜来定位问题。你看得到系统的心跳、呼吸、每一次抖动。这就是可观测性的本质不是出了问题才知道而是提前看到风险在酝酿。金句好的监控不会让你的系统不挂但会让你在它挂之前就知道它快撑不住了。下篇预告Day 21《Spring事件机制观察者模式在企业级解耦中的应用》——你会发现原来不用 MQ、不用 RPCSpring 自己就藏着一个优雅的组件解耦利器。明天见。