数据采集与预处理:数据源类型与清洗实战
数据采集与预处理,说白了就是给异常检测模型「喂饭」。饭喂得好不好,直接决定模型能不能吃饱、吃对。我见过太多团队花大把时间调模型,结果数据源没处理好,最后告警全是噪音。今天咱们就把这块硬骨头啃下来。
数据源类型:Metrics、Logs、Traces
体量异常检测依赖三类数据源,我习惯叫它们「运维三剑客」。每类数据都有自己的脾气,采集方式也完全不同。
| 数据源 | 典型格式 | 采集频率 | 存储量级 | 异常检测价值 |
|---|---|---|---|---|
| Metrics | Prometheus 指标、StatsD | 秒级~分钟级 | GB/天 | 趋势突变、阈值越界 |
| Logs | JSON、Syslog、文本 | 事件驱动 | TB/天 | 错误率、关键字爆发 |
| Traces | OpenTelemetry、Jaeger | 请求采样 | GB~TB/天 | 延迟异常、调用链断裂 |
我个人习惯把 Metrics 作为第一道防线。为什么?因为它轻量、实时、容易做基线。Logs 虽然信息量大,但噪声也多。Traces 呢,适合做根因定位,但采样率一低就容易漏掉异常。
数据清洗:去掉那些「脏东西」
数据采集上来,第一件事不是分析,而是清洗。我在项目中遇到过好几次,告警平台半夜狂响,查了半天发现是采集器挂了,发了一堆空值。你说气不气人?
常见的脏数据有这几类:
- 重复数据:采集器重试导致同一时间戳多条记录
- 异常值:传感器故障产生的 -1、999999 等明显不合理数值
- 格式错误:Log 里字段错位、JSON 解析失败
- 时间戳乱序:采集端时钟不同步导致数据「穿越」
清洗策略我一般分三步走:
- 去重:按时间戳+标签做唯一键,保留第一条或最后一条
- 过滤:设定合理范围,比如 CPU 使用率 0~100,超出直接丢弃
- 校验:对 Log 做正则匹配,格式不对的打入死信队列
# 一个简单的 Metrics 清洗示例(Python)
def clean_metric(data_point):
# 去重:相同时间戳和标签只保留一个
key = (data_point['timestamp'], frozenset(data_point['labels'].items()))
if key in seen_keys:
return None
# 范围过滤
if data_point['value'] < 0 or data_point['value'] > 100:
return None
# 时间戳合理性检查
now = time.time()
if abs(data_point['timestamp'] - now) > 3600:
return None
return data_point
缺失值处理:别让模型「饿肚子」
数据缺失在运维场景里太常见了。机器重启、网络抖动、采集器 OOM,都会导致数据断点。你想想看,如果模型在某个时间窗口里只有 50% 的数据,它怎么判断体量是否异常?
常用的处理方法有四种:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 前向填充 | 短时间缺失(<5 个点) | 简单、保持趋势 | 会掩盖突变 |
| 线性插值 | 周期性指标 | 平滑、合理 | 计算开销稍大 |
| 均值填充 | 稳定指标(如内存使用率) | 快速、稳定 | 会拉低方差 |
| 标记缺失 | 长时间缺失(>10 个点) | 不引入偏差 | 模型需支持缺失值 |
我个人习惯的做法是:先判断缺失比例。低于 5% 的,用前向填充;5%~20% 的,用线性插值;超过 20% 的,直接标记为「数据不可用」,不参与异常检测。为什么?因为强行填充太多假数据,会让模型产生幻觉。
数据标准化:让不同指标站在同一起跑线
QPS 可能是几万,CPU 是百分之几,延迟是毫秒级。这些指标的量纲完全不同,如果不做标准化,模型会天然偏向数值大的指标。说白了,就是「以大欺小」。
常用的标准化方法:
- Z-score 标准化:减去均值,除以标准差。适合数据近似正态分布的场景
- Min-Max 缩放:映射到 [0,1] 区间。适合有明确上下界的指标
- Robust 缩放:用中位数和四分位距。适合有离群点的数据
# Z-score 标准化示例
def zscore_normalize(series):
mean = np.mean(series)
std = np.std(series)
if std == 0:
return series # 全相同值,不做处理
return (series - mean) / std
# Min-Max 缩放示例
def minmax_normalize(series, min_val, max_val):
if max_val == min_val:
return series
return (series - min_val) / (max_val - min_val)
嗯,这里要注意:标准化参数(均值、标准差、最大最小值)必须在训练集上计算,然后应用到测试集。我见过有人对整个数据集做标准化,结果模型在线上表现一塌糊涂——因为线上数据分布变了,标准化参数没跟着更新。
知识体系总览
下面这张图把数据采集与预处理的完整流程串起来了。你可以把它当作一个检查清单,每次搭建检测系统时对照着走一遍。
从这张图能看出来,数据预处理不是一步到位的。它是一个流水线:采集 → 清洗 → 补缺 → 标准化。每一步的输出都是下一步的输入。我在实际项目中,会把每一步都做成独立的处理单元,方便调试和替换。比如某个数据源突然格式变了,我只需要改清洗那一步,其他环节完全不受影响。
好了,数据采集与预处理这块就聊到这儿。记住一句话:垃圾数据进,垃圾结果出。把基础打牢,后面的异常检测才能站得住脚。