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 技术文档

posted @ 2026-11-03 16:12  Xxtaoaooo  阅读(2)  评论(0)    收藏  举报