01月19, 2017

磁盘容量预测与处理机制

背景与目标

存储设备中磁盘容量是服务器能够可靠运行的重要保障。如何避免应用系统中出现存储容量耗尽的情况而导致应用系统负载率过高,最终引发系统故障是一个比较棘手的问题。

目前,工业界普遍采用被动容错机制,为磁盘容量设置一个阈值来保证系统的可靠性:即如果超过阈值,则会发生报警来让人工干预以降低磁盘容量。如果系统管理员不及时进行相应的处理,系统很容易出现故障,从而导致用户无法访问系统,严重影响企业的利益。

本文提出一种主动的预测与处理机制,提前对磁盘使用率进行预测,发现使用率比较高的机器。但是只有预测是远远不够的,如果能够提前自动处理报警,将会最大程度减少报警的次数。我们的机制分为两部分,一部分是预测,另一部分是处理,下图是我们系统的框架图:

image

智能预测

历史数据分析

应用系统出现故障通常不是突然瘫痪造成的,而是一个渐变的过程。例如。系统长时间运行,数据会持续写入存储,存储空间逐渐变少,最终磁盘被写满而导致系统故障。由此可见,在不考虑人为因素的影响时,存储空间随时间变化存在很强的关联性,且历史数据对未来的发展存在一定的影响。所以可以采用时间序列分析法对磁盘容量进行预测分析。

模型使用

本节将以分析磁盘容量时序介绍时间序列模型如何使用。 我们使用以下的步骤来建立一个时间序列模型:

获取数据

我们采集过去7天的数据,采集间隔是1小时。使用下面代码得到历史的数据。

#导入需要的模块
import csv
import date
import datetime
import pandas as pd
#从csv文件中读取时间和对应的数据
data = pd.read_csv("cpu_idle_data.csv")

time_series = []
mydata = []
#将时间保存在time列表中,而将数据保存在mydata中
#将.csv数据读入Pandas数据帧
for timestamp,used_percent in zip(data['timestamp'],data['used_percent']):
    #将数字时间转换为能够识别的时间 
    a = time.localtime(timestamp)
    b = time.strftime("%Y-%m-%d %H:%M:%S", a)
    time_series.append(b)
    mydata.append(used_percent)

创建时间序列

为数据建立索引,转换为pandas能够识别的时间序列。

dta=pd.Series(mydata)
dta.index = pd.Index(time_series)
dta.index = pd.DatetimeIndex(dta.index)

缺失值处理

使用均值来补齐缺失值。

dta = dta.resample('H')
dta = dta.fillna(np.mean(mydata))

历史趋势

查看磁盘容量过去一周的数据曲线: alt

平稳性检测:

观察4中的图,可以看出该序列不平稳,我们需要使用差分的方法来使该序列变为平稳序列。

fig = plt.figure(figsize=(12,8))
ax1= fig.add_subplot(111)
#一阶差分
diff1 = dta.diff(1)
diff1.plot(ax=ax1)

alt

可以看出,经过一阶差分后,数据已经平稳了,可以进行ARMA模型了。

通过肉眼观察每个图像显然不是平稳性检测最好的方法,我们可以使用单位根检测(ADF)进行平稳性检测。 平稳性检测代码:

from statsmodels.tsa.stattools import adfuller as ADF
diff=0
#平稳性检测函数ADF
adf=ADF(dta)
#adf[1]为p值,如果p值小于0.05则认为该序列是平稳的。
while adf[1]>=0.05:
    diff=diff+1
    adf=ADF(dta)
print(u'原始序列经过%s阶差分后归于平稳,p值为%s' %(diff, adf[1]))

白噪声检验

为了验证系列中是否还有有用的信息,是否已经被提取完毕,需要对序列进行白噪声检验。如果为白噪声,则有用的信息已经被提取完毕,剩下的随机扰动,无法进行预测和使用。 本节使用LB统计量的方法进行白噪声检验,代码如下:

from statsmodels.stats.diagnostic import acorr_ljungbox
#原始序列
[[lb],[p]]=acirr_ljungbox(dta,lag=1)
if p<0.05:
    print(u'原始序列为非白噪声序列,对应的p值为%s',%p)
else:
    print(u'原始序列为白噪声序列,对应的p值为%s',%p)
#一阶差分序列
[[lb],[p]]=acirr_ljungbox(dta.diff().dropna(),lag=1)
if p<0.05:
    print(u'一阶差分序列为非白噪声序列,对应的p值为%s',%p)
else:
    print(u'一阶差分序列为白噪声序列,对应的p值为%s',%p)

确定p和q的值,建立ARIMA(p,1,q)模型 第一种方法:人工识别 根据自相关图和偏自相关图来确定p和q的值。

alt

所以p为0,q为0 第二种方法:相对最优模型识别 计算ARIMA(p,q)。当p和q均小于一定值的所有组合的BIC信息量,去其中BIC信息量达到最小的模型阶数。

#迭代的阶数
#一般阶数不超过length/10
pmax = int(len(dta)/10)
qmax = int(len(dta)/10)
bic_matrix = []
for p in range(pmax+1):
    tmp = []
    for q in range(qmax):
        #存在部分p和q建模不成功
        try:
            model_tmp = ARIMA(dta, (p,1,q), freq='H')
            try:
                tmp.append(model_tmp.fit().bic)
            except:
                tmp.append(None)
        except:
            tmp.append(None)
    bic_matrix.append(tmp)
    bic_matrix = pd.DataFrame(bic_matrix)
#从中找到p和q的最小值
p,q = bic_matrix.stack().idxmin()

确定p和q的值:

从7中获得了p,q值,从5中获得d的值后我们就可以建立ARIMA模型了。

model = ARIMA(dta, (p,d,q), freq='H').fit(trend='nc')

预测未来趋势

预测未来一段时间的值。

#predict_outcome中保存了预测结果、标准误差以及置信区间
predict_outcome = model.forecast(24)
#我们可以从predict_outcome[0]获取到预测的结果
print predict_outcome[0]

预测结果和历史数据:

下面我们通过下面的代码画出历史数据和预测数据的图:

fig, ax = plt.subplots(figsize=(12, 8))
ax = dta.plot()
predict_outcome.plot(ax=ax)

下面是图像:

alt

可以看出预测结果能够真实的反映出历史数据的走势,能够真实的预测出未来的数据值。

有人可能会问这个系统可能依赖于预测模型的准确率。为了验证模型的准确率,我们提出来两个概念来说明效果:

  • 预测准确率:预测准确率=预测报警且具有报警趋势的机器数/预测报警的机器数
  • 报警减少率:预测覆盖率=预测报警且真正报警的机器数/报警的机器数

我们对线上20000+台机器未来24小时的走势进行预测,跟踪了将近一个月的预测结果。可以发现我们的模型预测准确率能够达到100%,报警减少率能够达到70%左右,这说明我们的模型能够获得比较好的效果。

智能处理

接下来将重点介绍在预测磁盘使用率将要达到阈值后,我们如何自动处理的过程。用户可以根据自己的意愿选择处理类型:一种是自动处理,一种是通知邮件。

如果是自动处理类型,我们会清理100%可以确定删除的日志文件,比如allweb文件以及一些归档的日志文件。虽然我们有一定的目录规范和定期的日志轮转,但是因为有些程序编写的不规范,业务访问量的增长,还是会有磁盘被写满的情况,所以单纯依靠自动清理会有一定的风险,所以我们还有一种是通知邮件,我们会定期将扫描出来的占用空间比较大的文件信息发送给用户,由用户自己去处理。

上面介绍的磁盘智能预测与处理机制已经在我们线上进行使用,并取得了比较好的效果。通过这种预测与处理机制,能够尽可能减少磁盘报警,真正解放人力资源。

本文链接:https://www.opsdev.cn/post/disk-predict.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。