一、告警的诞生:从监控指标到告警事件

大家好,我是你们的老朋友。今天咱们聊聊告警是怎么来的。

很多人觉得告警嘛,不就是监控系统发现不对劲,然后发个消息出来?其实没那么简单。我做了这么多年运维,见过太多团队被告警淹死——一天几万条,真正需要处理的不到十条。为什么会这样?说白了,就是没搞懂告警的生命周期。

我个人习惯把告警的诞生分成四个阶段:指标采集 → 异常检测 → 告警生成 → 事件分发。咱们一个一个拆开看。

1.1 指标采集:告警的原材料

告警不是凭空冒出来的。它的源头是监控指标。

你想想看,服务器CPU用了多少、内存还剩多少、接口响应时间多长——这些原始数据就是告警的「原材料」。我见过最离谱的案例,有人直接拿原始采样数据做告警判断,结果网络抖动一下,告警就炸了。

这里有个关键点:采集粒度。我个人建议,核心指标至少每10秒采一次,非核心的可以放宽到1分钟。但别太细,太细了存储扛不住。

核心原则:采集频率 = 业务容忍度 × 2。比如业务能容忍30秒的延迟,那你就15秒采一次。

1.2 异常检测:从数据到告警的「翻译」

原始数据本身不会说话。你得告诉系统:什么算正常,什么算异常。

这里分两种做法:

  • 静态阈值:比如CPU超过90%就告警。简单粗暴,但容易误报。我记得有一次,业务大促期间CPU冲到95%,其实是正常负载,结果告警把值班同学半夜叫起来三次。
  • 动态基线:系统自动学习历史数据,判断当前值是否偏离常态。我建议核心业务都用这个,虽然配置起来麻烦点,但准确率高很多。

嗯,这里要注意:动态基线不是万能的。我曾经遇到过一个场景,业务流量突然翻倍,动态基线直接崩了——因为它没见过这种模式。所以,动态基线 + 静态兜底才是王道。

1.3 告警生成:从「异常」到「事件」的跃迁

检测到异常之后,系统会生成一条告警事件。这个事件长什么样?我给大家看个典型结构:

{
  "alert_id": "alert_20240315_001",
  "source": "prometheus",
  "metric": "cpu_usage_percent",
  "value": 95.2,
  "threshold": 90,
  "severity": "critical",
  "timestamp": 1710489600,
  "labels": {
    "host": "web-01",
    "env": "production",
    "team": "platform"
  },
  "annotations": {
    "summary": "CPU使用率超过90%",
    "description": "web-01 当前CPU使用率95.2%,已持续5分钟"
  }
}

看到没?一个完整的告警事件包含:谁(source)、什么(metric)、多严重(severity)、什么时候(timestamp)、上下文(labels/annotations)

我的经验:labels 和 annotations 一定要写清楚。很多团队只写个「CPU高」,值班同学根本不知道是哪台机器、哪个业务。我后来强制要求:labels 必须包含 host、env、service 三个字段。

1.4 告警生命周期:从生到死的完整旅程

告警不是发出去就完事了。它有自己的生命周期。我画了张图,大家一看就明白:

告警生命周期流程图 指标采集 CPU/内存/延迟 异常检测 阈值/基线判断 告警生成 事件结构化 事件分发 通知/派单 正常 → 不处理 告警状态流转 触发中 告警中 已恢复 已关闭 告警从触发到关闭,经历完整的状态流转,每个状态都有对应的处理动作

这张图展示了告警的完整生命周期。我重点说几个关键状态:

  • 触发中:系统刚检测到异常,还没正式生成告警。这个阶段可以做「预聚合」——比如5分钟内同一个指标连续触发,合并成一条。
  • 告警中:正式告警,需要人工处理。我建议这个阶段自动带上「关联信息」——比如这台机器最近有没有变更、有没有其他告警。
  • 已恢复:指标恢复正常。很多人觉得恢复告警不重要,其实错了。我曾经因为没收到恢复通知,白白排查了两个小时。
  • 已关闭:人工确认问题已解决。这个状态很重要,它意味着告警的生命周期正式结束。
避坑指南:我曾经遇到过告警「死循环」——指标在阈值上下反复横跳,导致告警不断触发-恢复-触发。后来加了「抖动抑制」:恢复后至少5分钟不再触发,才算真正恢复。

1.5 告警事件的「身份证」

每个告警事件都应该有唯一的标识。我见过有人用时间戳+机器名做ID,结果同一台机器同一时间触发多个告警,ID就冲突了。

我推荐的做法:

字段 说明 示例
alert_id 全局唯一ID alert_20240315_001
fingerprint 去重指纹(相同告警合并用) md5(source+metric+labels)
instance_key 实例标识 web-01:9090

fingerprint 这个字段特别重要。我举个例子:同一台机器CPU持续高,每10秒触发一次告警。如果没有去重,一小时内就是360条告警。有了fingerprint,系统就知道「哦,这是同一条告警的重复」,直接合并成一条,只更新时间和次数。

我的习惯:fingerprint 用 MD5(source + metric + labels) 生成。这样只要来源、指标、标签一样,就认为是同一条告警。labels 里要排除时间戳这种会变的字段。

1.6 告警的「出生证明」

最后,我想聊聊告警的元数据。每条告警生成时,都应该记录它的「出生证明」——谁生的、怎么生的、为什么生。

我见过最糟糕的情况:告警来了,但没人知道这个告警是怎么配置的。是哪个监控项?阈值是多少?谁改过配置?全都不清楚。

所以我建议,告警事件里必须包含:

  • 告警规则ID:指向具体的监控规则配置
  • 规则版本号:规则每次变更都升级版本
  • 最后修改人:谁改的规则
  • 规则生效时间:这条规则什么时候开始生效的

有了这些信息,排查问题就方便多了。我记得有一次线上告警异常增多,一查发现是实习生改了阈值,从90%改成了80%。嗯,从那以后我加了个规则:修改阈值必须经过二级审批。

好了,告警的诞生就聊到这里。从指标采集到事件生成,每一步都有坑,每一步也都有优化空间。下一节咱们聊聊告警到了之后,怎么处理、怎么降噪——那才是真正考验运维功底的地方。


公众号:蓝海资料掘金营,微信deep3321