☰
基于Prometheus、Grafana与Alertmanager的服务器监控报警系统搭建指南
2026/10/12 20:54:55 网站建设 项目流程

1. 项目背景:一个连名字都没起好的项目,为什么会做起来

先说个真实情况:这个项目最初的名字就叫“这是一个标题”——不是故弄玄虚,而是当时确实没想好叫什么,需求也只有一个模糊的方向:给手头几台经常出幺蛾子的服务器加一套能及时发现问题、主动报警的监控。项目从立项到写出第一行代码,只花了不到半小时,因为大家心里都清楚,真正难的不是写代码,而是想明白到底要监控什么、怎么报警才不会吵死人、出了问题怎么才能快速定位。

如果你也维护过三五台服务器、跑过几个业务脚本,大概率体会过这种状态:白天一切正常,凌晨三点某个进程悄悄挂了,第二天用户反馈才被动发现;磁盘空间慢慢被日志撑爆,直到写入失败才惊慌失措;CPU飙到 100%,你登上去的时候已经卡得敲命令都要等半天。这些问题的共性是:没有监控,全靠事后补救。所以这个项目最终要解决的事情很朴素——在一台资源不算宽裕的轻量服务器上,搭一套能采集、能存储、能可视化、能主动通知的监控报警系统,把“被动救火”变成“提前预警”。

整个项目用到的核心组件是 Prometheus、Grafana、Node Exporter 和 Alertmanager,部署方式走的是 Docker Compose,面向的读者是那些已经有了几台服务器、想自己搭监控但还没理清组件关系的人。文章会讲清楚每个组件为什么存在、配置怎么写、踩过哪些坑、报警规则怎么定才不会被误报淹没,最后提供一个可以直接抄作业的完整方案。

2. 整体架构设计:从“一个标题”到一张清晰的组件关系图

2.1 为什么选 Prometheus 这套组合,而不是其他监控方案

在选型之前,我把市面上的方案粗略过了一遍:云厂商自带监控、Zabbix、Prometheus 全家桶。云厂商监控最省事,但每台机器都要装 agent,而且很多指标要额外付费,数据导出也受限,换了云厂商就得重新搞一套,绑定太深。Zabbix 是老牌选手,擅长设备监控和复杂告警,但部署偏重,配置文件写起来不够灵活,图形化展示也不是它的强项。Prometheus 这套组合之所以胜出,核心原因有三个。

第一,采集模型是“拉取式”的。Prometheus 定期主动去抓取目标暴露的指标接口,而不是像传统方案那样由 agent 把数据推给服务端。这个区别在实际运维中很有价值:你只要保证目标端口的 /metrics 接口可访问,Prometheus 这边配置好目标地址就能采集,新增一台机器就是加几行配置的事,不用在每台机器上都折腾安装包和重启服务。第二,指标数据模型统一且自带标签机制。Prometheus 把每一条数据都抽象成指标名加一组键值对标签,比如 cpu_usage{host="node1", core="0"},这种设计让数据查询和聚合变得非常灵活,分组、过滤都靠标签完成,不用像关系型数据库那样写一堆 GROUP BY。第三,生态完整。采集层有各种 Exporter,存储层有自带的时间序列数据库,告警层有独立的 Alertmanager,可视化层可以和 Grafana 无缝对接,每个环节都有成熟方案,不用自己造轮子。

当然这并不代表 Prometheus 没有缺点。它的数据是本地存储在单机上的,想搞长期归档或者大规模集群,还得接远程存储;对于只有几台服务器的小规模场景,这一点根本不是瓶颈,所以选它完全合理。

2.2 四个组件各司其职,谁先启动谁后启动很关键

这套架构里的四个角色,从一开始就要把它们的职责边界划清楚:

  • Node Exporter:跑在被监控机器上,负责收集操作系统层面的原始指标,比如 CPU 使用率、内存占用、磁盘空间、网络流量、文件系统状态,然后通过 HTTP 接口暴露出来。它本身不存储数据,也不做任何判断,只负责“采”和“露”。
  • Prometheus:核心中枢,负责按照配置的规则周期性去各台机器的 Node Exporter 拉取数据,存进自带的时间序列数据库,同时根据告警规则持续做判断,条件满足就生成一条告警事件,推给 Alertmanager。它负责“存”和“判”。
  • Alertmanager:处理 Prometheus 推过来的告警事件,负责去重、分组、静默、限流,然后通过配置好的接收器(邮件、Webhook、钉钉机器人)把消息发出去。它负责“管”和“送”。
  • Grafana:纯粹的数据展示层,从 Prometheus 里读数据,绘制成各种图表和仪表盘,解决“数据看到了但不直观”的问题。它只负责“看”。

这个依赖关系决定了启动顺序:Node Exporter 先起来,Prometheus 等它起来了再去抓;Alertmanager 要先于 Prometheus 的告警规则生效前就位,否则告警推过来没人接;Grafana 最后起,因为它只是去查询别人已有的数据。用 Docker Compose 管理时,虽然依赖设置不能百分之百保证容器内部服务就绪,但配置好 depends_on 至少能控制容器启动的顺序,避免 Prometheus 启动时抓不到目标而报一堆连接错误。

3. 采集端部署与指标解读:Node Exporter 的完整落地细节

3.1 在不同环境下的部署方式对比

Node Exporter 的部署方式取决于被监控机器的情况。如果目标机器本身就是 Docker 环境,直接用一个轻量容器跑起来最省事,但要注意一个小细节:容器里的 Node Exporter 要看到宿主的文件系统和网络状态,必须挂载宿主的 /proc、/sys 等目录,而且网络模式要用 host,这样才能拿到真实的主机指标,而不是容器自己的受限视图。如果目标机器是裸金属或者没有装 Docker 的系统,那直接下载二进制文件用 systemd 托管是最干净的方案。

我在实际部署中更推荐二进制加 systemd 的方式,因为 Node Exporter 本身是一个静态编译的二进制文件,没有任何依赖,拷贝过去就能跑,占用内存大约 20MB,对一个资源紧张的服务器来说几乎可以忽略。systemd 的好处是开机自启、崩溃自动拉起、日志统一管理,这些都是容器方式需要额外配置才能达到的效果。如果你有十台机器,挨个手动部署确实烦人,可以准备一个简单的安装脚本把下载、校验、安装 systemd 单元文件、启动的流程串起来,十几秒就能搞定一台。

3.2 采集到的核心指标都代表什么,怎么用不踩坑

Node Exporter 默认暴露的指标非常多,大多数人并不需要全部关心,重点盯住几类就够用了:

  • node_cpu_seconds_total:这是 CPU 时间的累计值,注意是 counter 类型,一直在增长。使用时必须用 rate() 函数做变化率计算才符合直觉,比如 rate(node_cpu_seconds_total{mode="idle"}[5m]) 表示过去 5 分钟空闲时间的比例,用 1 减去它才是使用率。直接查询原始值会得到一个持续变大的数,没有任何业务含义。
  • node_memory_MemTotal_bytes / node_memory_MemAvailable_bytes:内存总量和可用量,单位是字节。查询时要除以 1024 的三次方换算成 GB,或者直接在 Grafana 里设置单位,否则看到一长串数字很难受。这里有个经典误区:不要用 MemFree 判断内存余量,因为在 Linux 里已经被缓存占用但可以随时释放的内存对应用来说仍然是可用的,MemAvailable 才是内核根据回收成本算出来的真实可用值。
  • node_filesystem_avail_bytes:文件系统可用空间,做磁盘告警时一定要按挂载点分组过滤,把 tmpfs、overlay 这类虚拟文件系统排除掉。我在最开始写磁盘告警规则时没过滤,结果 tmpfs 因为容量小动不动就触发告警,后来才发现这类文件系统增长正常,不应该纳入监控范围。
  • node_network_receive_bytes_total / node_network_transmit_bytes_total:网络收发累计字节数,同样是 counter 类型,必须配合 rate() 才能看出实时速率。判断网卡是否正常时,可以用一个固定窗口观察基线值,如果长时间断崖式下跌,大概率是物理链路或带宽限速出了问题。

这些指标类型是理解 PromQL 查询的基础。简单说,counter 类型的指标只增不减,适合用 rate 求速率;gauge 类型的指标可增可减,直接查询就是当前值。很多查询不达预期,问题都出在把 counter 当 gauge 用。

3.3 Node Exporter 的 systemd 托管配置模板

如果选择二进制部署,systemd 单元文件建议按下面这样写。需要注意的有三点:User 指定为普通用户,不要用 root 跑 Exporter;ExecStart 里加 --collector.systemd 可以额外收集 systemd 服务的状态,方便后面监控某个关键进程是否存活;Restart=always 加上 RestartSec=10 能让进程在意外退出后十秒自动拉起,相当于多了一层保障。

[Unit] Description=Node Exporter Wants=network-online.target After=network-online.target [Service] User=node_exporter Group=node_exporter Type=simple ExecStart=/usr/local/bin/node_exporter --collector.systemd --web.listen-address=:9100 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target

配置好后依次执行 daemon-reload、enable、start,再用 curl 访问本机 9100 端口的 /metrics 接口,看到大量以 node_ 开头的指标就说明采集端已经就绪。如果访问不到,先检查端口有没有被防火墙拦住,再确认进程是否真的起来了,这是最常见的两个原因。

4. Prometheus 配置和告警规则:核心中枢的完整拆解

4.1 采集配置里最容易忽略的细节

Prometheus 的采集配置写在 prometheus.yml 里,构成了整个监控系统的心脏。给出一个可直接使用的例子:

global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: - alertmanager:9093 rule_files: - /etc/prometheus/alerts.yml scrape_configs: - job_name: "node" static_configs: - targets: - 192.168.1.11:9100 - 192.168.1.12:9100 labels: env: production

scrape_interval 是抓取周期,evaluation_interval 是告警规则评估周期,这两个值可以不同,但为了直觉上容易理解,可以设成一样。实际使用中抓取周期不要低于 5 秒,频繁的抓取对目标机器是额外的 I/O 负担,对 Prometheus 本身的存储写入压力也会翻好几倍,收益却很小。labels 的作用不能小看,它可以按环境、可用区、业务线给目标机器打上标签,后面写告警规则和查 Grafana 面板时,这些标签就是分组过滤的维度。

还有一个细节是 job_name 的命名。它会被自动加为指标的一个标签,叫 job。规范命名非常重要,比如把生产环境的 job 起名为 node_prod、预发环境的叫 node_staging,或者干脆用 labels 区分,都可以。否则所有机器在一个 job 下,想单独看某个环境的资源使用情况就要写很多正则过滤器,麻烦得很。

4.2 告警规则的正确写法:从报警疲劳到精准触达

告警规则文件是这套系统里最考验经验的部分。写得好是预警利器,写得差就是通知轰炸器。最经典的三个规则如下:

groups: - name: node_alerts rules: - alert: HostHighCpuUsage expr: (1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) * 100 > 85 for: 10m labels: severity: warning annotations: summary: "{{ $labels.instance }} CPU 使用率过高" description: "当前 CPU 使用率已达 {{ $value | humanizePercentage }},持续时间超过 10 分钟。" - alert: HostDiskAlmostFull expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100 < 15 for: 5m labels: severity: critical annotations: summary: "{{ $labels.instance }} 磁盘空间不足" description: "挂载点 {{ $labels.mountpoint }} 可用空间剩余不足 15%。"

CPU 告警里用 avg by (instance) 是取单台机器所有核心的平均使用率,如果有的机器是多核,某一核跑满但整体没超阈值,这种算法可能看不出问题,这时可以用 max by (instance) 把单核最高使用率暴露出来。用哪个取决于你的业务类型:在线请求类服务看平均更合理,批处理任务看单核更靠谱。

for: 10m 这个参数极易被忽略。它表示指标条件持续满足 10 分钟后才真正触发告警,目的是过滤瞬时抖动。比如某次 GC 导致 CPU 短暂冲高,几秒就恢复了,如果没有 for 条款,系统会立刻告警,造成打扰。但 for 也不能设太长,时间越长发现问题越滞后,一般 5 到 10 分钟是合理区间。

磁盘告警里最关键的是 fstype!~"tmpfs|overlay" 这个正则过滤。tmpfs 是内存文件系统,它的大小本来就是动态的,overlay 是容器镜像层,这类虚拟文件系统不适合参与磁盘告警。去掉这个过滤,你会发现 /run、/var/run 这类小配额目录整天报磁盘满,实际业务磁盘却很健康,告警疲劳就是这么来的。

4.3 Prometheus 查询:请先搞懂 rate、irate 和 increase 的区别

写告警规则和做图表都离不开 PromQL,最常见的三个函数 rate、irate、increase 让很多人犯迷糊,这里一次性说清楚。rate 和 irate 都是计算 counter 类型指标的变化率,区别在于 rate 取的是时间区间内首尾两个点的差值除以区间长度,得到的是这个窗口内的平均速率,曲线平滑;irate 取的是区间内最后两个数据点的差值除以时间间隔,得到的是瞬时速率,曲线毛刺多,对突发情况更敏感。increase 则是计算整个时间区间内 counter 的增长量,相当于把速率乘以了区间长度。

选型建议:做告警规则用 rate,因为告警需要稳定趋势而不是剧烈波动,irate 很容易导致误报;做实时流量监控图可以用 irate 配合短窗口,能更快反映当前状态。increase 一般用于统计总量变化,比如“这台机器今天接收了多少网络流量”,不适合作为判断是否异常的手段。理解了这三个函数,PromQL 就算入门了一半。

5. 告警通知与可视化落地:Alertmanager 和 Grafana 的实操记录

5.1 Alertmanager 配置:分组、抑制、路由一个都不能少

Alertmanager 存在的意义不只是把告警转发出去,它承担了更重要的职责:防止告警轰炸。如果每台机器每项指标不满足条件都各发一条消息,几百条通知同时涌进手机的时候,你会关了所有通知,系统彻底失去意义。合理的做法是分组和路由。

我的配置思路是这样的:同一台机器上同时有多条告警触发时,只在分组里发一条消息,把多个告警标题拼在一起;不同机器的相似问题,按机器名拆分成不同消息,保持可读性;如果已经有严重告警在被处理,同机器的其他次要告警可以抑制,避免重复打扰。这些逻辑都可以在 Alertmanager 的 route 和 inhibit_rules 里实现。

接收端的配置用的是 Webhook 加钉钉机器人,因为没有单独部署邮件服务器的成本。钉钉机器人只需要一个 Webhook 地址,Alertmanager 官方没有内置钉钉的接收器,所以用了一个通用的 webhook 服务把 Alertmanager 发来的 JSON 转成钉钉支持的消息格式。这个转换服务就是一个很轻量的 Python 脚本,监听一个端口收到 POST 请求就转发到钉钉 Webhook,部署起来比想象中简单,还不用引入额外的开源组件。

如果想从零开始配置,一个要点是 alertmanager.yml 里 receivers 与 route 的对应关系。route 规定哪类告警走哪个 receiver,receiver 定义具体怎么发。初学者最容易犯的错是只配置了 receiver 没把它写进 route,结果告警倒是生成了,消息却发不出去。

5.2 Grafana 仪表盘:数据都采集了,你还得让它看得懂

Grafana 是这套系统里观感提升最明显的一环。它本身不采集数据,只是个查询展示工具,天生适配 Prometheus。我的仪表盘配置有三块:主机总览、核心指标明细、告警状态看板。主机总览放最常用的几个面板,CPU 使用率、内存余量、磁盘空间和网络流量;核心指标明细用下拉框做实例切换,方便对比不同机器;告警状态看板直接查 ALERTS 这个内置指标,能看出当前有哪些活跃告警,配合日志用效果很好。

Grafana 里设置 Prometheus 数据源时,URL 填 http://prometheus:9090 这种容器内主机名,但要注意如果 Grafana 和 Prometheus 不在同一个 Docker 网络里,这个主机名是解析不了的。直接填 IP 地址永远是最保险的方式。导入面板后,很多官方分享的模板拿来就能用,但也不要迷信,官方模板的指标用的是同一个 Exporter 的字段名,版本兼容性一般没问题,最怕的是指标已经被自己写的容器方式暴露路径改过,匹配不上就全部显示 No Data,这时候先检查数据源的 query 和采集目标,不要急着改面板。

数据存储方面,Prometheus 的本地存储清理是一件需要主动做的工作。默认的存储方式会把时间序列数据写进 data 目录,时间长了磁盘占用不断上涨,但 Prometheus 本身提供数据保留期配置,在启动参数里加 --storage.tsdb.retention.time=15d 和 --storage.tsdb.retention.size=10GB,分别表示保留 15 天的数据和最多占用 10GB 磁盘,超过的部分会被自动清理。设置了这一层,才不用天天盯着数据目录的膨胀速度。

6. Docker Compose 编排:一套命令拉起的完整监控栈

6.1 编排文件的完整样例与网络配置

把四个组件串起来,最省心的方式就是 Docker Compose。我用的编排文件大致如下,核心思路是保证四容器在同一网络里,数据文件挂在宿主机目录上防止容器重建丢数据,Prometheus 和 Alertmanager 的配置文件也挂出来方便改动:

version: "3.8" services: node-exporter: image: prom/node-exporter:latest container_name: node-exporter command: - '--path.rootfs=/host' network_mode: host pid: host restart: unless-stopped volumes: - '/:/host:ro,rslave' prometheus: image: prom/prometheus:latest container_name: prometheus restart: unless-stopped ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./alerts.yml:/etc/prometheus/alerts.yml:ro - prometheus-data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=15d' - '--storage.tsdb.retention.size=10GB' alertmanager: image: prom/alertmanager:latest container_name: alertmanager restart: unless-stopped ports: - "9093:9093" volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro grafana: image: grafana/grafana:latest container_name: grafana restart: unless-stopped ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=your_strong_password volumes: - grafana-data:/var/lib/grafana volumes: prometheus-data: grafana-data:

Node Exporter 用了 network_mode: host 和 pid: host,这是让它拿到主机真实数据的两个前提。pid: host 保证它能看到宿主机上的所有进程个数,path.rootfs 挂载让它可以读取宿主根目录的文件系统信息。Prometheus 和 Grafana 的端口都映射到了宿主机,号段选择不冲突即可。注意 Grafana 的初始密码环境变量只在第一次启动时生效,之后改了它也不会更新认证方式,这是安全上的一个坑,上线前必须改掉默认密码。

6.2 数据持久化与升级注意事项

数据卷的作用在容器升级时特别明显。刚开始部署的时候我没用命名卷,而是把数据直接放在容器层,运行一段时间后 Prometheus 升级,容器被重建,收集的时序数据全部消失,等于监控从头开始积累。后面改成命名卷后,哪怕是删除容器重新创建,数据依然完好,这一点在长期运行的项目里必须在一开始就做好。

升级镜像时也要注意版本兼容。Prometheus 和它的配置文件结构存在持续调整,有时候新版本会废弃旧的配置项。按照我的经验,升级前先在测试环境用新镜像启动一遍,看日志有没有 warning 级别以上的报错,再决定是否替换生产容器。虽然多花一点时间,但能省去回滚的麻烦。

7. 常见问题与排查技巧实录:这台机器还没旧到能报修

7.1 目标挂了却不触发告警:问题出在哪

有次同事反馈,某台机器明显已经宕机了,Prometheus 的 UI 里看 target 显示 DOWN,但手机却没有收到任何告警消息。排查一圈发现问题出在告警规则本身:我只配了 CPU、磁盘这类指标做阈值判断,但这一类指标在目标机器挂了之后根本采集不到数据,Prometheus 在查询时遇到“没有数据”的情况不会返回数值,所以告警条件永远不成立,就不会触发告警。

解决方法是单独加一条“Up 指标为零”的规则。Prometheus 会给每个采集目标生成一个特殊的合成指标 up,目标正常时值为 1,抓取失败时值为 0。所以规则可以这样写:

- alert: InstanceDown expr: up == 0 for: 2m labels: severity: critical annotations: summary: "实例 {{ $labels.instance }} 已停止响应"

这条规则几乎可以覆盖所有“目标无响应”的场景,比监控单个进程是否存活的指令更可靠,因为进程可能一直跑着但采集接口已经因为网络或端口问题断开了。从此之后,多写一条 up 规则成为我构建任何监控面板的默认动作。

7.2 告警重复轰炸与消息延迟:分组和超时的取舍

另一个低频但头疼的问题是告警没有按预期分组,同一时间多条类似告警会来好几条通知。刚开始我在 Alertmanager 的 route 配置里没有设置 group_by,默认情况下所有告警都收到同一个分组,一条消息里堆了几十条告警,看起来信息很全,但实际很难看清是哪个实例的哪个问题。后来我改成按 instance 分组,每条消息保持清晰的单一问题语境,虽然消息数量增多了,但每条都有用,可读性大幅提升。

消息延迟方面,Alertmanager 有 group_wait 和 group_interval 两个参数。group_wait 表示一组新的告警等待时间,默认 30 秒,在这段时间内如果同一分组有更多告警到达,它们会被合并进同一条消息里再发出去,适合批量问题的场景。group_interval 表示已存在的告警组再次检查的间隔,默认 5 分钟。这个值会导致一个问题:当记忆中的告警已经恢复时,恢复通知可能延迟到下一个周期才发出。如果业务对通知时效要求高,可以把 group_interval 调短到 1 分钟,代价是收到的通知更频繁。按需权衡,没有标准答案。

7.3 时间数据错乱或缺失:检查时区和抓取间隔

部署完成后检查 Grafana 面板,发现两条很诡异的记录:一是时间轴显示的时间比本机时间快了整整 8 小时;二是某些数据点呈锯齿状,一会儿高一会儿低。第一个问题的原因很明确,Prometheus 内部一律使用 UTC 时间存储数据,Grafana 在展示时默认会按浏览器的时区换算,如果浏览器时区设置不对,看起来就存在偏移。Grafana 面板右上角的 Time zone 设置改成 UTC 或者浏览器自动模式,一般就能解决显示问题。

第二个问题则出在我自己的抓取间隔配置。我最初为了实时性把 scrape_interval 设为 5s,但告警评估周期是 15s,数据点的采集密度和查询窗口不匹配,画出图来曲线自然呈阶梯状。后来统一把抓取和评估都设成 15 秒,曲线平滑了很多。注意,PromQL 里的区间向量时长最好大于等于两倍的抓取间隔,这样每个窗口内至少有两个数据点,计算的速率才有足够的样本支撑,结果也有意义。这是个容易踩的坑,尤其在查询结果出现 No Data 或明显抖动时,要先检查这里。

7.4 快速定位问题的自检清单

基于这些经验,我把常见的监控故障排查整理成一张速查表,遇到问题时按顺序检查,基本能覆盖九成的情况:

现象排查思路常见原因
采集目标显示 DOWNcurl 目标 9100 端口,检查 /metrics 是否能访问防火墙拦截、Node Exporter 进程未启动、网络不通
有告警但没收到通知查看 Alertmanager UI 的 Alerts 页面,看告警状态是否为 Firing 且 receiver 是否正确route 未关联 receiver、Webhook 或钉钉地址失效、分组等待时间没过
面板显示 No DataPrometheus UI 里手动执行一次查询,确认指标名正确数据源 URL 写错、时间范围选错、指标标签过滤写错
图表时间偏移 8 小时检查 Grafana 面板时区和浏览器时区时区设置不一致,不影响数据准确性只影响显示
磁盘占用持续上涨查看 Prometheus data 目录大小和保留策略参数未设置 retention 参数,或设置无效导致数据积压

这张表是我踩完坑之后整理的,每次排查问题先过一遍,能节省大量翻日志的时间。

8. 实际踩坑记录与经验总结

8.1 一张表收集的运维黑历史

做这个项目前后踩过的坑,几乎每个都是典型的“文档没写但实际会遇到的”问题。这里系统整理一下,能给后来者省下不少时间。

踩坑场景错误做法正确做法影响等级
容器化部署 Node Exporter使用默认网络模式和路径挂载network_mode: host,pid: host,rootfs 挂载高,否则采集的是容器内部指标
磁盘告警规则未排除 tmpfs 和 overlay 文件系统fstype 正则过滤虚拟文件系统中,误报频繁
判断目标是否存活只监控 CPU 或内存指标增加 up == 0 规则单独判断高,目标挂掉时其他规则全失效
数据持久化未使用命名卷prometheus-data、grafana-data 命名卷高,容器重建数据全丢
告警通知消息过多所有告警塞在一个分组按 instance 分组,设置合理的 group_wait中,告警疲劳导致通知被忽略
告警间隔过长group_interval 保持默认 5 分钟时效敏感时调短到 1 分钟中,恢复通知延迟
查询窗口过短跟抓取间隔相同甚至更短窗口至少两倍抓取间隔低,数据点不足,结果不平滑
Grafana 时区混乱浏览器时区不一致面板显示 UTC 或固定脚本时区低,仅显示问题

8.2 告警阈值的动态调优方法

告警规则里最难的不是语法,而是阈值定多少。阈值定太严,系统天天狼来了,最后没人看;定太松,真出问题时不报警,形同虚设。我的方法是先观察一星期的基线数据,把高水位和低水位统计出来,设置阈值时留出百分之二十的余量。比如日常 CPU 平均使用率稳定在 30% 到 45%,那告警阈值设在 80% 更合适,而不是 60%,否则一个正常的业务高峰就会误报。磁盘空间的阈值相对静态,可以直接按剩余容量比例定,但要根据日志增长速度做预估,比如日志每天涨 2GB,磁盘只有 50GB,那 15% 的剩余空间其实只够用不到四天,最早可在剩余 30% 时触发提醒级别告警,15% 触发严重告警,留给运维人员足够处理时间。

阈值调优没有一劳永逸的方案,业务量在变,基线也在变。每季度拿最近一个月的指标重新看一下,及时调整,比任何时候都可靠。

8.3 一个小细节:告警消息模板里要带上什么信息

告警消息模板越完善,收到告警后的处理效率就越高。这点亲身经历过:最开始只发了一条“CPU 使用率过高”的通知,人到服务器前才发现连哪台机器、什么时候开始的、当前值是多少都不知道,还得自己手动查。后来模板里加上实例名、持续时间、当前值、阈值、告警级别,再附上一个到 Grafana 面板的跳转链接,处理效率完全不同。以下是我的建议模板结构:

[告警] 实例 192.168.1.11 磁盘空间不足 级别: critical 当前状态: 挂载点 /data 可用空间剩余 8%,低于阈值 15% 触发时间: 2024-XX-XX 10:23:00,已持续 12 分钟 查看面板: http://grafana.example.com/d/xxxx

一条包含这些字段的告警,已经足够让值班人员在手机上一眼判断出问题的重要性、位置和紧急程度,很多时候可以不打开电脑直接决定是加强关注还是马上处理。这个模板设计上的收益,远超想象的投入。

9. 部署完成后我还做了哪些事

9.1 把历史数据盘了一遍,确认监控覆盖到“该关心的东西”

监控系统上线后,我先用 PromQL 把近七天所有机器的核心指标跑了一遍,不是为了验证监控本身,而是为了发现那些我以为正常但实际不正常的指标。不看不知道,有一台机器的网络接收流量每天凌晨都会出现一个尖峰,持续十几分钟,平时完全没注意过,排查后才发现是一个定时任务在凌晨拉取大量更新包,尖峰完全合理。通过这样的数据盘查,能对现有业务有一个更客观的认识,也为后续告警阈值设定提供了参考基础。

这个习惯后来一直保留着:新系统上线、业务版本大更新后,花十分钟翻一翻监控数据,确认基线和预期一致,顺便看看有没有异常趋势出现,比事后再排查节省大量时间。

9.2 加了一个“自监控”任务

监控系统本身也可能出问题,比如 Prometheus 进程挂掉了,所有采集和告警都停止,那谁来告诉运维监控挂了?这个问题非常现实。我在 Prometheus 自身上也配置了一个简单的探测规则,定期去检查 Prometheus 自己的 /-/healthy 接口。这样 Prometheus 还活着的时候,它能通过告警规则发现 Web 接口异常并推送出去;如果 Prometheus 进程整个挂了,至少还有 systemd 的 Restart=always 兜底,能在进程退出后自动拉起来。这也算是一个朴素的“监控替身”方案。

10. 这个项目后续还能怎么扩展

因为我当时的需求只是一个基础的监控报警,所以没有继续做太多扩展。但如果你基于这套基础继续往下走,有几个方向性价比很高。

一个是增加更多 Exporter。目前只覆盖了主机层面的指标,如果跑着 MySQL、Nginx、Redis,各自的 Exporter 可以补齐应用层的监控盲区。每个 Exporter 的接入方式都类似,配置好采集目标和告警规则即可,成本很低。另一个是接入日志监控。Prometheus 本身不擅长日志分析,但如果日志里有明显响应异常,可以考虑配合 Loki,先把日志采集做起来,再设定简单的关键字告警规则,形成“主机指标加应用指标加日志告警”的三层监控结构。

第三个方向是自动化部署和回滚。现在这套方案还是手工在服务器上执行 docker compose up -d,如果机器数量再多一点,可考虑用自动化工具把配置分发和启动流程批量管理起来。只要做好基础编排文件的幂等性,就能实现新机器几十秒内自动接入监控体系。对我来说,当初从零搭建这套系统的最大收获,不只是那几块数据可视化面板,而是理解了监控运维中组件协作的逻辑——每个组件都做得很窄,但拼起来就是一个可靠的预警网络。这也是建议你从这套组合开始上手的原因。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询