监控不是堆一个 Dashboard
很多项目的“监控”止步于 Grafana 上挂一个看着很专业的 JVM 面板,真出问题时却没人看得懂:CPU 曲线很平稳,接口却超时;堆内存没满,服务却疯狂 Full GC。问题通常不在 Grafana,而在指标本身——只采了默认指标,没有业务维度的分位数、错误率和饱和度。
Prometheus + Grafana 的正确用法是:先定义要回答的问题(QPS 多少、P99 多少、错误率多少、资源还剩多少),再决定采哪些指标、配什么告警。
暴露指标:Actuator + Micrometer
Spring Boot 3.3/3.4 只需要两个依赖:spring-boot-starter-actuator 和 micrometer-registry-prometheus。
management:
endpoints:
web:
exposure:
include: health,info,prometheus,metrics
endpoint:
health:
probes:
enabled: true
metrics:
tags:
application: ${spring.application.name}
distribution:
percentiles-histogram:
http.server.requests: true
prometheus:
metrics:
export:
enabled: true
percentiles-histogram 是关键。不开启时,Micrometer 只输出 _count、_sum、_max,histogram_quantile 算不出 P99;开启后会额外输出 _bucket,才能做分位数和 SLO 统计。代价是时间序列数量增加,桶不要设得太密。
management.server.port 如果单独开了管理端口,Prometheus 抓取地址要跟着改。生产环境不要把 actuator 直接暴露在公网,至少用网络策略限制来源,或者加一层 Basic Auth。
Prometheus 抓取与告警
静态配置适合小规模,K8s 里更常用注解发现或 ServiceMonitor:
scrape_configs:
- job_name: spring-boot
metrics_path: /actuator/prometheus
scrape_interval: 15s
static_configs:
- targets: ['order-service:8080']
告警规则要围绕“用户能感知的指标”,而不是“CPU 超过 80%”这种间接指标:
groups:
- name: spring-boot-slo
rules:
- alert: HighHttp5xxRate
expr: |
sum by (application) (rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/
sum by (application) (rate(http_server_requests_seconds_count[5m]))
> 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.application }} 5xx 比例超过 5%"
for 很重要,没有它,一次发布重启带来的毛刺就会触发告警。告警发到哪里由 Alertmanager 负责,Prometheus 自己不发通知,这一步经常被漏掉。
几个真正有用的 PromQL
指标名和标签要先对齐:Boot 3 + Micrometer 的 HTTP 计时器叫 http_server_requests_seconds,常用标签是 application、uri、status、method。下面几条查询都基于这套标签。
接口 QPS:
sum by (application) (rate(http_server_requests_seconds_count[1m]))
P99 耗时,依赖 _bucket 序列:
histogram_quantile(0.99,
sum by (le, application) (
rate(http_server_requests_seconds_bucket[5m])
)
)
堆内存使用率:
sum by (application) (jvm_memory_used_bytes{area="heap"})
/ sum by (application) (jvm_memory_max_bytes{area="heap"})
连接池饱和度,接近 1 就该扩容或查慢 SQL:
hikaricp_connections_active / hikaricp_connections_max
GC 平均停顿:
rate(jvm_gc_pause_seconds_sum[5m]) / rate(jvm_gc_pause_seconds_count[5m])
看这些指标时有个基本原则:先看用户侧(QPS、错误率、P99),再看资源侧(CPU、内存、连接池)。资源指标正常但 P99 上涨,问题多半在依赖、锁或者 GC;资源指标先恶化,再顺着饱和点往下查。Grafana 面板不用追求多,一张黄金指标图加一张 JVM 图,足够覆盖大部分故障。指标量太大时,用 metric_relabel_configs 丢掉不需要的 series,别让每个面板都扫全量数据。
常见坑
坑一:/actuator/prometheus 返回 404。 要么没引 micrometer-registry-prometheus,要么端点没在 exposure.include 里,要么访问的是管理端口而不是业务端口。
坑二:histogram_quantile 返回 NaN。 没有 _bucket 序列,通常是没开 percentiles-histogram。另外 rate 的窗口要大于抓取间隔的 4 倍,15 秒抓取配 [1m] 才稳。
坑三:URI 标签基数爆炸。 http_server_requests_seconds 带 uri 标签,正常应该是 /orders/{id} 这种模板。但如果 404 请求把原始路径带进来,或者代码里拼接了 ID,序列数会迅速涨到几十万。用 MeterFilter 过滤或改写标签。
坑四:把实例级指标直接求和。 多副本时 sum 会掩盖单实例异常。排查时要按 instance 拆开看,别只看总量。
坑五:Target 显示 DOWN。 先 curl 目标地址确认能返回指标,再查服务发现、端口、防火墙和 Prometheus 的 up 指标,不要一上来就怀疑 Grafana。
坑六:Grafana 面板用了旧指标名。 从 Boot 2 升到 Boot 3,部分 HTTP 和 JVM 指标的标签有调整,旧面板会直接显示 No data。升级时先对比 /actuator/prometheus 的实际输出,再改面板,别急着怀疑采集链路。
排查步骤
curl http://服务:端口/actuator/prometheus确认指标能出来,关键字搜http_server_requests。- 打开 Prometheus 的 Targets 页面,确认该实例是 UP,没有报权限或超时;顺便看
scrape_duration_seconds,接近抓取间隔说明指标太多或应用响应太慢。 - 在 Prometheus 表达式浏览器里单独跑一次 P99 查询,确认不是 Grafana 变量的问题。
- 检查告警规则的
expr和for,用promtool check rules做语法校验。 - 最后看 Alertmanager 有没有收到告警,很多“告警没发出来”只是通知链路没配。
评论