3. 历史数据基础:告警时间序列数据的采集、清洗与存储格式
告警降噪阈值策略的 A/B 测试,其核心假设是“历史告警行为能够预测未来模式”。因此,历史数据的质量直接决定了阈值验证的可信度。本章聚焦于如何从生产环境中可靠地采集、清洗并格式化存储告警时间序列数据,为后续的统计分析和策略模拟打下坚实基础。
3.1 告警时间序列的数据特征与采集源
告警数据本质上是一种带有时间戳、状态和属性的离散事件流。与连续型监控指标(如 CPU 使用率)不同,告警事件具有突发性、稀疏性和多维度标签的特点。常见的采集源包括:
| 采集源 | 数据格式 | 典型字段 | 采集方式 |
|---|---|---|---|
| Prometheus Alertmanager | JSON / Webhook | alertname, instance, severity, startsAt, endsAt, annotations | Webhook Receiver / API 拉取 |
| Zabbix | JSON / XML | eventid, clock, value, triggerid, host, priority | API 轮询 / 数据库直连 |
| 自研监控系统 | Protobuf / Avro | rule_id, entity, status, first_occurred, last_occurred, count | 消息队列(Kafka)订阅 |
| 日志告警系统 | JSON Lines | log_source, pattern, level, timestamp, host, message | Filebeat / Fluentd 采集 |
关键原则:采集时务必保留告警的 开始时间 和 结束时间(或恢复时间)。仅保留触发时间会导致无法计算告警持续时间、恢复时长等关键特征,严重影响降噪策略的评估。
3.2 数据清洗:从原始事件到可用时间序列
原始告警数据通常包含大量噪声、重复和格式不一致问题。清洗流程分为以下四个核心步骤:
- 去重与合并(Deduplication & Merging):同一告警规则在短时间内可能多次触发。需根据
alertname + instance + fingerprint进行分组,合并重叠的告警区间,保留最早开始时间和最晚结束时间。 - 时间戳对齐(Timestamp Alignment):不同采集源的时间戳精度可能不同(秒级 vs 毫秒级)。统一转换为 Unix 时间戳(秒级),并处理时区偏移,确保所有数据在同一时间轴上。
- 异常值过滤(Outlier Filtering):剔除明显异常的数据点,例如:开始时间晚于结束时间、时间戳为未来时间、持续时间超过 30 天(通常为误报或系统故障)。
- 标签标准化(Label Normalization):统一标签键名(如
host与instance统一为entity),去除无意义的标签(如alert_id自增 ID),保留用于分组和聚合的维度。
清洗效果指标:经过上述清洗后,数据量通常减少 20%~40%,但数据质量显著提升。建议在清洗前后分别记录行数、唯一告警规则数、时间跨度,作为数据质量报告的基础。
3.3 存储格式:面向分析的时间序列表设计
清洗后的数据需要以适合分析查询的格式存储。推荐使用列式存储(如 Parquet)或时序数据库(如 ClickHouse、InfluxDB)。以下是一个通用的告警事件表结构设计:
-- 告警事件明细表 (alert_events)
CREATE TABLE alert_events (
event_id UInt64, -- 全局唯一事件 ID
rule_name String, -- 告警规则名称
entity String, -- 告警对象(主机、服务、容器)
severity String, -- 严重级别 (critical, warning, info)
status String, -- 当前状态 (firing, resolved)
start_ts DateTime, -- 告警开始时间
end_ts DateTime, -- 告警结束时间(NULL 表示未恢复)
duration_sec UInt32, -- 持续时间(秒),由 end_ts - start_ts 计算
labels Map(String, String), -- 其他标签键值对
annotations String, -- 告警注释信息
ingestion_ts DateTime, -- 数据写入时间
partition_date Date -- 分区字段,按天分区
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(partition_date)
ORDER BY (rule_name, entity, start_ts);
避坑提示:不要将告警事件直接存储在关系型数据库的单表中而不做分区。告警数据量增长极快,未分区的表在查询数月数据时会导致全表扫描,A/B 测试的模拟计算将变得不可用。务必按时间(月/周)进行分区。
3.4 数据管道架构:从采集到存储的完整链路
为了支撑 A/B 测试的反复回放与验证,数据管道需要具备高吞吐、低延迟和可回溯的特性。下图展示了推荐的告警数据采集与存储架构:
3.5 数据质量校验清单
在将数据用于 A/B 测试之前,建议执行以下校验,确保数据集的完整性和一致性:
| 校验项 | 检查方法 | 合格标准 |
|---|---|---|
| 时间连续性 | 按小时统计告警事件数,检查是否存在长时间无数据窗口 | 连续缺失不超过 1 小时 |
| 状态完整性 | 检查每条告警是否都有对应的 resolved 事件 | 未恢复告警占比 < 5% |
| 标签一致性 | 统计 rule_name 和 entity 的枚举值,检查是否有异常空值 | 空值占比 < 0.1% |
| 时间戳合理性 | 检查 start_ts 是否在数据采集时间之前 | 未来时间戳占比 = 0% |
最佳实践:建议将清洗后的数据同时保存一份原始快照(Raw Snapshot),以便在发现清洗逻辑有误时能够重新处理。原始快照可以存储在廉价的对象存储(如 S3、MinIO)中,按天归档。