3. 告警源接入:Prometheus、Zabbix、ELK 等常见数据源对接
告警源接入,说白了就是解决一个问题:我怎么把不同系统的告警统一收上来。
很多人觉得,这不就是调个 API 嘛,有什么好讲的?
嗯,我刚开始也是这么想的。直到有一次,我在项目里同时接到三个系统的告警——Prometheus 弹出来的、Zabbix 发过来的、还有个是 ELK 跑出来的日志告警。三个人各报各的,同一个问题重复报了五六次。从那以后,我才意识到:告警源对接,真正的坑不在于「能不能接」,而在于「怎么接得干净、接得规范」。
3.1 明确目标:告警源接入到底要解决什么?
我个人认为,核心目标就三点:
- 统一格式:所有源的数据结构必须对齐到一个标准 payload。
- 去重与关联:同一故障在多源中被触发时,只产生一条顶层告警。
- 无侵入:改造尽量在网关层做,别动原系统。
核心原则:告警源接入是一次「翻译」工作——把各系统的方言,翻译成告警中心听得懂的普通话。
3.2 Prometheus 对接:主动拉取 + webhook 双通道
Prometheus 在 Kubernetes 环境里用得最多。它的告警机制分两步:
- 规则评估:Prometheus Server 定时跑告警规则,产生告警事件。
- Alertmanager 处理:负责分组、抑制、静默,以及发送通知。
我们对接 Prometheus,本质上就是对接 Alertmanager。
3.2.1 方式一:通过 Alertmanager Webhook Receiver
这是最推荐的方式。在 alertmanager.yml 里配一个 webhook:
receivers:
- name: 'my-webhook'
webhook_configs:
- url: 'http://alert-center:8080/api/v1/receive'
send_resolved: true
这样做的好处:你只需要在接收端解析 JSON,不需要任何 Prometheus 特定的适配器。
小技巧:记得在接收端校验 Alertmanager 的 signature header,防止伪造告警。我在生产上见过有人直接把 webhook 地址暴露公网,结果被刷了几万条假告警。
3.2.2 方式二:直接拉取 Alertmanager API
有些场景下,你不希望修改 Alertmanager 配置。可以用定时任务拉它的 API:
GET /api/v2/alerts
返回格式固定,直接用 JSON 解析即可。但注意:这种方式有延迟,不适合对实时性要求高的场景。
3.2.3 数据格式对齐
Prometheus 的告警 payload 结构大致如下:
| 字段 | 说明 | 示例 |
|---|---|---|
| status | firing / resolved | firing |
| labels | 标签(含 severity,alertname) | {"severity":"critical","alertname":"HighCPU"} |
| annotations | 可读描述 | {"summary":"CPU > 90%"} |
| startsAt | 触发时间 | 2025-03-21T10:00:00Z |
注意:有些团队在 labels 里塞太多自定义信息。我建议只保留关键字段,其他放 annotations 里,否则告警路由规则会变得非常臃肿。
3.3 Zabbix 对接:走 API 还是走 script?
Zabbix 是传统企业里的老兵。它的对接方式比较「厚重」,但也稳。
我个人习惯两种方式:
3.3.1 通过 Zabbix API 轮询
Zabbix 提供了成熟的 JSON-RPC API。用 Python 写个定时任务,调用 problem.get 拉取当前问题:
zabbix_host = "http://your-zabbix/api_jsonrpc.php"
payload = {
"jsonrpc": "2.0",
"method": "problem.get",
"params": {
"recent": True,
"sortfield": ["eventid"],
"sortorder": "DESC"
},
"auth": ,
"id": 1
}
优点是不需要修改 Zabbix 本身的部署。缺点是延迟依赖轮询间隔。
3.3.2 通过 Zabbix Action 发 webhook
Zabbix 从 5.0 开始支持 Webhook 媒体类型。你可以在 Management → Media Types 里配一个 webhook,然后在 Action 里引用它。
这样做的好处是实时性强。但配置起来有点绕,我第一次配的时候整整花了半天。
经验之谈:Zabbix 的 Trigger 严重级别(Information → Disaster)和 Prometheus 的 severity 概念不完全一致。建议在转换层做映射,比如 Zabbix 的 "Disaster" 映射为 Prometheus 的 "critical"。
3.4 ELK(Elastic Stack)对接:日志驱动的告警
ELK 的告警源比较特殊——它是基于日志模式匹配的。你不需要主动告警,而是告警中心去订阅它的搜索结果。
3.4.1 方式一:ElastAlert
ElastAlert 是一个开源的日志告警规则引擎。它会定期查询 Elasticsearch,把匹配到规则的日志包装成告警事件。
举个例子:
es_host: your-es-cluster
rules:
- name: "error_count_rule"
type: frequency
index: app-logs-*
timeframe:
minutes: 5
num_events: 10
filter:
- query:
query_string:
query: "level: ERROR"
ElastAlert 的输出可以对接 webhook。我们在接收端只要解析它的结果即可。
3.4.2 方式二:Watcher(收费版)
如果你用的是 Elastic 的付费版本,可以使用 Watcher 原生功能。配置方式类似,但更集成。不过我不太推荐在自建环境里用,因为 license 限制挺多的。
避坑:我曾经遇到过一个场景:日志里某个错误每分钟出现一次,ElastAlert 每分钟触发一次告警。结果一天下来收了 1440 条。后来加了一个聚合窗口(aggregation),把 30 分钟内的同类错误合并成一条,问题才解决。
3.5 系统对接策略
不管接哪个源,我建议都经过一个统一的告警网关。这样设计的好处是:
- 源端增加时,只需要在网关配一条路由。
- 格式转换逻辑收敛在网关层,方便维护。
- 网关可以做限流、鉴权、调用链追踪。
| 源类型 | 对接方式 | 适用场景 |
|---|---|---|
| Prometheus | Webhook / API 拉取 | 云原生、Kubernetes |
| Zabbix | API 轮询 / Action Webhook | 传统监控、网络设备 |
| ELK | ElastAlert / Watcher | 日志告警、安全审计 |
| 自研系统 | 直接推送到统一接口 | 定制化场景 |
注意:无论是哪种源,接入后一定要做「源标识」标注。我见过有人不标注源,收到告警后第一反应是:这是 Prometheus 还是 Zabbix 报的?——这很尴尬。
3.6 网关层要做的四件事
- 格式标准化:把所有源的 payload 转换成统一的 JSON 结构。
- 源标记:在告警里增加
source字段,比如"source": "prometheus"。 - 租户隔离:如果有多条业务线,用
tenant_id来区分。 - 限流与降级:防止某个源突然爆发导致告警中心被冲垮。
个人习惯:我会在网关层保留原始 payload 的一个副本,放在 raw_data 字段。这样排查问题时,可以随时回溯原始数据,而不需要重新调用源端 API。
说白了,告警源接入这件事,真正考验的不是技术实现,而是你有没有把「统一入口、统一格式、统一治理」这三个理念落到系统架构里。我见过很多项目,每个源都直接对接通知通道,结果导致通知混乱、排查困难。所以,我强烈建议,所有告警先过一遍网关,再说别的。