3271 字
约 10 分钟
16
S11-A06 · 数据库容量与增长规划:从 QPS 到磁盘到连接数
2024-12-31
2026-11-09

容量规划不是"当前用了多少"的报表,而是回答四个问题:还能撑多久、瓶颈先从哪一侧到、扩容要多久、撑不住时降级成什么样。答案只来自四个维度:QPS、连接数、磁盘、单表行数。每个维度的估算都有明确误差来源,把它们写清楚,比算出一个漂亮的小数点更有用。


1. 四个问题各自的输入与输出

问题 需要的输入 输出形态 常见错误
能撑多久 当前水位、日增量、增长率 剩余天数区间 用平均值掩盖高峰
瓶颈先到哪 各维度的余量比例 一个有序清单 只看 CPU 不看连接数
扩容要多久 手段 × 单次操作耗时 排期表 忘算数据迁移与验证
降级怎么做 业务可牺牲顺序 分级预案 把降级写成"限流"一条

四个问题要同时回答:只算撑多久会在错误方向扩容,只排期不定降级线等于押注排期。


2. 四个维度的估算口径

-- 当前写入量级:按业务主键表估算日增量(示例口径,按 MySQL 8.x 核对语法)
SELECT table_name,
       table_rows,
       ROUND(data_length/1024/1024/1024, 2) AS data_gb,
       ROUND(index_length/1024/1024/1024, 2) AS index_gb
FROM information_schema.tables
WHERE table_schema = 'biz'
ORDER BY data_length DESC LIMIT 10;
剩余天数 = (容量上限 × 安全水位 − 当前占用) / 日均净增量
日均净增量 = 日均写入 − 日均清理(归档、TTL、删除标记回收)
维度 估算方法 主要误差来源
QPS 峰值采样 P99 分钟值 × 安全系数 采样窗口太短,漏掉活动峰
连接数 应用实例数 × 池上限 + 后台任务 池上限配了但没算中间件与运维连接
磁盘 单行字节 × 行数 × (1 + 索引系数) + 日志 行变宽(新增列)、索引重建翻倍
单表行数 日增行数 × 保留天数 保留策略没落地,实际不删

table_rows 是采样值,与 COUNT(*) 有偏差,够用于量级判断。


3. QPS 到 CPU 的换算为什么不可靠

同一个"QPS"在不同查询构成下,CPU 成本能差一个数量级:

因素 影响机制 规划含义
查询成本差异 主键点查与多表聚合的 CPU 差几个量级 按"查询类型占比"分桶估,不按总 QPS
缓存命中率 命中缓存时数据库不消耗 CPU 高峰时缓存击穿会把隐藏成本暴露
并发度 高并发带来上下文切换与锁竞争 低 QPS 高并发也可能打满 CPU
可用的换算形式(不用单点系数):
CPU 需求 ≈ Σ(某类查询 QPS × 该类单次 CPU 成本) × 冗余系数
某类单次 CPU 成本:在接近生产的数据量与并发下实测得到,不能从文档抄

结论:QPS→CPU 只能给区间,不能给点值。规划留冗余系数,并把"缓存命中率下降 20%"作为独立压测场景跑一遍。


4. 连接数不是越大越好

数据库侧的并发处理能力受工作线程数与锁竞争约束,应用侧连接池开大只是把排队从应用搬到数据库。

连接数过大的代价 表现
上下文切换 CPU 系统态占比上升,吞吐反而下降
内存 每连接独占排序缓冲、会话缓存,累加可观
数据库侧并发上限 超出 max_connections 直接拒绝,或进入锁等待
故障放大 一个慢查询占住连接,池被逐步耗尽
# 连接池配比示例(HikariCP 口径,按版本核对默认值)
pool:
  maximum-pool-size: 20      # 单实例,经验上不超过数据库可并发数的 1/N
  minimum-idle: 5
  connection-timeout: 3000   # 宁可快速失败,不要让请求无限排队
  max-lifetime: 1800000      # 短于数据库/中间件的空闲断开时间
  leak-detection-threshold: 60000

配比原则:实例数 × maximum-pool-size + 后台任务 + 运维保留 ≤ 数据库并发上限 × 0.8。剩余 20% 给运维、备份、监控与故障手动介入——事故里它比任何调优参数都值钱。


5. 磁盘增长的三部分

组成 增长驱动 处理手段
数据文件 业务写入、行变宽 归档、冷热分离
索引 新增索引、更新导致页分裂 索引审计、合并冗余索引
binlog / 备份 写入量、保留天数、全备频率 缩短保留、增量备份、异地存

经验区间:索引占数据量的比例通常在 20%–60% 之间,宽表加多列索引可超过数据本身。这个比例不是常数,随索引数量与列宽变化,规划时要按自己的表抽样核对,不要套固定系数。

# 磁盘水位与增长趋势(每分钟采样,落到时序库)
df -B1 /var/lib/mysql | awk 'NR==2{print $2, $3}'
# binlog 占用单独统计,别和业务数据混在一个盘
du -sh /var/lib/mysql/binlog 2>/dev/null

磁盘规划的关键不是总量,而是单盘写满的后果:binlog 满会阻塞写入,临时表满会中断大查询,备份盘满会让备份静默失败。三类盘分开是最便宜的防线。


6. 单表行数的实际上限取决于什么

"单表 2000 万行"是个流传的经验值,真实上限由四件事共同决定:

约束 机制 触发信号
索引层数 B+ 树每层一次页访问,行数增大层数增加 点查 P99 出现台阶式抬升
DDL 时间 大表加列/改索引耗时随行数增长 变更窗口从分钟级走向小时级
备份恢复 恢复时间 = 数据量 / 恢复吞吐 演练恢复超过 RTO
统计信息质量 大表采样比例不足导致执行计划跑偏 同一 SQL 计划突然改变
分表触发条件(满足两条以上再动):
1. 单表 > 单机可维护行数,且点查 P99 已受层数影响
2. 在线 DDL 影响写入,需跨窗口变更
3. 备份恢复演练超 RTO
4. 单表写入已成热点,索引维护成本占比过高

先分表还是先分库,判断依据是热点在哪:单表写入集中 → 分表;多表共同撑爆单机 → 分库。分表不解决单机 IO 与连接数上限,这一步必须分清。


7. 增长曲线的三种形态

形态 特征 应对节奏
线性 日增量稳定,方差小 按剩余天数排期,季度复核
阶跃 上线新业务/导入历史数据后跳变 变更前预留,变更后重算基线
病毒式 增长率本身在增长 按周复核,预设降级线

线性增长最危险的是"看起来还很久":按剩余 180 天排期,留给评估、采购、迁移、验证的时间往往只剩一半。阶跃用变更日历驱动复核;病毒式没有规划空间,只能提前把降级做成可开关能力。


8. 扩容手段的代价排序

顺序 手段 单次代价 引入的新问题
1 加索引 / 改 SQL 分钟级,可回滚 索引过多拖慢写入
2 加缓存 天级 一致性、击穿、雪崩
3 读写分离 天级 复制延迟、读到旧数据
4 垂直拆分 周级 跨库查询、事务边界
5 分库分表 月级 路由、分布式事务、聚合查询、扩容再均衡
6 换存储 季度级 双写迁移、回滚路径、运维体系重建
每一步都要先回答:回滚路径是什么、验证口径是什么、业务感知是什么。
没有回滚路径的手段,等价于一次性赌博。

代价排序的意义是先穷尽便宜的:第 1、2 步能解决的问题硬上第 5 步,等于把可用性押在一次跨月迁移上。


9. 压测、阈值与降级

压测的三个必要条件:数据量接近生产、读写混合、看 P99 与慢查询而非平均 QPS。

压测口径:
- 数据量:与生产同量级(至少同数量级的行数与索引结构)
- 混合比:按生产读写比,含一定比例的范围查询与聚合
- 观测:P99 延迟、慢查询条数、连接池等待时间、复制延迟
- 递增:阶梯加压,记录每级的水位与拒绝率
预警项 阈值形态 动作
磁盘 70% / 85% 双线 70% 启动归档,85% 冻结非必要写入
连接池等待 等待时间持续 > 10ms 查慢查询,不是先加池
复制延迟 超过业务可容忍窗口 读流量切主或降级为只读展示
单表行数 接近分表触发线 启动评估,不立即动手

降级按"业务可牺牲顺序"排,而不是按组件:关非核心展示 → 降级为异步写 → 限流入口 → 只保留下单支付。每级要有开关、验证与恢复步骤。


10. 排错:容量判断失准的五种情形

现象 原因 处理
监控显示余量充足,却突然打满 采样窗口太短,漏掉周期性峰值 用 P99 分钟值重算,加活动日历
扩容后性能没改善 瓶颈在连接数或锁竞争,不在 CPU 按维度清单逐项核对余量
磁盘增长远超写入量 binlog/备份与业务数据同盘 分盘,单独监控
单表变大后点查变慢 索引层数增加、缓冲命中下降 评估归档与分表,而非盲加索引
压测达标,上线不达标 数据量或读写比与生产不符 用生产子集重建压测数据集

最后一条最常见:压测库几百万行、生产几亿行,执行计划完全不同。压测的价值取决于数据集像不像生产。


11. 边界:这些情况不必急着动结构

场景 判断 理由
数据量小、增长可预测 不做分片 分片带来的复杂度远超收益
有强一致需求的核心账务 优先垂直拆分而非分库分表 跨分片事务代价高,边界清晰更划算
读写比极高且能容忍短暂旧数据 先读写分离 + 缓存 成本低、可回滚
增长已停止的历史库 只做归档与冷备 结构改造无收益
单机余量 > 一年且增长线性 季度复核即可 过度规划会锁死架构选择

容量规划的正确姿势是保留选择权:用足便宜手段的余量,把昂贵手段的触发条件写清楚,到线再动手。


12. 自测

  1. 容量规划要回答的四个问题里,哪一个决定了应急预案的有效性?
  2. 为什么 QPS 到 CPU 只能给区间,不能给点值?举出三个误差来源。
  3. 连接池调大之后吞吐反而下降,最可能是哪两类代价在起作用?
  4. 磁盘增长的三部分里,哪一部分最容易被漏算,漏算的后果是什么?
  5. 单表行数的实际上限由哪四件事决定?其中哪一件最先暴露?
  6. 扩容手段按代价排序后,为什么"先穷尽便宜的"比"一次到位"更安全?
S11-A06 · 数据库容量与增长规划:从 QPS 到磁盘到连接数
https://www.clxhxhhr.top/posts/6072/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。