告警条件设计:基于指标、日志、事件

告警条件的设计,说白了就是回答三个问题:什么时候要报警?用什么数据来判断?怎么组合才不误报? 我个人习惯把数据源分成三类 —— 指标、日志、事件。这三类各有脾气,组合起来才能覆盖真实场景。

核心原则:单一数据源容易漏报或误报,交叉验证才是王道。

1. 指标型条件 —— 数字会说话

指标是最常见的告警源。CPU、内存、延迟、错误率……这些都是数值型时间序列。我刚开始做监控时,只会设一个静态阈值,比如 CPU > 90% 就报警。结果半夜被叫起来,发现只是业务高峰期的正常波动。后来我学会了动态阈值和速率派生。

常见指标模式

  • 静态阈值:直接比较数值大小。适合已知安全边界的指标。
  • 同比/环比:和过去同一时段比。适合有周期性的业务。
  • 聚合速率:每秒/每分钟的变化率。比如 HTTP 5xx 速率突增。
  • 百分位值:P99 延迟 > 500ms,比平均值更敏感。

举个 PromQL 的例子,检测 5 分钟内的错误率持续上升:

# 5分钟错误率同比上周同一时段增长超过50%
(
  sum(rate(http_requests_total{status=~"5.."}[5m]))
  /
  sum(rate(http_requests_total[5m]))
)
/
(
  sum(rate(http_requests_total{status=~"5.."}[5m] offset 1w))
  /
  sum(rate(http_requests_total[5m] offset 1w))
) > 1.5

💡 经验:不要用平均值。我踩过的坑 —— 平均延迟正常,但 P99 已经飙到 3 秒,前端用户早炸了。用百分位或分位数更靠谱。

2. 日志型条件 —— 文字里藏着凶器

日志告警比指标更直接。但你想想看,每天几 TB 的日志,总不能每条都报警。关键是从非结构化文本中提取结构化信号。

日志告警的三种粒度

粒度例子适用场景
关键字匹配“OutOfMemoryError”已知异常模式
正则表达式“Connect timeout after \d+ms”可变参数的错误
模式频率1分钟内同一错误出现10次以上短时故障风暴

我曾经因为只配了关键字告警,忽略了“Connection reset by peer”这种变体,结果服务挂了半小时才被用户通知。后来我改用正则并加了频率窗口:

# 示例:Elasticsearch 查询
{
  "query": {
    "bool": {
      "must": [
        { "regexp": { "message": "Error|Exception|Failed" } },
        { "range": { "@timestamp": { "gte": "now-1m" } } }
      ]
    }
  },
  "aggs": {
    "error_count": { "value_count": { "field": "message.keyword" } }
  }
}

⚠️ 注意:日志量级过大时,聚合查询会成为性能瓶颈。建议先做流式统计(比如 Flink、Kafka Streams),落盘前就判断是否超标。

3. 事件型条件 —— 变化本身就是信号

事件不是数值,也不是文本,而是“发生了某件事”:部署上线、配置变更、服务重启、证书过期……这类告警往往需要和其他数据源联动。

典型事件告警场景

  • 部署后指标异常:新版本上线后 5 分钟内错误率突增。
  • 配置变更触发的连锁反应:某服务的超时配置被修改,随后下游出现大量 503。
  • 证书即将过期:提前 7 天告警,你总不想半夜去换证书吧?

事件告警的难点在于关联性。一个事件本身可能无害,但组合起来就要命。我自己的做法是给每个事件打标签(name、source、severity),然后用规则引擎做时序窗口匹配:

# 伪代码:事件+指标组合
WHEN
  event.name == "deploy_start" AND
  metric.error_rate > 5% AND
  duration 300s
THEN
  alert("部署疑似引入回归,请回滚")

4. 组合条件 —— 别让单点骗了你

单一数据源的告警就像单腿走路。我最怕的误报就是“日志里出现了 Error 但业务正常”,或者“CPU 高但负载低”。所以条件设计时,我习惯用与/或/非逻辑组合:

组合方式含义例子
AND全部满足才告警指标高 AND 日志里有对应错误
OR任一满足就告警P99 > 500ms OR 错误率 > 5%
NAND不满足所有用于抑制告警:维护窗口内不告警
时序窗口一段时间内持续异常5 分钟内连续 3 个采集点都超标

别忘了沉默期和衰减。同一问题重复告警 = 噪音。我一般设置相同告警 1 小时内只发一次,除非状态改变。

5. 一张图看清告警条件设计

下面这张图把三类数据源和组合逻辑串起来了。你可以把它当作自己设计告警规则的“地图”。

告警条件设计框架图 告警条件设计框架 📊 指标 CPU / 延迟 / 错误率 📋 日志 关键字 / 正则 / 频率 🔔 事件 部署 / 配置 / 证书 告警规则引擎 AND / OR / NOT / 时序窗口 静态阈值 / 动态阈值 适配指标 关键词 / 正则 / 聚合 适配日志 事件标签 / 关联 适配事件 🚨 告警管道 抑制 / 沉默 / 升级 避免告警风暴

6. 避坑指南

最后说几个我踩过的坑,希望你别再重蹈覆辙。

  • 阈值设得太死:我曾给磁盘使用率设了 85% 告警,结果每周扩一次盘。后来改为 80% 警告、90% 严重,配合预测增长趋势,清净多了。
  • 忽略日志采样:日志量大的时候,全文索引慢得可怕。我用 Logstash 先做采样,只保留 ERROR 级别且去重后的日志,告警性能提升 10 倍。
  • 事件没有去重:一次集群滚动重启,产生了 3000 个“服务停止”事件。如果没有窗口去重,告警系统直接崩溃。我当时加了 5 分钟内相同 event_id 只发一次。
  • 组合条件缺少超时:AND 条件里,如果两个信号时间差太大(比如指标滞后事件 2 分钟),告警就不会触发。我一般用 1 分钟的滑动窗口做对齐。

调试小技巧:先在不发送真实告警的干跑模式下测试规则。用历史数据回放,看规则能不能命中已知故障。我就靠这个发现了不少漏报。

告警条件设计不是一蹴而就的。你需要根据业务变化持续调整。指标、日志、事件这三驾马车,用好了就是你的千里眼和顺风耳。希望这一章的内容能帮你少走些弯路。