行为基线基础:正常行为建模思想

老实说,当初我刚接触异常检测时也犯过“见啥都觉得异常”的毛病。后来带我的老哥说了句话我一直记着:不知道什么正常,就别谈什么异常。这句话点醒了。行为基线,说白了就是给系统的“正常画个像”,然后让异常自己跳出来。

为什么非要先建基线?

你想想看,每个系统都有自己的脾气——访问量有高低峰,API调用有节假日效应,数据库连接数有昼夜规律。你要是拿一把死尺子去量,准出事。所以基线是从历史数据里长出来的活标准。它的核心思想就八个字:多数正常,少数异常。

我在一个电商监控项目里就吃过亏:硬件指标明明没变,报警却一天响几百次。后来发现——我拿的是全局均值当基线,但业务流量晚上8点翻三倍。那不是异常,那是正常规律。嗯,这坑我栽过,后面会细说。

正常行为建模的两个方向

建模方法归根结底两类:统计基线 和 时序基线。我建议你先把这两条路捋清楚,后面写算法才不会跑偏。

对比维度统计基线时序基线
核心理念用概率分布描述整体用时间模式描述变化
典型指标均值、标准差、Z-score周期分量、趋势、残差
适用场景指标稳定、无强周期有日/W/季规律
建模方式历史数据 → 统计量历史序列 → 分解/预测
检测能力发现离群点发现模式偏离
缺点忽略时间关联对突变反应慢

核心原则:统计基线更“静”,时序基线更“动”。大部分复杂系统需要两者配合,我习惯先跑个时序分解看看趋势,再在残差上做统计检测。

统计基线:拿概率说话

这是最直观的做法。假设正常行为落在某个概率范围内,比如正态分布 ±3σ 内算正常。你只需要收集一段时间的历史数据,算均值和标准差就搞定了。

举个例子:某API每秒请求数,历史均值为200,标准差为15。那么Z-score = (当前值 - 200) / 15。 |Z| > 3,我就报异常。简单粗暴,但管用。

import numpy as np

# 假设历史数据
history = [205, 198, 210, 202, 195, 208, 200, ...]
mean = np.mean(history)      # 约200
std = np.std(history)        # 约15

# 实时检测
current = 240
z = (current - mean) / std   # z ≈ 2.67

if abs(z) > 3:
    print("异常:请求量激增")
else:
    print("正常")

看起来很美好对吧?但小心两个坑:

  • 数据本身就不服从正态分布——别硬套,我是吃过亏的。碰到长尾分布(比如文件大小),建议换成中位数+四分位距(IQR)。
  • 统计基线无视时间顺序。你凌晨3点请求量20算异常吗?如果在深夜时段的历史分布里,20可能是正常。但你把全天数据混一起,20就变成离群点了。所以…

我曾经犯的错:拿24小时的总统计量去检测所有时段,结果白天报警少、夜里乱报警。后来老老实实加了个“时段分桶”,每小时的基线独立算。效果立刻好了。

时序基线:让规律自己说话

时序基线想解决的问题正是统计基线忽略的:时间关联。你的请求量、连接数、CPU使用率,今天8点的值和昨天8点的值高度相关,但和今天凌晨2点的值关系不大。

常见做法:

  • 移动平均法:取过去N个点的滑动窗口均值作为期望值,残差 = 当前值 - 移动平均。残差超阈值就报警。
  • 周期分解法(STL):把时间序列拆成趋势 + 季节 + 残差。残差异常就报。
  • 预测类模型:如ARIMA、Holt-Winters。用历史拟合模型,预测下一个值,实际值和预测值的差 > 阈值则异常。

我记得在做一个IoT设备流量监控时,设备每周有固定固件升级流量脉冲。用统计基线怎么也调不平报警,换成时序分解后把“每周脉冲”当作季节分量抽掉,剩下的残差才真正代表异常。那感觉,就像把噪音滤掉了一样的清爽。

实践建议:如果业务有明显周期(比如工作日/周末),先对数据按周期分桶再建基线。分桶比高级模型更容易解释,出问题排查也快。

什么时候该用哪种?

我个人的经验法则:

  • 指标波动平稳(如系统资源利用率)→ 统计基线足够。
  • 指标有明显周期且周期稳定(如Web日活)→ 时序基线优先。
  • 指标既平稳又有周期(如数据库QPS,白天高夜里低)→ 先分时段,每个时段内做统计基线。这是性价比最高的方案。

如果你刚起步,我强烈建议从分段统计基线开始:按小时、星期几分桶,每个桶内算均值+标准差。代码简单,效果好,排查问题也直观。等业务复杂了再叠加时序模型不迟。

行为基线建模流程 原始日志 / 指标流 特征提取 & 分桶 统计基线 均值+标准差 / IQR 时序基线 周期分解 / ARIMA 阈值判定 & 异常标记 核心:建模前一定要先理解业务周期,否则基线就是错的

建基线的实用检查清单

最后分享一份我每次上线前都会过一遍的清单:

  1. 数据是否干净? 去掉历史中的异常值再算基线,否则基线自己就是歪的。
  2. 时间规律是否考虑了? 周期、趋势、节假日,一个都不能少。
  3. 阈值是否可解释? 别用黑盒调参,Z=3还是IQR×1.5,必须能对业务讲清楚。
  4. 基线是否持续更新? 场景会漂移,建议每周/每月重新拟合一次。

再说句掏心窝的话:很多时候失败不是因为算法不够先进,而是基线构建阶段就把业务理解丢了。多和运维、业务聊聊天,比多看几篇管用。