4. 告警数据标准化:定义统一告警模型
告警数据标准化,说白了就是给所有告警定个规矩。
我见过太多团队,告警数据格式五花八门。有的用JSON,有的用XML,有的干脆就是一行文本。结果呢?告警聚合做不了,去重搞不定,根源分析更是无从谈起。
所以,第一步就是定义统一的告警模型。我习惯叫它 Alert Object。
4.1 统一告警模型(Alert Object)
一个标准的告警对象,应该包含哪些字段?我总结了一套最小必要集:
| 字段名 | 类型 | 说明 | 示例 |
|---|---|---|---|
| alert_id | string | 全局唯一ID | alert-20250321-001 |
| alert_name | string | 告警名称 | CPU使用率过高 |
| severity | enum | 告警级别 | critical |
| status | enum | 告警状态 | firing |
| source | string | 告警来源 | prometheus |
| fingerprint | string | 告警指纹 | sha256(host+alert_name) |
| labels | map | 标签集合 | {host: web-01, env: prod} |
| annotations | map | 注解信息 | {summary: "CPU > 90%"} |
| started_at | timestamp | 告警开始时间 | 2025-03-21T10:00:00Z |
| ended_at | timestamp | 告警结束时间 | 2025-03-21T10:30:00Z |
嗯,这里要注意。labels和annotations的区别。labels是用来做匹配和聚合的,annotations是给人看的描述信息。我在项目中遇到过有人把IP地址放在annotations里,结果去重时死活匹配不上——这就是典型的字段设计问题。
4.2 规范告警级别
告警级别怎么定?我见过最离谱的是分了10个级别。你想想看,运维收到告警还得先查一下这个级别代表什么,这不是添乱吗?
我个人建议,最多分4级:
- critical(严重):服务不可用,需要立即响应。比如数据库挂了、核心接口超时。
- warning(警告):指标异常,需要关注。比如CPU超过80%、磁盘使用率超过90%。
- info(信息):通知类告警。比如部署完成、配置变更。
- debug(调试):仅供开发调试使用,不触发通知。
4.3 规范告警状态
告警状态其实是个状态机。我习惯用这几种:
- firing:告警正在触发。这是初始状态。
- acknowledged:已确认。有人接手处理了。
- resolved:已解决。告警条件不再满足。
- suppressed:已抑制。被其他告警覆盖了。
状态流转很简单:firing → acknowledged → resolved。或者firing → suppressed → resolved。
为什么要有acknowledged状态?说白了就是防止多人同时处理同一个告警。我在项目中遇到过,一个告警来了,三个人同时去看,结果谁都没处理完——这就是典型的协作问题。
4.4 规范告警来源
告警来源字段,我建议用统一的命名规范。比如:
- Prometheus →
prometheus - Zabbix →
zabbix - 自定义脚本 →
custom_script - 云监控 →
cloud_monitor
你可能会问,为什么不用IP或者主机名?因为来源是逻辑概念,不是物理概念。同一个Prometheus实例可能监控多个集群,你只需要知道告警来自Prometheus就够了。
4.5 告警指纹去重机制
这是本章的重头戏。告警去重,说白了就是判断两条告警是不是同一个问题。
我见过最原始的做法:直接用告警名称去重。结果呢?同一个主机CPU告警,第一次是80%,第二次是90%,被当成两条不同的告警处理了。
正确的做法是设计 告警指纹(Fingerprint)。
指纹的生成逻辑:
fingerprint = sha256(alert_name + sorted(labels))
为什么用sha256?因为要保证唯一性。为什么排序labels?因为JSON的key顺序是不确定的。
举个例子:
告警A:{alert_name: "cpu_high", labels: {host: "web-01", env: "prod"}}
告警B:{alert_name: "cpu_high", labels: {env: "prod", host: "web-01"}}
指纹A = sha256("cpu_high" + "env=prod,host=web-01")
指纹B = sha256("cpu_high" + "env=prod,host=web-01")
// 指纹相同,判定为重复告警
我在项目中遇到过一个问题:同一个主机,CPU告警和内存告警同时触发。如果只用主机名做指纹,这两条告警会被当成同一条。所以指纹一定要包含告警名称。
4.6 去重策略实战
有了指纹,去重就简单了。我常用的策略:
- 时间窗口去重:在5分钟内,相同指纹的告警只保留一条。
- 状态去重:如果告警已经acknowledged,相同指纹的新告警自动suppressed。
- 级别去重:如果已有critical告警,相同指纹的warning告警自动合并。
4.7 知识体系总览
下面这张图,是我对本章知识体系的总结。你看一眼就能明白告警标准化的全貌:
你看,整个体系其实就四个层次:字段定义打基础,级别规范定优先级,状态机管生命周期,指纹去重解决重复问题。把这四层做好了,告警数据标准化就算完成了80%。
剩下的20%是什么?是持续优化。比如有些团队会把告警指纹设计得更复杂,加入时间窗口、加入上下文信息。但不管怎么优化,核心逻辑不变——用指纹来唯一标识一个告警事件。
好了,这一章就到这里。告警数据标准化是告警管理系统的地基,地基打不牢,后面所有功能都是空中楼阁。下一章我们聊聊告警路由和通知策略,那才是真正让告警发挥价值的地方。
公众号:蓝海资料掘金营,微信deep3321