最近在解决一个挺有意思的问题,该问题可以抽象简化为:如何检测外部依赖接口发生异常。如果是在中小公司,那么这个问题其实是不需要解决的,从研发层面规范接口的格式,并规定依赖接口必须达到要求的可用性,只要调用成功率低于规范就进行告警。不幸的是,这个方法在当前的BU中是推不动的,是为背景。
简单的对接口调用失败量对齐时间轴看了一下,这是一个典型的时序数据异常检测问题。
从分类看,当前发展阶段的时序异常检测算法和模型可以分为一下几类:
- 统计模型:优点是复杂度低,计算速度快,泛化能力强悍。因为没有训练过程,即使没有前期的数据积累,也可以快速的投入生产使用。缺点是准确率一般。但是这个其实是看场景的,并且也有简单的方法来提高业务层面的准确率。这个后面会提到。
- 机器学习模型:鲁棒性较好,准确率较高。需要训练模型,泛化能力一般。
- 深度学习模型:普遍需要喂大量的数据,计算复杂度高。整体看,准确性高,尤其是近段时间,强化学习的引入,进一步巩固其准确性方面的领先优势。
而我们希望在9月份就能够上线运行,并且没有历史数据,更不要提打标数据了。因此,只能选择统计模型作为一期落地的方案。而在统计模型中,twitter 在2015年发布的 AnomalyDetection 自然是翘楚。如果你正好使用 R 语言,那么直接上手就可以用。如果你需要 pure python 版本,推荐使用 Twitter’s Anomaly Detection in Pure Python.
S-H-ESD 原理
twitter 公开的异常检测算法的核心是使用了S-H-ESD异常检测算法。这种算法的思想是将时序数据使用 STL 分解,然后将分解的余项使用 Grubbs’ Test 进行异常点的检测(实际使用的算法考虑了极值异常点对整体的影响,实际使用的是的Grubbs’ Test变形)。关于算法的细节可以参看 twitter 发布的论文 Automatic Anomaly Detection in the Cloud Via Statistical Learning. 显然,这个算法之所以有效的两个关键就是 STL 和 Grubbs’ Test。
STL 将时序数据分解为 趋势 + 周期 + 余项:
直观上,可以将趋势项理解为时序数据的骨骼;周期数据是数据的振幅;余项是则是消除趋势和周期数据后,相对平滑稳定的“皮毛”。而这种皮毛数据是符合 Grubbs’ Test 假设中正常数据正态分布的。反之,则被 Grubbs’ Test 认为是异常数据。
因此,S-H-ESD 只适用于周期性数据。对于无周期性或数据变化特别剧烈的时序数据,S-H-ESD都不是好的选择。
S-H-ESD 用于生产环境
S-H-ESD 原理简单,理论效果也非常不错,基本起手能达到 40% ~ 60% 的准确率。但是实际应用中经常会遇到以下典型的误报情况:
而这种误报其实很难从算法本身消除,即使消除了其实也没有泛化性。一种简单的思路是引入更多数据和规则:
- 上图中我们只是用的接口的报错量作为时序数据,单村在报错量上提高准确性在统计模型这个大前提下边际成本已经很高了。因此,可以考虑引入接口调用量和成功率来综合判断该点是否真正异常。
- 结合实际业务,设定一些简单的规则减少误报量。对于我们的场景,可以设定的规则有报错量的基础阈值、报错点的持续时长等。
S-H-ESD 不是银弹,结合多维数据和业务规则以后,准确率基本达到了我们的预期。S-H-ESD 也不是终点,确切说是我们顺便解决当前问题,同时收集异常数据的手段。未来,我们会尝试结合深度学习模型提高异常检测点上的准确性,同时融合多维数据,将点上的异常检测逐步整合为线和面上的检测能力。