devops系列(五) Prometheus + Grafana:让系统状态一目了然

张开发
2026/4/14 15:30:17 15 分钟阅读

分享文章

devops系列(五) Prometheus + Grafana:让系统状态一目了然
Prometheus Grafana让系统状态一目了然一、问题引入服务挂了用户比你先知道说实话这事儿搁谁身上都尴尬。上个月咱们一个 Spring Boot 项目上线刚开始一切正常我还美滋滋地觉得稳了。结果某天早上刚到公司产品经理就甩过来一张截图“用户说页面打不开了你赶紧看看。”我一查日志好家伙服务凌晨两点就 OOM 了硬是挂了六个小时没人发现。更扎心的是老板后来问我现在系统负载多少CPU 占用高不高我支支吾吾说了句“应该……还行吧”——你懂的那种心虚感简直想找个地缝钻进去。说白了没有监控的系统就像闭着眼睛开车。路面平不平、前面有没有坑全靠猜。用户成了你的人肉监控这谁顶得住所以今天咱们就来聊聊怎么用Prometheus Grafana这套组合拳把系统状态看得清清楚楚。二、方案分析监控这件事到底该咋做2.1 可观测性三支柱Metrics、Logging、Tracing在动手之前咱们先理清楚一个概念可观测性Observability。江湖上流传着它的三支柱支柱管什么打个比方Metrics系统的量化指标比如 CPU、内存、QPS体温计、血压仪Logging离散的事件记录比如错误日志、访问日志病历本Tracing请求在微服务间的完整调用链路快递物流跟踪这三兄弟各司其职缺一不可。咱们今天重点聊的是Metrics因为它最直观、最适合做实时监控和告警。Logging 和 Tracing 也很重要但那是另外的故事了。2.2 为什么选 Prometheus Grafana市面上监控方案不少我一开始也纠结过Zabbix老牌选手功能全但配置复杂风格偏传统运维对云原生支持一般。ELK 栈日志分析无敌但做实时指标监控和告警差点意思。Prometheus Grafana云原生时代的标配Pull 模型简单直接Grafana 仪表盘又好看社区生态还特别丰富。我最后选了 Prometheus Grafana原因很简单轻量、好搭、好看、社区卷。Spring Boot 还有 Micrometer 原生支持几乎是开箱即用。三、Prometheus 架构它到底怎么工作的很多同学刚接触 Prometheus 的时候会被一堆名词绕晕。咱们换个接地气的说法你可以把 Prometheus 想象成一家体检中心Exporter数据采集员跑到各个服务器、应用里把心率、血压、血糖这些数据测出来。Prometheus Server体检中心总部定时把各采集员的数据拉回来存到自己的档案柜里。TSDB档案柜专门存时间序列数据的地方按时间顺序归档。Alertmanager急诊室发现指标异常了负责打电话、发微信通知你。整个流程就是Exporter 暴露指标 → Prometheus 定时去拉 → 存进 TSDB → 发现异常就交给 Alertmanager 告警。简单吧咱们接下来一步一步搭起来。四、实战监控一个 Spring Boot 应用4.1 第一步Spring Boot 暴露指标MicrometerSpring Boot 2.x 之后内置了 Micrometer咱们只需要引入spring-boot-starter-actuator和micrometer-registry-prometheus。pom.xml 里加这两段!-- 开启 actuator 端点 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!-- 把指标转成 Prometheus 格式 --dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-registry-prometheus/artifactId/dependencyapplication.yml 里开一下端口management:endpoints:web:exposure:include:prometheus,health,info# 关键把 prometheus 端点暴露出来endpoint:prometheus:enabled:true启动应用后访问http://localhost:8080/actuator/prometheus就能看到一堆类似这样的指标jvm_memory_used_bytes{areaheap,idG1 Old Gen,} 1.2345678E7 http_server_requests_seconds_count{uri/api/users,} 42.0关键点Micrometer 会自动帮你收集 JVM、HTTP 请求、线程池等指标而且格式就是 Prometheus 能直接读的。这一步几乎零成本。4.2 第二步Prometheus 配置拉取任务接下来让 Prometheus 知道去哪拉数据。写一个简单的prometheus.ymlglobal:scrape_interval:15s# 每隔15秒去采一次数据evaluation_interval:15s# 每隔15秒评估一次告警规则scrape_configs:-job_name:spring-boot-appmetrics_path:/actuator/prometheusstatic_configs:-targets:[localhost:8080]# 你的应用地址为什么要设置scrape_interval太短了Prometheus 自己压力大太长了告警延迟高。15 秒是社区比较通用的默认值生产环境可以根据实际情况调。启动 PrometheusDocker 方式最方便dockerrun-d\-p9090:9090\-v$(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml\prom/prometheus打开http://localhost:9090在 Expression 里输入jvm_memory_used_bytes能看到数据就说明连上了。4.3 第三步Grafana 配置仪表盘Prometheus 自带的 Web UI 能查数据但真的不好看。Grafana 就是来解决这个问题的。启动 Grafanadockerrun-d-p3000:3000 grafana/grafana默认账号密码都是admin登录后做两件事1. 添加数据源左侧菜单 → Connections → Data sources → Add data source选 PrometheusURL 填http://host.docker.internal:9090如果你也是 Docker 启动的点 Save Test变绿就是成功了2. 创建仪表盘Grafana 社区有很多现成的模板比如搜 “JVM Micrometer”ID 是 4701导入后稍微改改就能用。如果你自己想配一个 HTTP QPS 面板PromQL 可以这么写rate(http_server_requests_seconds_count[1m])意思是计算过去 1 分钟内每秒平均请求数。rate()是 PromQL 里最常用的函数之一看 QPS 必备。五、常用指标讲解这些数字到底代表啥刚开始看指标的时候我也是一脸懵。后来用多了发现其实就关注这么几类5.1 机器层面指标PromQL 示例说明CPU 使用率100 - (avg by (instance) (irate(node_cpu_seconds_total{modeidle}[5m])) * 100)用 100 减去空闲 CPU 占比内存使用率(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100已用内存 / 总内存磁盘使用率(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100注意过滤掉fstypetmpfs小提示机器层面的指标需要装Node Exporter它是 Prometheus 官方提供的系统数据采集员。5.2 应用层面JVM / HTTP指标PromQL 示例说明JVM 堆内存使用jvm_memory_used_bytes{areaheap}看老年代和新生代分别占多少GC 次数increase(jvm_gc_pause_seconds_count[1m])每分钟 GC 暂停次数太频繁就要警惕了HTTP QPSrate(http_server_requests_seconds_count[1m])每秒请求量HTTP 平均响应时间rate(http_server_requests_seconds_sum[1m]) / rate(http_server_requests_seconds_count[1m])总耗时 / 总次数错误率rate(http_server_requests_seconds_count{status~5..}[1m])5xx 错误每分钟的变化率这些指标往 Grafana 仪表盘上一摆系统健不健康瞟一眼心里就有数了。六、告警规则别等用户来找你监控看了下一步就是告警。Prometheus 的告警规则写在alerts.yml里下面给你一个我实际在用的例子groups:-name:system-alertsrules:# CPU 使用率超过 80%持续 5 分钟才告警-alert:HighCPUUsageexpr:100-(avg by (instance) (irate(node_cpu_seconds_total{modeidle}[5m])) * 100)80for:5mlabels:severity:warningannotations:summary:CPU 使用率过高description:实例 {{ $labels.instance }} 的 CPU 使用率已超过 80%持续 5 分钟当前值{{ $value }}%# 内存使用率超过 85%持续 3 分钟告警-alert:HighMemoryUsageexpr:(node_memory_MemTotal_bytes-node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 10085for:3mlabels:severity:criticalannotations:summary:内存使用率过高description:实例 {{ $labels.instance }} 的内存使用率已超过 85%当前值{{ $value }}%关键点解读for: 5m这个特别重要。它表示指标持续超过阈值 5 分钟才触发告警避免抖动导致的狼来了。{{ $labels.instance }}和{{ $value }}告警信息里的变量能让你一眼看出是哪个机器、当前值是多少。写完之后记得在prometheus.yml里引用这个规则文件rule_files:-alerts.yml告警触发后Prometheus 会把消息推给 AlertmanagerAlertmanager 再负责通过钉钉、飞书、邮件等方式通知你。Alertmanager 的配置这里就不展开了感兴趣的话咱们下回单独聊。七、踩坑记录这些坑我替你踩过了光讲顺利的没意思来聊聊我真实踩过的坑。坑一指标 Cardinality 爆炸Prometheus 内存直接飙高有一次我在 HTTP 指标里把用户 ID 也作为 label 加进去了比如http_requests_total{user_id10001,uri/api/order} http_requests_total{user_id10002,uri/api/order}结果用户一多这个指标的时间序列数量指数级增长。Prometheus 内存从 2G 直接飙到 16G最后 OOM 了。教训label 的值必须是有限且可控的。像用户 ID、订单号这种高基数字段千万不能往 Metrics label 里塞。需要这种维度分析请走 Logging 或 Tracing。坑二Grafana 数据源配成了localhost:9090结果连不上我一开始在 Docker 里跑 Grafana数据源 URL 填了http://localhost:9090怎么测都是红的。后来才反应过来Grafana 也在 Docker 容器里它的localhost是它自己不是宿主机器。改成http://host.docker.internal:9090Mac/Windows或者宿主机的 IP 地址才解决。教训容器网络里的localhost是个坑跨容器通信要用容器网络名或宿主机 IP。坑三告警规则语法写错死活不生效有回我把alerts.yml写成了rules:alert:HighCPUUsageexpr:...注意看rules:后面直接跟alert:少了前面的-。Prometheus 启动没报错但规则就是加载不出来。后来用http://localhost:9090/rules页面检查才发现列表是空的。教训YAML 格式严格尤其是列表和缩进。写完后一定要去 Prometheus 的 Rules 页面确认加载成功。八、验证与总结咱们来回顾一下这套方案搭下来你得到了什么Spring Boot 应用通过 Micrometer 自动暴露 JVM、HTTP 等指标Prometheus定时拉取并存储这些数据Grafana把枯燥的数字变成直观的仪表盘Alertmanager在异常时第一时间通知你。从此老板再问系统负载多少你可以淡定地打开 Grafana指着仪表盘说“CPU 35%内存 60%QPS 稳定在 1200一切正常。”那种心里有底的感觉真的不一样。当然监控不是万能的。它帮你看见问题但怎么解决问题还得靠你的经验和代码质量。而且告警规则也要不断优化太松了漏报太紧了告警疲劳这个度需要慢慢摸索。写在最后你在实际项目里是怎么做监控的有没有被半夜的告警短信吵醒过或者你有什么更优雅的告警降噪方案欢迎在评论区聊聊咱们一起进步

更多文章