简介资源包内含应用系统负载分析与磁盘容量预测的Python源码面向数据分析、系统运维及存储规划人员解决如何根据历史负载数据识别规律、构建预测模型并提前评估磁盘容量趋势的问题。压缩包共6个文件包含4个Excel数据文件原始监测数据、经过处理的数据以及待预测数据、1个Python主程序脚本和1个导入模块说明文本整体大小约20KB体积精简便于下载后直接运行。目前已有561人学习浏览。源码遵循数据挖掘流程先分析数据中的模式和趋势再建立预测模型并应用到实际系统负载及磁盘容量的预测场景中配套的xls文件提供了完整的输入数据说明文本则列出了关键模块及依赖方便快速跑通。通过学习这份资源可以掌握数据预处理、特征提取、模型参数调整等操作方法也可作为课程设计、毕业设计或企业容量规划的实用参考具有较好的启发性与复用价值。1. 应用系统负载分析与磁盘容量预测一套Python源码包解决“磁盘何时满”磁盘写满不是渐变事故而是突发的线上故障。很多团队直到No space left on device告警炸了才去清理但日志、临时文件、数据库的WAL归档往往在几个小时内就把最后那点剩余空间吃光。应用系统负载分析要回答的不只是“现在忙不忙”而是“按照当前增长趋势磁盘还撑多久、哪台机器先撑不住”。这套Python源码做的事就是从监控系统或历史数据里把负载指标拉下来做趋势拟合再外推出磁盘容量到达阈值的时间点。它适合手里有历史监控数据、想提前做容量规划的运维和开发也适合刚接触时间序列预测、想用一个真实场景练手的初学者。核心思路不复杂负载是波动的趋势是朴素的预测要的是“什么时候该扩容”的答案而不是一个花哨的深度学习模型。2. 负载分析和容量预测的边界为什么预测磁盘比预测CPU靠谱2.1 磁盘容量预测本质是趋势外推不是复杂度竞赛负载分析包含CPU使用率、内存占用、请求QPS、IO等待、磁盘使用量等指标但只有磁盘容量这一类适合做中长期预测。原因是它内在的规律不同CPU使用率在秒级和分钟级剧烈振荡受业务峰值、定时任务、用户行为影响今天上午10点和明天上午10点的曲线可能完全对不上预测误差动辄超过50%。而磁盘已用空间是一个累积量——今天写入了 300GB明天大概率再写 200GB后天大概率再写 250GB它只增不减不发生清理的前提下短期波动被累积效应抹平了。所以磁盘容量预测的数学模型本质是一元时间序列的趋势外推把历史采样点看作一条带噪声的上升曲线拟合出增长趋势再往前延伸。换句话说用 LSTM 或 Transformer 预测磁盘容量不是不可以但属于杀鸡用牛刀还容易翻车——这类模型需要大量高质量样本而一台机器的磁盘监控历史往往只有几个月、采样粒度还粗深层网络在小样本上拟合出的曲线经常在预测窗口后半段出现不合理的陡升或震荡。业界容量预测的常见做法是用 Prophet、指数平滑或分段线性回归它们对小样本友好、参数直白、结果可解释。这套源码里主模型选 Prophet 也是基于同样的理由。2.2 从 Prometheus 到 DataFrame指标选型与时间对齐要做预测先把数据拿出来。常见的数据来源有两种用哪种都绕不开“时间对齐”这一步。如果你从 Prometheus 拉数据会得到典型的(timestamp, value)序列比如node_filesystem_avail_bytes这个指标如果你从 Zabbix 或自研监控导 CSV字段通常是time, host, mount_point, usage_percent, avail_bytes。无论哪种落到 pandas DataFrame 后必须把时间列转成datetime64并按固定间隔重采样。Prometheus 拉接口的原始间隔是 15 秒到 1 分钟不等但训练 Prophet 不需要这么密一小时一个点足够太密反而把毛刺噪声灌进模型。# 从Prometheus拉取磁盘可用字节数并聚合为小时序列 import requests import pandas as pd prom_url http://prometheus.internal:9090/api/v1/query_range query node_filesystem_avail_bytes{mountpoint/data, instanceapp-01} resp requests.get( prom_url, params{ query: query, start: 2024-06-01T00:00:00Z, end: 2025-01-01T00:00:00Z, step: 3600 }, timeout30 ) data resp.json()[data][result][0][values] df pd.DataFrame(data, columns[ts, avail]) df[ts] pd.to_datetime(df[ts], units, utcTrue) df[avail] df[avail].astype(float) df df.set_index(ts).resample(1h).min() # 小时级聚合取极小值更保守这段代码里有两个值得说的参数。step3600让 Prometheus 直接按小时返回数据点减少网络传输和本地计算压力。重采样用.min()而不是.mean()含义是“一小时内最危险的那个可用容量点”——如果某个瞬间磁盘几乎被写满平均值会把这个危险信号稀释掉。实际项目里我会对可用字节数和已用字节数都做一次拉取因为预测“剩余空间什么时候归零”和预测“已用空间什么时候越过阈值”是同一个问题的两种表述但后者更容易画图汇报。# 已用字节 总字节 - 可用字节并按天聚合消除日内短波动 df_total pd.Series(500.0 * 1024**3, indexdf.index) # 假设磁盘总量500GB df_used (df_total - df[avail]) / (1024**3) # 转为GB df_daily df_used.resample(1D).max().dropna().to_frame(namey) df_daily.index.name ds按天聚合是我在调参过程中养成的习惯。磁盘写入有很强的日内节奏——凌晨的日志轮转、夜间的备份任务都会造成小时级的凸起但这些对“一周后满不满”没有影响。一天一个点让模型只盯着长期趋势也把数据量从几千点压到一两百点Prophet 在这种规模上训练只需要几秒。需要注意总量字段在这里写死为 500GB实际应从node_filesystem_size_bytes拉取否则预测的是绝对字节数一旦扩容就会失真。3. 用Prophet拟合磁盘增长曲线最小可运行代码与参数调优3.1 环境准备与依赖安装这套源码的依赖不算多核心就四个pandas、numpy、prophet、scikit-learn。Prophet 是 Facebook 开源的时间序列预测库底层是 stan 概率编程框架安装包较大在干净环境里首次pip install prophet可能要等两三分钟这是正常现象不是卡死了。Python 版本建议 3.9 到 3.11太老的 3.7 在编译 stan 依赖时容易报 C 兼容错误。如果你从来没装过 numpy 和 pandas先执行下面的命令把基础环境补上。pip install pandas numpy prophet scikit-learn装完以后可以用一行命令验证 Prophet 能否正常导入。常见的一个坑是cmdstanpy在 Windows 上需要 C 构建工具缺失时会报RuntimeError: Error during promotion解决办法不是硬装 visual studio而是换成pip install prophet --only-binary :all:拉预编译轮子或者直接在 Linux 容器里跑。3.2 数据清洗时序预测最容易在这步翻车很多人在数据清洗上栽跟头不是因为代码写错而是因为监控数据里有“假趋势”。磁盘清理动作、数据迁移任务、临时文件被删除这些事件会让已用空间曲线出现一个突然下跌的台阶。如果不过滤这种台阶模型会把下跌拟合成趋势的一部分预测出的未来曲线可能显示“磁盘永远不会满”——这是最坑的翻车方式。我的做法是先画图、再清洗、再训练三步顺序不能反。import matplotlib.pyplot as plt from prophet import Prophet # 第一步画全量曲线肉眼找台阶 plt.figure(figsize(12, 4)) plt.plot(df_daily.index, df_daily[y]) plt.title(disk used (GB) before cleaning) plt.show()画完图之后凡是看到单日跌幅超过总容量 5% 的跳变点都要查一下当天是不是发生了清理或迁移。确认后把台阶后面的所有数据整体抬高或降低对齐到台阶前的趋势上。更省事的做法是直接用df_daily[y] df_daily[y].clip(upper当前可用空间上限缓冲)但裁剪会损失真实信息不如平移修正。平移的幅度怎么定找到台阶前后各 7 天的均值差把台阶后的整段数据减去这个差值相当于把曲线“接回”原趋势。# 假设 idx_cleanup 是清理发生的那一天这里做台阶修正 before_mean df_daily.loc[:idx_cleanup].tail(7)[y].mean() after_mean df_daily.loc[idx_cleanup:].head(7)[y].mean() shift after_mean - before_mean df_daily.loc[idx_cleanup:, y] - shift df_daily df_daily[df_daily[y] 0] # 修正后不应出现负值idx_cleanup需要你自己根据画图结果确定这步没有标准答案。处理完台阶后还有一个常规操作把ds列和y列的列名固定成 Prophet 要求的格式ds是时间戳y是要预测的数值。很多人在这里随手用了别的列名导致训练时报KeyError: ds这不是模型的问题是接口契约没遵守。3.3 拟合与预测核心参数只有三个Prophet 的默认参数在大多数磁盘容量场景下表现已经不错但想要预测结果有决策价值必须调三个参数growth、changepoint_prior_scale、interval_width。growth控制趋势形式默认是linear但磁盘容量在极端情况下会表现出指数增长——比如日志没做轮转时写入速度会随着文件数量增加而恶化这时候要用logistic并指定cap上限。changepoint_prior_scale是趋势拐点的灵敏度默认 0.05磁盘数据拐点少我一般降到 0.02~0.03避免模型把正常波动拆成好几个拐点。interval_width是置信区间宽度默认 0.8在容量预测里我建议开到 0.95因为我们要拿上限做决策——宁可提前扩容不可侥幸冒险。from prophet import Prophet model Prophet( growthlinear, changepoint_prior_scale0.02, interval_width0.95, weekly_seasonalityFalse, daily_seasonalityFalse ) model.fit(df_daily) future model.make_future_dataframe(periods60, freqD) # 预测未来60天 forecast model.predict(future)make_future_dataframe的periods和freq决定了预测窗口。60 天是容量规划里比较舒服的提前量——太短7 天留给采购和工单的时间不够太长180 天趋势可能因为业务变更失效。我把weekly_seasonality和daily_seasonality都关掉原因前面提过磁盘写入没有稳定的周内周期打开反而会让模型在一个只有 200 个点的数据集上硬学出一个假的周期性成分。# 把预测结果整理成一眼能看懂的表格 result forecast[[ds, yhat, yhat_lower, yhat_upper]].tail(60) result[ds] result[ds].dt.date result.columns [日期, 预测已用(GB), 下界(GB), 上界(GB)] print(result.head(10))这里的yhat是预测中位数yhat_lower和yhat_upper是置信区间边界。读结果时不要盯着yhat看要看yhat_upper——那是 95% 置信下的最坏情况。如果上限在第 45 天就越过阈值实际最迟那天可能还差 10% 余量但按照最坏情况计划才是容量管理的第一原则。3.4 预测结果画图把曲线和实际重叠到一起Prophet 自带plot方法但对运维汇报来说原始图不够直观。我通常会叠加一条实际数据的散点把阈值线画上去一眼就能看出“预测曲线什么时候越过红线”。import matplotlib.dates as mdates fig, ax plt.subplots(figsize(12, 5)) ax.scatter(df_daily.index, df_daily[y], s15, labelactual) ax.plot(result[日期], result[预测已用(GB)], colortab:blue, labelforecast) ax.fill_between(result[日期], result[下界(GB)], result[上界(GB)], alpha0.2) ax.axhline(threshold_gb, colorred, linestyle--, labelthreshold 80%) ax.xaxis.set_major_formatter(mdates.DateFormatter(%m-%d)) ax.legend() plt.title(disk usage forecast with 95% interval) plt.show()threshold_gb是磁盘容量阈值的绝对数值比如总量 500GB 的 80% 就是 400GB。把阈值画进去是给决策者看的不是给模型看的。如果预测上限距离阈值还远那图上会有一条明显的安全走廊如果已经逼近这张图本身就是扩容申请的附件。这段画图逻辑也是这套源码里价值最高的部分——预测本身不产生价值产生价值的是把预测转换成“哪天之前必须行动”的结论。4. 计算“磁盘满盘时间点”把预测折线变成运维工单4.1 阈值插值法不依赖单个越界点预测表和画图都只是铺垫运维要的是一个具体日期某台机器预计在哪一天达到 80% 容量。直接取yhat_upper首次超过阈值的日期是最简单的做法但离散的预测日期间隔是一天如果上限从第 29 天的 398GB 跳到第 30 天的 412GB我们只能得出“第 30 天越界”不够精确。更稳的办法是线性插值用越界点前后两天的预测值在两者之间插值求出精确到小数天的越界日期。import numpy as np threshold_gb 400.0 upper result[上界(GB)].values dates np.arange(len(upper)) over_idx np.where(upper threshold_gb)[0] if len(over_idx) 0: over_day None else: i over_idx[0] if i 0: over_day 0 else: # 线性插值越过阈值的那一天在第 i-1 天和第 i 天之间 y0, y1 upper[i - 1], upper[i] d0, d1 dates[i - 1], dates[i] over_day d0 (threshold_gb - y0) / (y1 - y0) * (d1 - d0) if over_day is not None: target_date result[日期].iloc[min(int(np.ceil(over_day)), len(result) - 1)] print(f预计 {target_date} 达到 {threshold_gb}GB ({over_day:.1f} 天后)) else: print(f未来 {len(result)} 天内不会达到阈值)插值公式d0 (threshold - y0) / (y1 - y0) * (d1 - d0)就是初中线性比例关系但很多实现直接跳过这一步用np.argmax(upper threshold)拿到一个粗糙的整数天数。在容量规划里差出 0.5 天可能意味着要不要赶在周末前发工单的区别。这个算法对存量的磁盘持续增长场景足够前提是预测区间不要宽到没有决策意义——如果yhat_upper和yhat_lower差了 100GB插值出来的日期本身就是“玄学”所以第 6 章我会重点写怎么验证区间宽度是否合理。4.2 多机器批量预测扩容排队顺序怎么定单机预测只是热身真实环境里至少几十台机器挂着不同挂载点。逐个跑训练脚本不现实常见做法是遍历机器列表每台都走清洗→训练→预测→插值四步最后汇总成一张表按“预计触顶日期”排序越靠前的越紧急。这张表就是磁盘容量预测的核心产出。主机名挂载点已用容量(GB)预测触顶天数建议动作app-01/data372.523.4申请扩容 / 清理30天前日志app-02/var/lib/mysql318.241.1观察预留预警app-03/data401.82.1立即清理否则本周内满排序的关键字段是“预测触顶天数”不是“已用容量百分比”。一张 80% 的盘如果增长放缓可能能撑两个月一张 65% 的盘如果日志暴涨可能只剩三天——只看当前水位会误判危险等级。做批量预测时还要注意挂载点之间的差异/data这类纯日志盘增长平滑模型效果好/var/lib/mysql这类数据库盘的增长随业务活动波动更大建议把changepoint_prior_scale调回 0.05否则模型学不到突变点。# 伪代码批量预测调度结构 for host, mnt in inventory: df load_and_clean(host, mnt) model create_model(mnt) # 按挂载点类型选择参数 fc train_and_forecast(model, df) day interpolate_over_day(fc, threshold_gb[host]) results.append({host: host, mount: mnt, day_to_full: day})create_model里对不同挂载点用不同参数这是我在实战中总结的规律——日志盘和数据库盘的数据特征完全不同统一参数必然有一半机器预测效果差。如果机器太多导致整体训练耗时过长可以考虑用model.fit(df, disable_parallelTrue)关闭并行或者把数据按挂载点分组后并行训练而不是一次跑几百个模型。5. 避坑磁盘容量预测常见的5次翻车与排查思路5.1 现象预测曲线突然变成一条几乎水平的直线触顶日期永远很远原因数据里有清理台阶没修正模型把下跌当成了趋势反转线性趋势被带平甚至带负。解决回到 3.2 节的清洗流程花十分钟画图看台阶用平移法修正后再重训。还有一种隐蔽情况监控探针重启过导致连续几天数据缺失缺失期间的y值被 pandas 自动填成了 0这也会把趋势拉平。排查方法是检查df_daily[y]是否有连续的 0 值或 NaN用前向填充ffill()而非直接把缺失段丢弃。5.2 现象预测区间极度宽泛yhat_lower是 300GByhat_upper是 700GB原因数据点太少只有 30~40 天模型对趋势的不确定性评估过高。解决至少积累 90 天的监控数据再跑预测。如果等不了有两个补救方案一是把interval_width从 0.95 调回 0.8区间会窄一些但代价是置信度下降二是改用growthflat不要把趋势外推当主要手段而是用近期日均增长量做一个简单线性外推当参考线。我再强调一遍区间宽不代表模型差它反映的是数据量支撑不起长周期预测写报告时要写明这是“低置信预测”。5.3 现象预测触顶日期比实际提前了三个月虚惊一场原因磁盘清理策略是周期性执行的比如每周日凌晨清一次日志。模型看到了每周一已用空间下跌的周期性但因为weekly_seasonalityFalse它学不到这个回落只盯着上涨趋势外推。解决如果确实有固定的定期清理任务把weekly_seasonalityTrue打开让模型把“下跌拐点”建模成每周重复的规律。但如果清理不是严格周期性的打开反而会引入错误的周期性假设。判断标准很简单把已用空间按周几分组画箱线图如果周日明显低于周五就开启如果看不出规律保持关闭。5.4 现象磁盘已经 90% 满预测却显示还有 60 天余量原因趋势模型是全局拟合的当最近 7 天突然加速写入比如新上线了日志采集客户端全局趋势被之前三个月的平缓增长稀释尾部预测跟不上新趋势。解决对不到 30% 剩余空间的机器不要只依赖全局模型单独用一个“近 14 天日均增量 × 剩余空间”的简单除法做一个快速估算两者取更危险的那个值。这不是模型的问题是场景变了——接近满盘的机器属于紧急通道不适合优雅的趋势外推。5.5 现象每次重训模型预测结果都不一样参数没改但曲线变了原因Prophet 底层采样有随机性虽然数据相同但 MCMC 采样种子不同导致结果在小范围内浮动。这不影响整体结论但如果要对汇报数字必须固定随机种子。解决训练前在脚本里加np.random.seed(42)和Prophet(..., uncertainty_samples1000)前者固定 Python 随机数后者固定采样次数。加了之后可以验证连续跑两次脚本预测表的yhat数字应当完全一致。如果还有浮动检查是否在多线程环境里多个模型共享了全局随机状态。6. 验证预测准不准时间序列回测与误差评估6.1 按时间先后切分回测不能随机抽样模型训练完最该做的不是看拟合曲线有多贴合历史——那只是模型在背答案。真正的验证是把时间序列切成训练段和测试段用前 80% 的历史数据训练预测后 20% 的时间段再把预测值和实际值对比。注意它和普通机器学习回测的本质区别切分必须按时间顺序禁止随机抽样因为时间序列有先后依赖随机打散会把“未来”混进训练集指标会虚高。切分点应该留出至少 30 天做测试否则误差数字没有统计意义。from sklearn.metrics import mean_absolute_percentage_error train df_daily.iloc[:int(len(df_daily) * 0.8)] test df_daily.iloc[int(len(df_daily) * 0.8):] model Prophet(changepoint_prior_scale0.02, interval_width0.95) model.fit(train) future model.make_future_dataframe(periodslen(test), freqD) pred model.predict(future)[yhat].tail(len(test)).values actual test[y].values mape mean_absolute_percentage_error(actual, pred) * 100 print(fMAPE: {mape:.1f}%)MAPE 代表预测误差百分比20% 以内是可以接受的容量预测精度10% 以内属于优秀。但我要提醒如果测试期恰好包含一次清理事件MAPE 会被瞬间拉爆这不代表模型退化而是测试段本身的趋势变了。此时应把评估指标换成“是否成功预测趋势方向”比如测试段实际增长了 50GB模型预测增长 40GB方向正确且幅度接近就说明模型学会了增长逻辑。6.2 用覆盖率检查置信区间是否诚实MAPE 只能评价点预测精度评价区间预测质量要看覆盖率实际值落在yhat_lower和yhat_upper之间的比例。理论上interval_width0.95意味着约 95% 的实际值应落在区间内。如果覆盖率只有 60%说明置信区间过于自信如果覆盖率接近 100%说明区间过宽、失去了决策参考意义。这两种情况都需要调interval_width或检查数据量。inside ((actual pred_lower) (actual pred_upper)).mean() print(f覆盖率: {inside:.2%} (期望约 95%))覆盖率是容量预测里最容易被忽略的指标。很多人只盯着预测中位数忽略了区间但容量决策恰恰必须依据上限——覆盖率偏低意味着“最坏情况”的数据可能不可信触顶日期会被延迟预估。我在复盘过一个案例某机器预测触顶在第 45 天实际上第 31 天就满了回头查覆盖率只有 70%问题出在测试段包含了大量高波动写入日异常点全落在了区间之外。6.3 进阶异常点修正与快慢双模型当过完回测发现误差集中在少数异常点后有一个实用技巧把这些异常日的日期标记出来在训练数据里将它们替换为相邻 7 天滚动中位数避免它们在模型里形成虚假的趋势拐点。注意这是对训练数据的修饰不能对测试数据做同样处理——否则回测就失真了。另一个思路是维护一快一慢两个模型慢模型用 90 天数据训练负责看长期趋势快模型只用最近 14 天训练负责捕捉加速增长。最终报告取两者中更接近触顶的那个日期牺牲一点乐观估计换来的是留给采购和扩容操作更充足的缓冲期。这也是我这几年做下来最值得复用的习惯预测模型要服务的不是理论精度而是“留够后悔药”的工程决策。希望帮到你。本文还有配套的精品资源点击获取