欢迎光临
我们一直在努力

云上告警疲劳与告警治理实战:告警轰炸、误报降噪、值班效率与告警闭环

别跟我讲什么上周被告警吵醒了三次这种故事,直接进入正题。你要治理告警,先把这四条红线记住,碰一条就翻车:

严禁操作清单:

  • 不要为了安静直接关掉告警。 关掉等于裸奔,线上挂了你是最后一个知道的。
  • 不要一次性把所有阈值调高。 你觉得CPU 80%就报警太吵,全改成95%,结果真实故障来了CPU飙到93%你啥都不知道。漏报比误报更致命。
  • 不要不加分级一股脑全推给值班。 P1和P4用同一个通道、同一个音量轰炸,值班三天就麻木了,真P1来了照样当噪音划掉。
  • 不要告警处理完不记录不关闭。 告警响了,你看了一眼"哦没事",然后不管了。下次同样的告警又响,你又看一眼。这不叫处理,这叫熬鹰。没有闭环的告警永远在循环。
  • 处置总原则,刻在脑门上:

    先分级定责,再逐条降噪;先保关键告警,再减无效告警。

    意思是:你得先搞清楚哪些告警是要命的,保住它们别漏;然后回头去砍那些天天响但没人管的。顺序不能反。


    第一步:正确开局——先盘家底,别急着调规则

    很多兄弟上来就改阈值、加抑制,改完发现更乱了。不对。你得先知道自己有多少烂摊子。

    1. 盘清楚这些数字

    • 当前一共有多少条告警规则?
    • 每天产生多少条告警?
    • 这里面多少是误报?多少是有效告警?
    • 哪些告警从配置那天起就没人处理过?
    • 值班工程师处理一条告警平均花多久?

    怎么查?命令直接拿走。

    导出Prometheus所有告警规则:

    curl -s http://<prometheus-addr>:9090/api/v1/rules \\
    | jq '.data.groups[].rules[] | {name: .name, state: .state, health: .health, query: .query}' \\
    > alert_rules_export.json

    # 看看一共多少条
    cat alert_rules_export.json | jq -s 'length'

    导出Alertmanager当前活跃告警:

    amtool –alertmanager.url=http://<alertmanager-addr>:9093 alert query -o json > active_alerts.json

    统计过去7天告警触发次数TOP20(Prometheus侧):

    curl -s 'http://<prometheus-addr>:9090/api/v1/query?query=ALERTS{alertstate="firing"}[7d]' \\
    | jq -r '.data.result[].metric.alertname' \\
    | sort | uniq -c | sort -rn | head -20

    如果你用的是Grafana告警,走API:

    curl -s -H "Authorization: Bearer <your-token>" \\
    http://<grafana-addr>:3000/api/alert-rules \\
    | jq '.[] | {title: .title, uid: .uid, state: .state}' > grafana_alert_rules.json

    2. 定优先级

    拿到数据以后,按这个顺序排:

  • 先处理触发频率最高的误报。 一个规则一天响200次,99次是假的,这种先干掉,立竿见影。
  • 再保核心业务告警。 订单服务、支付链路的告警,宁可多报不可漏报。
  • 最后清理僵尸告警。 配了半年从没人看的,要么删,要么改对。
  • 3. 按四类收敛

    把所有告警规则归到四个桶里:

    类别例子
    可用性 服务挂了、接口5xx、健康检查失败
    性能 接口响应时间过长、数据库慢查询
    容量 磁盘快满了、内存不足、连接池耗尽
    安全 异常登录、权限变更、漏洞扫描

    别混在一起。安全告警和性能告警走不同的通知通道,看的人不一样。

    4. 区分三种告警

    • 有效告警:真出故障了,需要人去处理。
    • 误报:规则写得有问题、阈值不合理,实际上没事。
    • 无效告警(僵尸告警):配了但没人能处理、没人负责,或者对应的服务早就下线了。

    僵尸告警最恶心,天天响,值班划掉,下周继续响。这种直接标记"待废弃",走审批删掉。


    第二步:实施主链路——一步步走

    环节一:导出告警规则 + 命中次数

    上面命令已经给了。重点看什么?看health字段。如果大量规则health是err,说明你的PromQL写错了或者数据源有问题,告警根本没在工作,属于"你以为你在监控,其实你在裸奔"。

    环节二:按告警类型/对象/时间聚合统计TOP

    # 按告警名统计
    cat active_alerts.json | jq -r '.[].labels.alertname' | sort | uniq -c | sort -rn | head -20

    # 按实例/机器统计,看是不是某台机器在疯狂报警
    cat active_alerts.json | jq -r '.[].labels.instance' | sort | uniq -c | sort -rn | head -10

    # 按时间段统计(需要结合日志或者告警历史接口)
    # 这里用alertmanager的api查最近24h
    amtool –alertmanager.url=http://<alertmanager-addr>:9093 alert query –active

    现象对应问题:

    • 某个alertname占了80%的量 → 这条规则阈值或表达式有问题,重点查。
    • 某台instance告警特别多 → 可能是单机问题,也可能是采集异常。
    • 凌晨2-5点告警集中爆发 → 大概率是定时任务、备份、日志轮转引起的,不是真故障。

    环节三:分析单条告警完整链路

    一条告警从产生到关闭,链路是这样的:

    指标采集(Prometheus/Agent) → 规则评估(Recording/Alerting Rule)
    → 触发条件满足 → Alertmanager接收 → 去重/分组/抑制/静默
    → 通知通道(Webhook/邮件/钉钉/飞书/电话) → 值班人收到
    → 确认 → 处理 → 关闭 → 复盘记录

    每一环都可能出问题:

    • 采集断了 → 告警漏报
    • 规则评估间隔太长(evaluation_interval设了5分钟) → 告警延迟
    • Alertmanager没配对路由 → 告警发了但没人收
    • 通知通道挂了(钉钉token过期、邮件SMTP不通) → 告警到了门口进不来
    • 值班人收到没确认 → 没有闭环

    检查Alertmanager路由是否正常:

    amtool –alertmanager.url=http://<alertmanager-addr>:9093 config routes

    检查通知通道是否通畅(手动触发测试告警):

    amtool –alertmanager.url=http://<alertmanager-addr>:9093 alert add \\
    alertname=TestAlert severity=critical instance=test-01 \\
    summary="告警通道测试,请忽略"

    看到值班群里收到消息了,说明通道没问题。收不到,先去查webhook地址、token、防火墙。

    环节四:阈值合理性评估

    别拍脑袋。拿历史数据说话。

    # 查某个指标过去30天的P99值
    curl -s 'http://<prometheus-addr>:9090/api/v1/query?query=quantile_over_time(0.99, http_request_duration_seconds[30d])'

    # 查CPU过去7天的最大值
    curl -s 'http://<prometheus-addr>:9090/api/v1/query?query=max_over_time(node_cpu_seconds_total{mode!="idle"}[7d])'

    原则: 阈值要基于你业务自己的基线。别人的80%跟你没关系。你的服务常年跑在75%CPU,那你告警线至少得85%以上。你的服务平时5%,突然到30%就该叫了。

    环节五:告警分级配置

    按严重程度分P1-P4:

    级别含义通知方式响应要求
    P1 核心业务不可用 电话 + 短信 + IM 5分钟内响应
    P2 核心业务降级/性能严重劣化 短信 + IM 15分钟内响应
    P3 非核心业务异常 IM 工作时间处理
    P4 信息类/趋势预警 邮件 有空看就行

    Alertmanager路由配置示例:

    route:
    receiver: 'default'
    group_by: ['alertname', 'cluster']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    routes:
    match:
    severity: critical
    receiver: 'oncall-phone'
    group_wait: 10s
    repeat_interval: 15m
    match:
    severity: warning
    receiver: 'oncall-im'
    repeat_interval: 1h
    match:
    severity: info
    receiver: 'dev-email'
    repeat_interval: 12h

    receivers:
    name: 'oncall-phone'
    webhook_configs:
    url: 'http://<phone-gateway>/call'
    name: 'oncall-im'
    webhook_configs:
    url: 'https://oapi.dingtalk.com/robot/send?access_token=<your-token>'
    name: 'dev-email'
    email_configs:
    to: 'dev-team@company.com'

    现象对应问题:

    • P1告警用的是邮件通知 → 半夜没人看邮件,漏了。
    • P4告警用了电话 → 值班被你骂死。
    • 所有告警都走了同一个receiver → 没分级,等于没配。

    环节六:抑制与聚合规则

    聚合(group_by): 同一个alertname、同一个集群的告警合并成一条通知,别一条一条发。

    route:
    group_by: ['alertname', 'cluster', 'service']
    group_wait: 30s # 等新告警凑一凑,30秒内同组的一起发
    group_interval: 5m # 同组告警有更新时,至少等5分钟再发下一波
    repeat_interval: 4h # 同一条告警没恢复,4小时后再提醒一次

    抑制(inhibit_rules): 比如整个机房网络断了,那机房里所有机器的"主机不可达"告警就不要再发了。

    inhibit_rules:
    source_match:
    alertname: 'DatacenterDown'
    severity: 'critical'
    target_match:
    alertname: 'HostUnreachable'
    equal: ['datacenter']

    静默窗口(Silence): 已知维护时间段,提前设静默。

    # 给某个告警设2小时静默
    amtool –alertmanager.url=http://<alertmanager-addr>:9093 silence add \\
    alertname="DiskSpaceLow" instance="prod-db-01" \\
    –comment="计划扩容磁盘" \\
    –duration="2h"

    # 查看当前静默
    amtool –alertmanager.url=http://<alertmanager-addr>:9093 silence query

    ⚠️ 生产环境风险提醒: 抑制规则写错了会把关键告警也吞掉。加完抑制一定要用amtool check-config验证配置,再reload。

    环节七:告警接收人/值班组配置

    别把告警发给离职的人、别发给不负责这块业务的人。

    如果你用Grafana OnCall或者PagerDuty,直接在上面排值班表。如果没有,最简单的方式是用钉钉/飞书群机器人的webhook,配合一个定时脚本换webhook地址。

    # 示例:通过crontab每周日切换值班webhook
    # crontab -e
    0 0 * * 0 /opt/scripts/rotate_oncall_webhook.sh

    环节八:告警闭环流程

    一条告警的生命周期必须走完这四步:

    确认(Acknowledge) → 处理(处理中状态) → 关闭(Resolved) → 复盘(记录根因和处理动作)

    如果你用的Alertmanager原生能力有限,建议接一个工单系统或者用Grafana OnCall。至少做到:

    • 收到告警 → 在群里回复"收到,在处理"(确认)
    • 处理完 → 在告警平台点Resolved或者回复"已处理,原因xxx"(关闭)
    • 每周值班交接 → 把本周未关闭的告警过一遍(复盘)

    现象对应问题:

    • 告警自动恢复了但没人确认 → 不知道是误报还是自愈,下次再响照样慌。
    • 告警挂了一周没关闭 → 值班列表里全是历史告警,新告警淹没在里面。

    第三步:高频现场逐个拆

    场景1:同一告警每小时轰炸几十条

    现象: 值班手机一直在震,打开一看全是同一个HighMemoryUsage,50台机器每台一条。

    原因: 没配聚合,或者group_by没包含alertname。

    处理:

    # alertmanager.yml
    route:
    group_by: ['alertname', 'cluster']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h

    改完reload:

    curl -X POST http://<alertmanager-addr>:9093/-/reload

    改完50条变成1条汇总消息:“HighMemoryUsage 在 cluster-prod 集群有50个实例触发”。

    场景2:深夜误报警

    现象: 凌晨3点DiskIOHigh告警,值班爬起来一看,是定时备份在跑,磁盘IO本来就会高。

    原因: 阈值没考虑定时任务的基线波动,或者维护窗口没设。

    处理:

    方案A:改PromQL,排除备份时段:

    # 原始
    alert: DiskIOHigh
    expr: rate(node_disk_io_time_seconds_total[5m]) > 0.9

    # 改后:只在非备份时间(6:00-23:00)报警
    alert: DiskIOHigh
    expr: rate(node_disk_io_time_seconds_total[5m]) > 0.9
    and ON() (hour() > 6 and hour() < 23)

    方案B:设静默窗口(上面amtool silence add命令,或者Alertmanager的mute_time_intervals)。

    # alertmanager.yml
    time_intervals:
    name: backupwindow
    time_intervals:
    times:
    start_time: '02:00'
    end_time: '04:00'

    route:
    routes:
    match:
    alertname: 'DiskIOHigh'
    mute_time_intervals:
    backupwindow

    场景3:告警发给了不值班的人

    现象: 周六告警发给了周一到周五值班的老王,老王在外面带娃,没看到。

    原因: 接收人写死了,没跟排班表联动。

    处理: 引入值班轮换。如果不想上Grafana OnCall这种平台,最低成本方案是用一个变量webhook:

    receivers:
    name: 'oncall-im'
    webhook_configs:
    url: 'http://<internal-service>/get-current-oncall-webhook'

    后端服务根据当天日期返回当前值班人的webhook地址。

    场景4:关键故障没人收到告警

    现象: 支付接口挂了20分钟,客户投诉了才知道。查告警平台,没有告警记录。

    原因: 漏配规则、路由配错、或者通知通道token过期。

    处理:

    # 1. 确认规则存不存在
    curl -s http://<prometheus-addr>:9090/api/v1/rules | jq '.data.groups[].rules[] | select(.name == "PaymentServiceDown")'

    # 2. 确认Alertmanager路由能不能匹配
    amtool –alertmanager.url=http://<alertmanager-addr>:9093 config routes

    # 3. 手动触发测试(上面给过的amtool alert add命令)

    逐个排查,八成是路由没匹配到正确的receiver,或者webhook地址404了。

    场景5:告警太多干脆全关

    现象: 值班被搞崩溃了,直接在Alertmanager把所有告警静默了,或者直接stop了Alertmanager进程。

    原因: 告警疲劳到了临界点。

    处理: 这就是开篇说的红线第一条。先恢复,然后用第一步的方法盘TOP误报,先把前5个高频误报处理掉,告警量通常能降50%以上。别走极端。

    场景6:安全告警和性能告警混在一起

    现象: 值班群里同时出现"CPU使用率超80%“和"检测到异常SSH登录”,值班运维看到CPU告警去查了,安全告警被刷过去了。

    原因: 没分级、没分路由。

    处理: 按前面说的四类(可用性、性能、容量、安全)加label区分,Alertmanager里配不同route走不同receiver。安全告警走安全团队,性能告警走运维团队。

    route:
    routes:
    match:
    category: 'security'
    receiver: 'security-team'
    match:
    category: 'performance'
    receiver: 'ops-team'

    场景7:告警处理了没人记录

    现象: 同一个告警每周响一次,每次都"看一眼没事",从来没记录过为什么没事。三个月后真出事了,查历史记录一片空白。

    原因: 没有闭环流程。

    处理: 强制要求每条告警必须有处理记录。最简方案:在钉钉/飞书群里用固定格式回复:

    【告警闭环】
    告警名:HighMemoryUsage
    触发时间:2026-09-01 03:00
    处理人:张三
    处理结果:误报,原因是定时任务内存峰值
    后续动作:调整阈值为85% / 加入静默窗口

    嫌麻烦就上Grafana OnCall或者接Jira自动建工单。


    第四步:落地与推广——分场景给策略

    三个阶段,别想一步到位

    阶段目标周期做什么
    止血 降噪高频误报 1-2周 干掉TOP10误报,加聚合,设静默
    治理 分级+聚合+路由 1-2月 全量告警分级P1-P4,配路由,配值班
    运营 定期复盘 持续 每周看告警统计,每月复盘,持续优化

    先止血。值班兄弟快被搞疯了,你上来就搞分级体系,人家没空配合你。先帮他把每天200条降到50条,他才会支持你后面做的事。

    核心业务 vs 边缘业务

    • 核心业务(支付、订单、登录): 宁可多报,不可漏报。阈值可以敏感一点,P1级别,电话通知。
    • 边缘业务(内部后台、报表导出): 阈值放宽,P3/P4级别,IM或邮件。没人半夜爬起来修报表系统。

    7×24值班 vs 工作时间值班

    • 7×24值班: P1/P2走电话/短信,任何时间都通知。P3/P4走IM,可以设夜间静默。
    • 工作时间值班: 所有告警都走IM/邮件,P1可以加电话但仅限工作时间。非工作时间P1告警发到群里,依赖第二天早上处理。

    什么时候宁可保留冗余告警

    关键业务的可用性告警。你不确定ServiceDown和HealthCheckFailed是不是重复了?都留着。 关键业务少报一个告警的代价是线上事故,多报一个的代价是值班多看一眼。你自己选。

    告警规则变更走审批留痕

    改阈值、加抑制、删规则,都要走审批。最简单的办法:所有告警规则用Git管理(Grafana的provisioning或者Prometheus的rules文件放在Git仓库),改规则提PR,至少一个人review。别直接上去改配置文件,出了问题说不清谁改的。

    # 示例:告警规则Git仓库结构
    alert-rules/
    ├── core/
    │ ├── payment.yml
    │ └── order.yml
    ├── infra/
    │ ├── node.yml
    │ └── database.yml
    └── security/
    └── auth.yml


    第五步:根因分析——告警疲劳到底怎么来的

    干了几年,告警疲劳的根因翻来覆去就这几个:

  • 规则没有按业务基线配置。 从网上抄了一套Prometheus告警规则直接导入,阈值是人家业务的,不是你的。你的服务CPU常年70%,人家设的阈值75%,你天天报警。

  • 阈值拍脑袋定。 “CPU超过80%就告警吧。” 为什么80%?不知道。没有任何数据支撑。

  • 没有聚合抑制。 50台机器同一秒触发同一个告警,发50条消息。这不是监控,这是DDoS值班工程师。

  • 没有分级。 P1和P4一样响、一样发通知。狼来了喊多了,真狼来了也没人动。

  • 告警与值班脱节。 规则配好了,通知发给一个固定邮箱,值班的人从来不看那个邮箱。

  • 缺少复盘机制。 告警响了就处理,处理完就忘。没有人回头看哪些告警是误报、哪些规则需要调整。

  • 怎么定位清楚? 把告警统计数据(哪些规则触发最多、什么时间段集中)和值班记录(哪些告警处理了、哪些标记为误报、哪些没管)对照着看。触发100次、值班标记误报95次的规则,就是你需要治理的第一优先级。


    第六步:事后加固要点

    治理完不是结束。你得有机制防止退回原样。

    加固项具体做法
    告警规则按业务基线重设 每季度用quantile_over_time拉一次历史数据,校准阈值
    分级+分路由 新加告警必须带severity和category label,否则合并不进主干配置
    聚合抑制与静默窗口 所有维护操作必须提前加silence,写进SOP
    值班表自动化 值班轮换与通知通道联动,别手动改webhook
    告警闭环SLA 明确P1五分钟响应、P2十五分钟响应,写进值班手册
    定期告警复盘会 每周五花15分钟过一遍本周告警清单
    告警质量指标 每周统计:误报率(误报数/总告警数)、漏报率(事故数-告警数/事故数)、平均响应时长

    ⚠️ 生产环境风险提醒: 改完Alertmanager配置一定要先check再reload:

    amtool check-config /etc/alertmanager/alertmanager.yml
    curl -X POST http://<alertmanager-addr>:9093/-/reload

    别直接reload,配置有语法错误Alertmanager会拒绝加载,但旧配置还在跑。你以为你生效了新规则,其实还在用旧的。


    第七步:踩坑清单

    最后总结,治理告警过程中我踩过和看别人踩过的坑:

    坑后果
    为了安静关告警 线上挂了没人知道,你背锅
    阈值全调高 真实故障来了没触发,客户先发现
    不分级全推给值班 值班三天就辞职
    告警没闭环处理 同一个问题反复响,浪费所有人时间
    深夜误报没人管 值班被折腾到崩溃,开始关告警(回到第一个坑)
    安全告警被性能告警淹没 被入侵了三天后才发现
    加了抑制把关键告警也吞了 机房断网了,你因为配了"网络异常时抑制主机告警",连主机不可达都收不到,以为一切正常

    最后一个坑最阴。加抑制的时候一定要想清楚:source_match条件会不会过于宽泛。建议先在测试环境用amtool test-routing验证路由和抑制效果。

    # 测试一条告警会走哪个路由
    amtool –alertmanager.url=http://<alertmanager-addr>:9093 test-routing \\
    –labels alertname=HighMemoryUsage severity=warning cluster=prod


    写在最后

    告警治理这事不是一次性的项目,是持续运营的活。你今天把误报率从60%降到20%,下个月业务上了新功能,又冒出一堆新告警。正常的。关键是你要把"盘现状→分级→降噪→闭环→复盘"这个流程跑起来,变成习惯。

    值班工程师是人,不是告警接收器。你少发一条垃圾告警,他就多一分精力去看那条真正要命的P1。

    就这样,希望这篇能帮你少熬几个夜。


    觉得有用的话,点个赞👍 收藏⭐ 一下,下次告警轰炸的时候翻出来照着做。有问题评论区聊,看到都会回。关注博主,后续更新SRE实战系列。

    赞(0)
    未经允许不得转载:171主机测评 » 云上告警疲劳与告警治理实战:告警轰炸、误报降噪、值班效率与告警闭环
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址