DolphinDB 存储容量规划实战:增长监控、满盘倒计时与扩容决策
摘要
运维时序平台,基本都看到过这样的告警:"磁盘使用率超过 85%",接下来就是一套熟悉的救火动作:找出占盘最多的表、手动删几个月旧分区、写个紧急清理脚本、第二天提采购申请。折腾完发现,同样的事半年前干过一次。
容量问题在 IoT 平台上是必然发生的——设备只增不减、测点只多不少、数据只进不出。既然必然,就该从"被动接告警"换成"主动做规划":清楚地知道每天在涨多少、还能撑多少-天、什么时候必须做决定、决定时有哪些选项。
容量规划听起来像运维文档,拆开看全是时序分析的活儿:磁盘用量是一个单调递增的累计序列(和电表读数一个脾气),日增长量是它的差分,增长趋势要看移动平均,业务扩张造成的增长突变要单独检测,"还剩多少天满"是一次线性外推——用平台分析平台自己,这些恰好都是时序库的本职。
本文把容量规划拆成四步:先算三笔账(写入到存储、净增长、决策杠杆)、把容量变成时序数据、增长趋势与突变分析、满盘倒计时外推与决策。核心主张:外推不是预言,是"什么时候必须做决定"的信号。
一、先算三笔账
动手监控之前,先把容量的账算明白。算不清账,后面一切外推都没有意义。
1.1 第一笔:从写入速率到日增存储
容量增长的源头是写入。估算链路:
写入速率(点/秒) × 每点字节数 × 86400 秒 = 日增原始量(字节)
日增原始量 ÷ 压缩比 = 日增磁盘占用
举例:1000 个测点、每秒 1 条、每条一行(时间戳 8B + 设备号 4B + 若干数值列约 40B)——日增约 4.3 GB 原始量。列存压缩后落到盘上通常明显缩小(常见时序负载的压缩区间较宽,以自己环境的实测为准),按实测 8 倍算,日增约 0.5 GB。
这笔账的关键不是算得多准,而是建立数量级的直觉:知道一胎新产线接入(2000 测点)意味着日增翻倍还多,容量压力从"遥远"变"紧迫"。
1.2 第二笔:净增长——TTL 让曲线趋平
如果配了保留策略(比如保留 180 天),容量曲线不是永远陡增的:保留窗口走满之后,每天的写入增量和过期清理量接近相等,净增长趋近于零,用量曲线进入平台期。
用量
│ ╭──────── 平台期(日增 ≈ 日删)
│ ╭───╯
│ ╭───╯ ← 爬坡期(保留窗口未满,只增不删)
│ ╭──╯
└──────────────────── 时间
└── 180 天 ──┘
所以容量压力主要来自两段:保留窗口未走满的爬坡期,和业务扩张带来的台阶(新产线、提频、加测点)。监控的意义就是盯住这两段。
1.3 第三笔:决策时的三个杠杆
容量吃紧时只有三个选项,各有代价:
| 杠杆 | 动作 | 代价 |
| 扩容 | 加盘 / 加节点 | 花钱、有采购周期 |
| 收紧保留 | TTL 从 180 天减到 120 天 | 丢历史,分析回溯变短 |
| 降采样归档 | 原始数据过期后只留分钟级聚合 | 丢细节,故障复盘能力下降 |
三个杠杆怎么选,是第五节的事。这里先记住:容量决策不是"扩不扩"的二选一,是三个杠杆的组合拳——比如"扩 30% + 高频表保留减 60 天",常常比单拉任何一个杠杆都便宜。
二、把容量变成时序数据
容量规划的第一步工程动作:让磁盘用量本身成为库里的一张时序表。
2.1 每日快照
// 容量快照表:每天一行
dbCap = database("dfs://ops", VALUE, 2026.01.01..2026.12.31)
capSchema = table(1:0,
`day`totalUsedGB`diskTotalGB`partitionCount`iotUsedGB,
[DATE, DOUBLE, DOUBLE, INT, DOUBLE])
dbCap.createPartitionedTable(capSchema, "capacityDaily", `day)
// 每日采样任务(磁盘用量来自系统层采样脚本,写入这张表)
def sampleCapacity() {
// 采集当前用量与分区数(由外部脚本或系统命令取数后写入)
loadTable("dfs://ops", "capacityDaily").tableInsert(...)
}
scheduleJob("cap_sample", "每日容量采样", sampleCapacity,
now() + 1d, 2030.12.31, 'D', "01:00m")
快照除了总量,建议再记两个维度:按库的占比(哪个业务在吃盘,一查便知)和分区数(分区数异常增长是另一个隐患信号)。
2.2 增长序列:差分
有了每日快照,日增长就是一次差分:
// 日增长序列(快照表一天一行、按写入自然有序,直接差分)
growth = select day, totalUsedGB,
deltas(totalUsedGB) as dailyGrowthGB
from loadTable("dfs://ops", "capacityDaily")
注意这里和电表读数一样:累计量差分才是真实的增长,直接看总量曲线的"感觉"会骗人——总量涨了 2% 可能是正常爬坡也可能是扩张前兆,差分序列一拉就清楚。
三、增长分析:趋势与突变
3.1 趋势:两个移动平均
日增长序列有波动(周末停产、月初批量任务),直接看单日值会被噪声带偏。拉两条移动平均:
// 7 日与 30 日平均日增——短期波动 vs 长期基线
trend = select day, dailyGrowthGB,
mavg(dailyGrowthGB, 7) as growth_ma7,
mavg(dailyGrowthGB, 30) as growth_ma30
from growth
ma7 贴着短期波动走,ma30 是长期基线。两个的关系就是容量叙事:ma7 长期贴着 ma30 → 平稳;ma7 持续抬升且 ma30 跟涨 → 结构性增长(业务真的变大了);ma7 突然跳离 ma30 → 有事件发生。
3.2 突变检测:增长台阶
业务扩张(新产线接入、采集提频)在增长序列上表现为台阶——日增从 0.5 GB 直接跳到 1.2 GB。检测它:
// 日增显著偏离 30 日基线 → 标记为增长事件
events = select day, dailyGrowthGB, growth_ma30,
iif(abs(dailyGrowthGB - growth_ma30) > 3 * mstd(dailyGrowthGB, 30),
1, 0) as isSpike
from trend
突变检测的价值不在告警本身,在于给外推切分数据段:台阶之后的世界和台阶之前不是一个增长模型,拿扩张前的 90 天数据外推扩张后的满盘时间,会严重失真。发现台阶,外推从台阶后重新起算。
四、满盘倒计时:线性外推
4.1 剩余天数
容量决策的核心数字:按当前增长速度,磁盘还能撑多少天。线性外推,一行账:
剩余天数 = (总容量 − 当前用量) ÷ 日均增长
用 SQL 实现并每日更新(取近 30 天的最小二乘斜率,比首尾相减更抗噪):
// 近 30 天的线性斜率(最小二乘)与剩余天数
def daysToFull() {
t = select day, totalUsedGB
from loadTable("dfs://ops", "capacityDaily")
order by day desc limit 30
n = t.size()
// 最小二乘斜率(x 用 1..n 代替日期)
x = 1..n
slope = (n * sum(x * t`totalUsedGB) - sum(x) * sum(t`totalUsedGB))
\ (n * sum(x * x) - sum(x) * sum(x))
latest = last(t`totalUsedGB)
total = 4000.0 // 磁盘总容量(GB)
return (total - latest) \ slope
}
4.2 给区间,不给单点
外推要诚实——增长本身有波动,一个精确到个位的天数是伪精确。工程做法是给区间:
-
用近 7 天斜率算一遍(激进估计)
-
用近 30 天斜率算一遍(稳健估计)
-
两个结果一起报:"按近 7 天增速约 80 天,按近 30 天增速约 140 天"
区间比单点有用得多:决策看的是区间的下界——激进估计都还有 200 天,可以不动;稳健估计只剩 90 天,采购流程现在就要走。
4.3 外推每天都要重算
容量外推不是一个"算过一次"的数字,而是一个每天更新的序列。把 daysToFull 也挂进每日任务,结果入库——它的趋势本身是信号:剩余天数每天都在缩短是正常,缩短速度突然变快说明增长率上了新台阶。
五、决策:三个杠杆的权衡账
倒计时进入行动区间(比如小于 90 天,覆盖采购周期加缓冲)就该做决定了。三个杠杆各自的账:
5.1 杠杆一:收紧保留
稳态后(保留窗口已走满),TTL 每减一天,稳态用量就降一个"日增"的量:
180 天保留 → 120 天保留:稳态用量减少 60 × 日增
(日增 0.5 GB 时 ≈ 省 30 GB)
前提:丢掉的 60 天历史要业务点头。收保留的决策权在数据的使用方,不在运维——这条纪律能避免大量事后扯皮。
5.2 杠杆二:降采样归档
高频数据过期后只留聚合:10 kHz 振动原始波归档下线,在线只留 1 Hz 的特征序列——压缩比是数百倍量级。代价是老数据的频域分析能力没了(故障复盘想看三年前的原始波形,看不到了)。常见折中:近期保原始 + 远期保聚合,分层保留。
5.3 杠杆三:扩容
直接但最贵。扩多少不是拍脑袋:用第四节的斜率外推下一个规划周期(比如 18 个月)的增量,加上 30% 余量——扩一次要覆盖到下个决策窗口,别三个月后又来一次。
5.4 组合决策表
| 倒计时 | 局面 | 建议组合 |
| > 200 天 | 平稳 | 不动,继续每日监控 |
| 90~200 天 | 爬坡未满 | 提前评估:降采样归档 + 小幅扩容的组合方案 |
| < 90 天 | 临近行动线 | 立即走采购 + 临时收紧低价值表保留 |
| 增长台阶刚发生 | 新业务接入 | 重新外推 + 新业务容量评审(下述纪律) |
六、坑与纪律
6.1 压缩比不是常数,理论账别当真
第一笔账里算的"日增 0.5 GB"只是起点。压缩比随数据类型、工况波动、列的基数变化——真实决策依据是实测的增长序列,理论估算只用来做事前评审。这也是第二节强调"把容量变成时序数据"的原因:自己的数最可信。
6.2 监控"剩余最小的盘",不是总量
分布式集群里分区未必均匀:总量还有 40%,某一块盘可能只剩 8%——先满的永远是单盘。快照表按盘拆开记,倒计时按"剩余最小的盘"算。总量充裕而单盘将满的假安全感,比缺容量更危险。
6.3 突增要当事件管,不当统计看
新产线接入让日增翻倍,这不是"增长序列上的一个尖刺",是容量模型的换轨。纪律:任何大的接入(新产线、批量提频、新业务库)都要过一次容量评审——按第一笔账估算增量、按第四节重算倒计时、确认在行动线之外才放行。事后从监控曲线里"发现"扩张,已经晚了半个采购周期。
6.4 告警阈值往后放,倒计时往前放
多数团队的容量告警是"使用率 85%"——这是最后时刻的告警。把告警建立在剩余天数上("倒计时 < 90 天"预警、"倒计时 < 60 天"严重),使用率阈值只作兜底。告警的触发条件,应该是"还来得及做决定的时刻",不是"已经来不及的时刻"。
七、写在最后
这篇文章的每一块拼图都是时序分析的老朋友:累计序列的差分、移动平均看趋势、离群检测抓台阶、线性回归做外推——只不过分析的对象从设备数据换成了平台自己的磁盘。用平台分析平台自己,这是本文最想留下的视角:监控数据也是时序数据,容量规划不过是又一张表上的又一次分析。
四步收拢:
-
先算账:写入到存储的数量级、TTL 稳态的形状、三个杠杆的代价
-
变数据:容量快照入表,增长序列差分
-
看趋势:双移动平均叙事,台阶检测切分外推段
-
算倒计时:区间不给单点,每天重算,决策看下界
两条纪律压轴:
-
监控剩余最小的盘,总量会撒谎
-
告警建在"来得及做决定的时刻"(剩余天数),不建在"来不及的时刻"(使用率)
最后回到那句主张:外推不是预言,是"什么时候必须做决定"的信号。磁盘总会满的——区别只在于,你是提前九十天从容地组合三个杠杆,还是某个深夜对着 85% 的红色告警手忙脚乱地删分区。
相关链接:
DolphinDB 官网:DolphinDB 智能数据平台
DolphinDB 官方文档:DolphinDB 技术文档

浙公网安备 33010602011771号