容量规划、压测与扩容决策实战

容量规划不是“CPU 到 80% 就加机器”,而是把业务目标、用户访问模型、单实例能力、依赖上限和故障冗余转换为可以验证的容量模型。好的容量规划能够回答三个问题:当前系统还能承受多少负载、下一次活动需要准备多少资源、超过设计能力时系统如何有序降级。

本文面向 Web 服务、API、数据库、中间件和容器平台。示例数字用于说明方法,不能直接替代真实压测和生产数据。

一、先区分四类容量

容量类型 关注内容 常见误区
业务容量 用户数、订单量、任务量、文件量 只看服务器配置,不看业务峰值
服务容量 QPS、并发数、吞吐量、响应时间 把平均值当峰值
资源容量 CPU、内存、磁盘、IOPS、带宽 只看利用率,不看排队和延迟
可靠性容量 单节点故障、机房故障后的剩余能力 平时刚好够用,故障时立即过载

生产容量必须同时满足性能和可靠性。例如 4 个实例在正常情况下刚好承载峰值,但失去 1 个实例后剩余 3 个已经过载,这不是满足高可用要求的容量设计。

二、建立业务负载模型

先从业务量推导请求量,不要直接猜 QPS。假设某系统日活 20 万,10% 的用户集中在最忙的 30 分钟内,每位用户产生 12 次动态请求:

峰值请求量 = 200000 × 10% × 12 = 240000 次
平均峰值 QPS = 240000 ÷ 1800 ≈ 134

真实流量会有秒级突发,还要加入峰值系数。若历史数据表明一分钟峰值通常是半小时均值的 2.2 倍,则目标至少为 295 QPS。活动、批处理和爬虫流量应分开建模,否则平均值会掩盖不同请求的成本差异。

建议记录以下输入:

  • 日、小时、分钟和秒级峰值,不只保存日均值;
  • 请求类型占比,例如查询、写入、导出和登录;
  • 请求大小、返回大小、缓存命中率和数据库访问次数;
  • 周期性任务、消息消费和备份窗口;
  • 年增长率、活动增长系数与不可预测余量;
  • 允许的延迟、错误率和排队长度。

三、用 Little 定律理解并发

在稳定系统中,可以使用近似关系:

并发数 ≈ 吞吐量 × 平均响应时间

当吞吐量为 300 QPS、平均响应时间为 0.2 秒时,平均在途请求约为 60。若下游数据库变慢,响应时间升到 2 秒,即使流量不变,并发也会升到约 600,连接池、线程池和内存压力会同步上升。因此,“并发突然增加”可能是原因,也可能只是下游变慢后的结果。

容量评估应同时观察 QPS、并发和延迟。只提高线程数通常不能解决下游已经饱和的问题,反而可能扩大排队和超时风暴。

四、确定服务级容量目标

先定义通过条件,再开始压测。一个示例目标如下:

指标 通过条件
吞吐量 持续 20 分钟达到 350 QPS
延迟 P95 小于 300 ms,P99 小于 800 ms
错误率 小于 0.1%
CPU 单实例稳定低于 70%
内存 无持续增长和频繁 Full GC
数据库 连接池低于 70%,复制延迟在目标内
恢复 压测停止后 5 分钟内队列恢复正常

平均响应时间会掩盖长尾请求,容量验收应优先使用 P95、P99。还要定义“错误”:HTTP 200 但返回空结果、降级页或业务失败码,也可能是失败。

五、设计代表性压测

1. 流量组成

按照生产比例编排请求,而不是只压一个最简单接口。登录态、缓存冷热、不同租户、大小对象和读写比例都要覆盖。

2. 压测阶段

  1. 基线测试:低负载验证脚本、数据和指标是否正确。
  2. 阶梯测试:逐级增加流量,寻找性能转折点。
  3. 峰值测试:验证预计业务峰值和安全余量。
  4. 压力测试:超过设计值,确认系统如何退化。
  5. 稳定性测试:持续数小时,观察泄漏、GC、队列和连接。
  6. 恢复测试:撤掉流量后确认积压能否消退。

不要在未批准的生产系统直接进行破坏性压测。涉及支付、短信、邮件、库存和第三方接口时,应使用隔离数据、沙箱或明确的流量阻断措施。

六、寻找真正的饱和点

当负载增加时,系统通常经历线性区、弯折区和崩溃区:

  • 线性区:吞吐量随资源增加,延迟变化较小;
  • 弯折区:吞吐增长变慢,延迟、队列和超时快速增加;
  • 崩溃区:重试放大负载,吞吐反而下降。

常见证据包括:

  • CPU 使用率高且运行队列增长;
  • CPU 不高,但锁等待、I/O wait 或下游延迟增加;
  • 内存接近上限、GC 暂停增长或发生 OOM;
  • 磁盘延迟和队列深度上升;
  • 数据库活跃连接到顶、锁等待和慢查询增加;
  • 消息积压增长速度高于消费速度;
  • 出口带宽、NAT 端口或负载均衡连接数接近上限。

“CPU 只有 30%”不能证明还有 70% 容量。单线程热点、锁竞争、限流、连接池和外部配额都可能先成为瓶颈。

七、计算实例数量与冗余

假设单实例在满足 P99 延迟目标时稳定承载 85 QPS,预测峰值为 350 QPS,容量利用目标为 65%:

基础实例数 = ceil(350 ÷ (85 × 65%)) = 7

如果要求任意 1 个实例故障后仍满足峰值,则至少检查 6 个实例是否仍能承载。如果跨可用区部署,还要验证失去一个可用区后的剩余容量,而不是只做 N+1 算术。

资源冗余应按故障域设计:

  • 单进程故障:实例级冗余;
  • 单主机故障:反亲和或分散调度;
  • 单可用区故障:跨区容量;
  • 区域故障:跨区域恢复或流量切换;
  • 下游限额:配额预留和降级策略。

八、自动扩缩容不等于容量规划

自动扩容有启动时间、镜像拉取、预热、缓存建立和健康检查延迟。若流量在 1 分钟内暴涨,而新实例 8 分钟才能可用,单靠 CPU HPA 无法保护系统。

应组合使用:

  • 预测性扩容:活动前提前增加容量;
  • 快速指标:请求队列、并发或自定义业务指标;
  • 最小实例数:保留即时冗余;
  • 扩容速度和稳定窗口:避免抖动;
  • 负载保护:限流、排队、负载卸载和熔断;
  • 缩容保护:确认长连接、任务和缓存不会被突然终止。

九、容量报告模板

每次评估至少输出以下内容:

业务范围:订单查询 API
预测周期:未来 6 个月
峰值模型:350 QPS,读写比 8:2,峰值系数 2.2
性能目标:P95 < 300 ms,错误率 < 0.1%
单实例能力:85 QPS(满足延迟目标时)
部署建议:7 个实例,跨 3 个故障域
主要瓶颈:数据库写入、NAT 连接上限
保护措施:限流、排队、写入降级、提前扩容
触发条件:预测 14 天内达到安全容量的 75%
回退条件:错误率、P99 或下游延迟超过阈值

报告必须写明测试版本、数据规模、环境差异和不确定性,避免把测试环境结果当成生产保证。

十、扩容决策树

  1. 用户体验是否接近 SLO 边界?若没有,先确认是否只是资源利用率偏高。
  2. 是否存在明确的饱和证据?确认 CPU、内存、I/O、锁、连接或配额。
  3. 能否通过修复低效查询、缓存或批处理降低需求?
  4. 瓶颈能否水平扩展?有状态组件可能需要分片或架构调整。
  5. 扩容后下游是否成为新瓶颈?
  6. 故障域和冗余是否仍满足要求?
  7. 是否有验证、监控、停止条件和回退方案?

十一、常见错误

  • 用平均 QPS 和平均延迟估算峰值容量;
  • 只压应用,不准备与生产相近的数据规模;
  • 忽略缓存冷启动、连接建立和 JVM 预热;
  • 只看压测期间,不看停止后的积压恢复;
  • 把资源利用率阈值直接当作业务容量;
  • 无限重试,导致过载时形成重试风暴;
  • 扩容应用实例,却未检查数据库、DNS、NAT 和第三方配额;
  • 没有保留单节点或单故障域失效余量。

十二、容量模型需要持续校准

容量报告不是永久结论。代码版本、数据量、请求结构、缓存命中率、实例规格和下游配额变化后,单实例能力都可能改变。建议建立以下复核触发器:

  • 核心版本或架构发生明显变化;
  • 数据规模、日活或峰值流量增长超过 20%;
  • 实例规格、数据库参数或存储类型调整;
  • 出现由过载、队列或限流引发的事故;
  • 大型活动和容量采购之前;
  • 即使没有变更,也至少按季度复核关键服务。

每次复核应比较预测与实际:预测峰值、实际峰值、计划实例数、实际实例数、单实例吞吐、资源水位和用户 SLI。如果实际偏差长期超过预设范围,应修正模型中的峰值系数或请求成本,而不是每次临时增加余量。

容量数据也要保留版本。报告应能回答“当时为什么买这些资源”,避免只留下最终数字而没有业务假设和测试证据。

十三、上线前检查清单

  • [ ] 有分钟和秒级峰值数据,而不是只有日均数据;
  • [ ] 请求类型、数据量和缓存状态具有代表性;
  • [ ] 定义了吞吐、长尾延迟、错误率和恢复目标;
  • [ ] 找到了第一个饱和资源及其证据;
  • [ ] 验证了单节点或单故障域失效后的容量;
  • [ ] 扩缩容指标、速度、预热与缩容保护已验证;
  • [ ] 限流、排队、熔断和降级策略可用;
  • [ ] 结果记录了版本、环境差异和有效期;
  • [ ] 容量报告有负责人和下次复核日期。

十四、参考资料

Copyright © yan-jian.com 2023 - 2026 · Powered by GitBook更新时间: 2026-10-18 22:49:34

results matching ""

    No results matching ""