目录

一种监控报警阈值确定的思路 —— 统计分布算法

统计分布算法

统计分布算法(Statistical Distribution Algorithm):这种算法是根据数据的概率分布进行阈值设置的。比如,计算出数据的均值和标准差,通过均值加减若干个标准差来确定阈值。根据数据的分布情况,阈值的精度和敏感度较高,常见的应用场景有金融风控系统等。 统计分布算法是根据数据的概率分布来进行阈值设置的。具体步骤如下:

  1. 首先,需要计算数据集的均值和标准差。
  2. 然后,根据需要确定一个合适的标准差倍数k (通常取 2 或 3 )。
  3. 根据均值和标准差,计算上下界,公式为:
    1. upper_bound = mean + k * std_deviation
    2. lower_bound = mean - k * std_deviation
  4. 最后,设置阈值为 upper_bound 和 lower_bound 之间的某个值,根据实际情况和需求来选择。 统计分布算法是一种比较常用和实用的算法,适用于大部分的场景。但是不同的场景需要区别对待,具体的应用还需要结合实际情况来制定具体的数值

实践思路

当我们建立一个线上项目的监控系统,在项目出现异常时会想要及时被通知的需求。对于大部分已有的监控方案,大部分都提供了监控报警功能,但其中的阈值该如何确定,是一个值得思考的问题。

如果监控系统还没上线,大部分时候对于报警阈值,往往是根据经验决定。而对于已经上线并获取到一些项目监控数据的,确定报警阈值可以使用统计学方法,根据历史数据确定一个值。

比如我们收集了项目的异常事件,并发送到 Sentry 监控。在收集了一段时间后项目异常后,我们并不能百分百解决所有上报的问题:有一些问题出现的原因是暂时无法定位的;有一些是偶发性问题,影响并不大,优先级并不高;还有一些是可预知的事件,比如在版本释放后,会有一些服务暂时下线不可用引起的异常。

那么监控系统里会经常驻留这些异常,这类异常对我们来说已经知晓,但暂无精力去解决。对于报警监控来说它们可能不算做系统异常情况。我们可根据这些异常值的数量做为基准,来确定监控阈值该设定为多少合适。

我们可将历史的异常数量按一定的单位时间导出为一张 Excel 表,根据这些数值用 AVERAGE 函数算出平均值,再用 STDEV.S 算出标准差。理论上单位时间内,“正常”值应该在平均数上下一个标准差内波动的数值上正常情况,监控系统只关心的是上限,所以低于一个标准差的值是不用关心的。那么如果较为关心超过正常值的情况,可将报警阈值设置为平均数加上一个标准差为第一个报警阈值,而后根据情况设置增加几个标准差为第二个报警阈值,以及第三、第四个等。

根据正态分布和标准差的性质,我们从计算阈值要包含所有 0 开始的值,一个正标准差约覆盖 84.13% 的情况,两个标准差约覆盖 97.72% 的情况,三个标准差则为 99.87,之后发生的概率就是小于 1% 的发生概率了,那么也就是说可以根据这个思路,来确定我们该去设置几个标准差的值为报警阈值。

数据过滤

对于一些服务系统并不是全体 24 小时都有用户使用,所以对数据还需做一些过滤。比如过滤掉周末时间,过滤掉晚间无用户使用系统时间,然后对于过低和过高的值进行过滤

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math

# 读取数据
df = pd.read_excel('data.xlsx')
# 过滤掉周末时间
df = df[df['date'].dt.dayofweek < 5]
# 过滤掉晚间无用户使用系统时间
df = df[(df['date'].dt.hour >= 8) & (df['date'].dt.hour <= 22)]
# 过滤掉过低和过高的值
df = df[(df['count'] > 0) & (df['count'] < 1000)]
# 计算均值和标准差
mean = df['count'].mean()
std = df['count'].std()
# 计算上下界
upper_bound = mean + 3 * std
lower_bound = mean - 3 * std
# 设置阈值
threshold = upper_bound
# 绘制图表
plt.figure(figsize=(20, 10))
plt.plot(df['date'], df['count'], label='count')
plt.axhline(y=threshold, color='r', linestyle='-', label='threshold')
plt.legend()
plt.show()

参考

百度百科. 标准差[EB/OL]. [2023-02-23]. https://baike.baidu.com/item/%E6%A0%87%E5%87%86%E5%B7%AE/1415772 .

百度百科. 正态分布[EB/OL]. [2023-02-23]. https://baike.baidu.com/item/%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83/829892