告警响不停?3招教你写出"不扰民"的Prometheus规则

刚接手运维工作那会儿,我犯过一个极其"经典"的错误:觉得监控覆盖率越高越好,于是把网上抄来的Prometheus规则一股脑全配上了。

结果就是,我的手机成了24小时震动的按摩棒。凌晨3点被"CPU使用率超过80%“的告警惊醒,爬起来一看,只是个定时备份任务在跑,两分钟后就自动恢复了。这种"狼来了"的故事发生几次后,我和团队对告警彻底麻木了,直到真正发生线上故障时,那条关键的报错信息淹没在了几百条无效告警里,导致我们晚了半小时才介入处理。

那时候我才明白:写告警规则不是填空题,而是一门关于"信噪比"的艺术。

很多兄弟在落地Prometheus时,往往只关注"能不能抓到指标”,却忽略了"这玩意儿到底该不该报"。今天咱们不聊虚的,我想结合这几年踩过的坑,聊聊怎么写出既精准又"不扰民"的高质量Prometheus规则。

一、 别让"抖动"骗了你:引入时间窗口与趋势预测

新手写规则最喜欢"直来直去"。比如监控磁盘,看到剩下10%就马上报警。这听起来没毛病,但在实际生产环境里,这种瞬时值的判断非常容易误报。

真实案例: 我们有个日志处理服务,每隔几小时会有一次短暂的数据写入洪峰,磁盘I/O和使用率会瞬间飙高,但很快就会被清理脚本释放。刚开始我们设置了node_filesystem_free_bytes < 10%就告警,结果运维群每天都要炸几次锅,大家查了一圈发现"没事啊",久而久之就没人看了。

配图

避坑方法论: 告警的本质是呼叫人工介入。如果它能自己恢复,就不应该半夜叫醒你。我们需要引入持续时间(Duration)趋势预测(Prediction)

  1. 加个"for"缓冲: 只有当问题持续一段时间(比如5分钟)还没恢复,才算真问题。
  2. 看未来趋势: 与其盯着现在的剩余空间,不如算算"按照当前写入速度,多久之后会写满"。

优化后的规则示例:

groups:
- name: disk_alerts
  rules:
  # 只有当磁盘将在4小时内填满,且当前剩余空间确实小于10%时,才告警
  # predict_linear 是个神技,利用过去1小时的数据预测未来
  - alert: DiskWillFillIn4Hours
    expr: predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) < 0 and node_filesystem_free_bytes / node_filesystem_size_bytes < 0.1
    for: 10m  # 持续10分钟满足条件才触发
    labels:
      severity: warning
    annotations:
      summary: "磁盘将在4小时内耗尽"
      description: " 的磁盘写入过快,预计4小时后写满,请检查日志量。"

自从换了这个规则,那个日志服务的无效告警直接归零。只有当清理脚本挂了,或者业务量暴增导致真要写满时,我们才会收到通知。这时候,每个人都知道:这条告警必须处理,不能滑过去。

二、 告别"资源焦虑":从RED方法论切入业务视角

很多团队的Prometheus规则里,90%都是CPU、内存、磁盘这些基础资源监控。

但我问你一个扎心的问题:如果CPU跑到了95%,但用户访问完全正常,这算故障吗? 反过来说,如果CPU只有10%,但用户下单全报500错误,这算故障吗?

显然后者才是我们要死磕的。过分关注底层资源,很容易陷入"资源焦虑"。作为开发和运维人员,我们的关注点应该从"机器活得好不好"转移到"服务干得行不行"。

真实案例: 有次大促,我们盯着仪表盘看CPU负载,一切平稳。结果客服炸了,说用户反馈无法支付。查了半天才发现,是下游支付网关的一个连接池配置错了,导致请求大量超时。因为等待超时不消耗CPU,所以资源监控全是绿的,但业务其实已经挂了。

落地框架:RED方法论 Weaveworks 提出的 RED 方法论非常适合微服务监控。我们在写规则时,优先覆盖这三个维度:

  • R (Rate):请求速率(每秒多少请求?)
  • E (Errors):错误率(有多少失败了?)
  • D (Duration):响应时间(处理要多久?)

实操代码:

比起盯着CPU,我强烈建议你先配好这条关于"错误率"的黄金规则:

groups:
- name: service_level_alerts
  rules:
  # 5分钟内,如果错误率超过1%,立马告警
  # sum(rate(...)) 是处理微服务聚合的标准姿势
  - alert: HighErrorRate
    expr: |
      sum(rate(http_requests_total{status=~"5.."}[5m])) 
      / 
      sum(rate(http_requests_total[5m])) > 0.01
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "服务  错误率飙升"
      description: "当前错误率已超过1%,请立即检查日志!"

这不仅能让你在业务受损的第一时间感知,还能帮你过滤掉那些"虽然CPU高但服务很健康"的无效焦虑。我现在的习惯是:凡是不能直接映射到用户体验的资源告警,等级全部设为 Warning,只有 RED 指标异常才设为 Critical 并触发电话通知。

三、 巧用"中间层":Recording Rules 拯救你的Prometheus

随着规则越写越多,你可能会发现Prometheus的查询变慢了,甚至有时候评估规则本身就让Prometheus OOM(内存溢出)了。

这通常是因为你在Alert规则里写了太多复杂的实时计算。比如,你要算全公司几千个实例过去7天的SLA(服务等级协议),如果在告警规则里直接跑这个查询,Prometheus大概率会原地去世。

踩坑经历: 我们曾试图在一个规则里计算"过去24小时API的P99响应时间",结果每到整点评估规则时,Prometheus就出现短暂的卡顿,数据断点频发。

解决方法:预计算(Recording Rules) 这就像编程里的"缓存"或者是数据库里的"物化视图"。先把复杂的查询算好,存成一个新的指标,告警的时候直接查这个新指标。

优化步骤:

  1. 定义中间指标: 先把复杂的聚合算出来。
groups:
- name: recording_rules
  rules:
  # 每分钟预计算一次,存成 job:http_inprogress_requests:sum
  - record: job:http_inprogress_requests:sum
    expr: sum by (job) (http_inprogress_requests)

配图

  1. 基于中间指标告警:
- alert: HighRequestLoad
  # 告警查询瞬间完成,不再消耗大量算力
  expr: job:http_inprogress_requests:sum > 1000
  for: 1m

我个人的经验是,只要你的PromQL里出现了3层以上的聚合操作(sum套rate再套predict),就应该考虑把它拆解成Recording Rules。 这不仅能救你的Prometheus一命,还能让你的告警规则看起来清爽得多,后期维护也容易。

结尾与行动建议

做监控这么多年,我最大的感悟是:最好的告警,是你收到它时,手心会出汗,而不是翻个白眼把它划掉。

自定义Prometheus规则不仅仅是写几行YAML配置,它倒逼着我们去理解业务的真实形态、理解系统的瓶颈所在。

如果你觉得现在的告警太吵,不妨在这个周五下午(我通常选这个时间做复盘),试着做这3个动作:

  1. 做一次"告警大扫除": 导出过去一周触发次数最多的Top 3告警,问问自己:这几条告警如果没发,系统会挂吗?如果不会,删了它或者调低等级。
  2. 落地一条RED规则: 挑一个核心服务,给它加上基于错误率(Errors)的告警,替代掉单纯的CPU告警。
  3. 加上for参数: 检查所有现有的规则,凡是没有加for持续时间的,全部加上至少1分钟的缓冲。

你在配置Prometheus规则时,遇到过最离谱的误报是什么?或者你有什么独门的"降噪"技巧? 欢迎在评论区聊聊,咱们一起把监控做得更"丝滑"。