带宽是CDN最核心的资源,也是成本占比最高的部分。做容量规划时,最头疼的问题往往是:下个月带宽会涨到多少?明年这个时候需要储备多少带宽?拍脑袋给数字,要么扩容不足导致高峰期用户访问变慢甚至被限流,要么储备过多白白浪费成本。其实CDN的带宽数据有一个很有利的特点——它有非常明显的周期性和趋势性,工作日和周末的访问模式不同,白天和深夜的带宽曲线相对稳定,业务增长又带来长期上升趋势。只要历史数据积累得足够,用统计模型做增长预测的准确率可以相当可观。这篇文章就围绕如何基于历史带宽数据构建增长预测模型展开,从数据准备到建模再到工程落地,把整个流程讲清楚。

一、历史带宽数据的采集与预处理
构建预测模型的第一步是拿到质量过硬的历史数据。CDN的带宽数据通常可以从两个渠道获取:一是CDN服务商的控制台API,一般能导出按分钟或五分钟粒度的带宽数据;二是自建监控体系,比如通过日志分析或SNMP采集节点流量。建议至少积累12个月的数据,这样才能覆盖完整的年度周期,识别出季节性波动。如果业务有大促场景,还需要单独标记这些日期。
拿到原始数据后不能直接建模,需要先做清洗。最常见的问题是数据缺失和异常尖刺。某个采集点丢失会导致序列出现空洞,而短暂的异常尖刺(比如监控抖动或者突发爬虫流量)会把增长率计算带偏。处理缺失可以用前后相邻点线性插值,处理尖刺可以用滑动窗口的中位数替代法,即判断某个点是否偏离前后若干点的中位数超过一定倍数的标准差。下面的代码演示了一个简单的清洗流程:
import pandas as pd
import numpy as np
# 读取带宽数据,包含time和bandwidth两列,单位Mbps
df = pd.read_csv('bandwidth.csv', parse_dates=['time'])
df = df.set_index('time').sort_index()
# 按五分钟粒度重采样,缺失值线性插值
df = df.resample('5T').mean().interpolate(method='time')
# 用滑动中位数检测异常尖刺
window = 12 # 一个小时的点数
median = df['bandwidth'].rolling(window, center=True).median()
std = df['bandwidth'].rolling(window, center=True).std()
mask = np.abs(df['bandwidth'] - median) > 3 * std
df.loc[mask, 'bandwidth'] = median[mask]
print(df.describe())
清洗完成后,建议把数据聚合成多个粒度分别保存:五分钟粒度用于峰值分析,小时粒度用于日周期分析,天粒度用于长期趋势建模。不同粒度对应的规划目标不同,混在一起反而会让模型抓不住重点。
二、三种可行的增长预测方法
1. 环比增长率法
最简单直接的方法是计算历史月度带宽的环比增长率,然后取近几个月增长率的加权平均值外推。比如近六个月的月环比增长率分别是8%、6%、9%、7%、8%、7%,加权平均后约7.5%,那么下月预测带宽就是本月带宽乘以1.075。这个方法实现成本极低,适合业务处于稳定增长期的场景。它的缺点是对突变不敏感,如果业务即将上线新内容源或者打开新市场,历史增长率就没有参考意义了。因此这个方法适合做基线预测,再叠加业务侧的信息做人工修正。
2. 移动平均与线性回归
对天粒度的带宽峰值序列做移动平均可以滤掉短期波动,让长期趋势显现出来。然后对趋势部分做线性回归,得到斜率就是每日增长量。这种方法比环比法更平滑,对偶发的业务波动不敏感。回归时建议用最近90到180天的数据,时间窗口太长会把早期的低速增长也纳入拟合,导致预测偏保守。
from sklearn.linear_model import LinearRegression
# 使用天粒度峰值带宽序列
daily = df['bandwidth'].resample('D').max()
trend = daily.rolling(30).mean().dropna()
X = np.arange(len(trend)).reshape(-1, 1)
y = trend.values
model = LinearRegression().fit(X, y)
# 预测未来90天的趋势值
future_days = 90
last_idx = len(trend) - 1
pred = model.predict(np.arange(last_idx + 1, last_idx + 1 + future_days).reshape(-1, 1))
print('日均增长量(Mbps/天):', model.coef_[0])
print('90天后趋势预测(Mbps):', pred[-1])
3. 时间序列分解模型
更规范的做法是把带宽序列分解为趋势项、周期项和残差项三部分,分别建模再叠加。Python的statsmodels库提供了现成的季节性分解接口,周期设为7天可以提取周周期,设为365天可以提取年度周期。分解出趋势项后,用回归或者指数平滑外推趋势,再把周期项按对应日期加回去,就能得到带有波动的预测曲线。这种方法的解释性最好,你能明确知道预测值里有多少来自趋势增长、多少来自周期波动,方便和业务方沟通。如果追求更高精度,可以进一步使用SARIMA或者Prophet这类模型,它们对节假日效应的建模能力更强,适合有大促场景的业务。
三、从预测值到扩容决策的换算
预测出未来的带宽走势只是中间结果,最终要回答的问题是带宽储备应该定在多少。这里有一个关键指标:峰值均值比,即月度峰值带宽除以月均带宽。CDN的计费通常按月度峰值或者第95百分位计费,而容量储备必须按峰值准备。根据历史数据算出稳定的峰值均值比之后,扩容阈值就可以这样确定:用预测模型得到的下月峰值带宽预测值,乘以一个安全系数,一般取1.2到1.5,视业务的突发容忍度而定,再和当前已储备带宽比较,超出部分就是要提前采购的量。
安全系数的选择需要权衡两个成本:带宽超卖导致的服务质量损失和用户体验下降,以及过度储备带来的成本浪费。如果业务对延迟敏感,比如视频直播,建议取1.5;如果是纯静态资源分发,短时回源可以扛住突发,1.2就够用。另外建议建立月度滚动预测机制,每月用最新数据重新拟合模型,把预测误差反馈回来持续修正,这样模型会随着时间越用越准。还可以跟踪预测值和实际值的偏差率,一旦连续两个月偏差超过15%,就说明业务模式发生了结构性变化,需要重新审视建模假设,而不能继续机械地套用旧模型。
四、工程落地的几点建议
模型建好后,落地环节同样重要。第一,把数据采集、清洗、建模、告警的流程固化成定时任务,每天自动输出未来一个月的带宽预测曲线,推送到运维群。第二,设置分级告警:当预测的下月峰值达到当前储备的80%时触发预警,达到90%时触发紧急扩容流程,给采购和调度留出足够的时间窗口。第三,保留每次预测和实际的对比记录,形成误差分析报告,这是后续调优模型最宝贵的素材。容量规划不是一次性工程,而是持续运转的数据闭环,坚持滚动迭代几个月后,你会发现带宽决策从拍脑袋变成了看数据,扩容节奏也能从容地和业务增长对齐。