4. 异常事件标准化接入
责任路由要做得准,前提是输入要干净。异常事件标准化接入这一层,本质上是在“事件产生”与“路由决策”之间建立一道加工工序:把来自监控、日志、工单、业务系统、人工上报等异构来源的原始信号,转换成字段统一、语义明确、可去重、可聚合、可补全的标准事件,再交给路由引擎。如果这一层缺失,路由规则再精细也会被脏数据拖垮——同一个故障被拆成十几条事件重复派单,或者关键字段为空导致规则无法命中。
统一异常事件格式:先定契约,再谈对接
标准事件格式的核心是“最小完备字段集”。字段太少,路由无法判断;字段太多,接入成本高且容易缺项。建议以如下字段作为标准事件契约的基线,各来源系统按此映射:
| 字段 | 含义 | 是否必填 | 示例 |
|---|---|---|---|
| event_id | 标准事件全局唯一标识 | 是 | evt-20240612-000871 |
| source_system | 来源系统标识 | 是 | prometheus / zabbix / itsm |
| source_event_id | 来源侧原始事件ID | 是 | alert-9f3a21 |
| event_type | 事件类型(可用性/性能/容量/安全/业务) | 是 | availability |
| severity | 严重级别(P0–P3) | 是 | P1 |
| entity | 受影响对象(服务/主机/数据库/接口) | 是 | order-service |
| entity_type | 对象类型 | 是 | microservice |
| region / zone | 地域与可用区 | 否 | cn-east-1 / az-b |
| metric / signal | 触发指标或信号名 | 否 | http_5xx_rate |
| observed_value | 观测值 | 否 | 0.37 |
| threshold | 阈值 | 否 | 0.05 |
| first_seen | 首次出现时间(UTC毫秒) | 是 | 1718150400000 |
| last_seen | 最近出现时间 | 是 | 1718150460000 |
| owner_hint | 来源侧给出的责任线索 | 否 | team-payment |
| raw_payload | 原始报文(保留追溯) | 否 | {...} |
字段定义要同时约定“语义”和“取值规范”。例如 severity 必须映射到 P0–P3 四档,来源系统的“critical/warning/info”要建立固定映射表;entity 必须使用 CMDB 中的标准服务名,而不是主机名或容器名混用。时间统一用 UTC 毫秒时间戳,避免跨时区比较出错。这些约定写进契约文档,接入方按契约实现适配器,后续路由规则才能稳定引用字段。
来源系统对接:适配器模式与字段映射
对接不建议让路由引擎直接消费各来源的原始格式,而是在中间加一层“接入适配器”。每个来源系统对应一个适配器,职责是:拉取或接收原始事件、按映射表转换字段、调用标准化校验、写入标准事件总线。适配器可以做成配置驱动,把映射关系外置为配置,新增来源时只加配置不改代码。
以 Prometheus Alertmanager 为例,其 webhook 报文包含 labels、annotations、startsAt 等字段。适配器需要把 labels.alertname 映射到 metric/signal,labels.instance 映射到 entity,annotations.summary 映射到描述,startsAt 转成 first_seen。Zabbix 的 trigger 事件则要把 trigger.severity 映射到 severity,host.name 映射到 entity。ITSM 工单系统作为人工上报来源,需要把工单标题、影响范围、紧急程度映射到标准字段,并标记 source_system=itsm。
对接过程中要处理三类常见问题:一是字段缺失,适配器应填充默认值并打上“字段缺失”标记,而不是直接丢弃事件;二是枚举值不匹配,映射表要覆盖来源侧全部取值,未覆盖的落入 unknown 并告警;三是时间格式不一致,统一在适配器内完成转换。适配器还应做基础校验,比如 event_id 非空、severity 在允许集合内,校验失败的事件进入隔离队列,避免污染主流程。
事件去重与聚合:从“告警风暴”到“一个故障”
去重解决的是“同一事件被重复上报”,聚合解决的是“同一故障的多个相关事件被合并”。两者目标一致:让路由引擎看到的是“一个可处理的问题”,而不是成百上千条碎片。
去重通常基于“去重键”。去重键由若干字段组合而成,例如 source_system + entity + metric + severity。当两条事件的去重键相同,且时间窗口重叠(比如 last_seen 与 first_seen 间隔小于 5 分钟),则判定为重复,只保留一条,更新 last_seen 并累加重复计数。去重键的选择要谨慎:太宽会把不同问题误合并,太窄则去重效果差。建议按事件类型分别定义去重键,可用性类事件用 entity + metric,业务类事件用 entity + 业务单据号。
聚合则是在去重基础上,把“同一实体、同一时间段、存在因果或关联关系”的多个事件合并为一个聚合事件。例如一台主机宕机,会同时触发主机不可达、其上服务不可用、数据库连接失败等多条事件。聚合策略可以按实体层级聚合:先按主机聚合,再按服务聚合,最终形成一个“根因事件 + 影响事件列表”的结构。聚合事件保留子事件列表,路由时以根因事件为主,影响事件作为上下文。
示例:聚合规则配置片段
aggregation:
- name: host-down-cluster
match:
entity_type: host
event_type: availability
group_by: [host_id, region]
window_seconds: 300
root_cause_priority:
- metric: host_unreachable
- metric: service_unavailable
output:
event_type: aggregated_availability
severity: max(children.severity)
child_events: keep
去重与聚合都会改变事件数量,因此必须保留“原始事件—标准事件—聚合事件”的追溯链。标准事件里保留 source_event_id 和 raw_payload,聚合事件里保留 child_event_ids,这样后续复盘时能还原完整现场。
元数据补全:让路由规则有据可依
来源系统给出的字段往往不足以支撑路由决策。比如一条告警只说了“order-service 5xx 升高”,但路由需要知道这个服务属于哪个业务域、哪个团队负责、依赖哪些下游、SLA 等级是多少。这些信息不在告警里,需要从 CMDB、服务目录、组织架构、SLA 台账等系统补全。
元数据补全的典型动作包括:用 entity 查询 CMDB 得到 owner_team、business_domain、sla_tier、upstream/downstream;用 region 查询地域责任表得到 oncall 团队;用 event_type 和 severity 查询 SLA 矩阵得到响应时限和升级路径。补全后的标准事件才具备“可路由性”。
补全过程要处理“查不到”的情况。如果 entity 在 CMDB 中不存在,不能简单丢弃,而应标记 metadata_missing=true,并路由到“元数据治理队列”由人工确认。这类事件往往暴露了 CMDB 数据质量问题,是治理的重要输入。补全结果建议缓存,减少对 CMDB 的实时查询压力,但缓存要有失效策略,比如服务归属变更后 5 分钟内生效。
整条流水线走完后,进入路由引擎的标准事件应当满足几个可检验的条件:event_id 全局唯一且非空;severity 在 P0–P3 集合内;entity 能在 CMDB 中解析到归属;first_seen/last_seen 为 UTC 毫秒且 last_seen ≥ first_seen;重复事件已合并且重复计数可查;聚合事件保留子事件列表;元数据补全字段完整或明确标记缺失。这些条件可以作为接入层的验收清单,逐条核对后再放行到路由环节。
接入层的一个实用原则是“宁可标记,不可丢弃”。字段缺失、枚举未知、元数据查不到的事件,都应带着标记继续流转,而不是被静默过滤。被丢弃的事件往往正是最需要人工介入的异常,静默丢弃会让路由覆盖率虚高,掩盖真实问题。
当接入层稳定运行后,可以进一步统计几个指标来评估质量:标准事件与原始事件的数量比(反映去重聚合效果)、元数据补全成功率、字段缺失率、隔离队列积压量。这些指标持续恶化时,说明来源系统或 CMDB 出现了变化,需要及时回到适配器或元数据治理环节排查。标准化接入不是一次性工程,而是需要持续维护的数据契约。