容量评估与压测方法论¶
要点卡¶
30 秒回答
容量规划把业务负载模型、单元实测能力、故障场景和安全余量连接起来;压测要找满足 SLO 的最大稳定负载、排队拐点和资源饱和点,而不是只追峰值 QPS。Headroom 没有通用 30%: 应由单可用区损失、滚动发布、增长误差和扩容时延反推,并通过阶梯、突发、耐久和故障压测验证。
3 分钟展开
- 是什么:估算需要多少机器/DB/带宽;用压测证明设计在峰值下满足 SLO。
- 为什么:大促、增长、新功能上线前避免「上线即宕」;成本与可靠性平衡。
- 怎么做:Little 定律估平均在途量;单实例测出 workload-specific 基线,再做集群压测验证 共享依赖、热点和非线性效应;阶梯加压同时观察吞吐、P95/P99、错误、队列、连接池、GC 和下游。
| 记忆槽 | 内容 |
|---|---|
| 三个不变量 | workload 必须可复现;容量取满足 SLO 的最大稳定负载;headroom 由故障/发布/扩容场景反推 |
| 手画图 | forecast → unit load test → saturation knee → cluster/dependency test → scenario factor → verify |
| 项目落点 | 用实际 API、索引器、行情或风控链路说明 payload、命中率、fan-out、持久化和 P99 口径;只引用本人实际参与部分和可解释指标 |
| 一个取舍 | 高利用率省成本但缩小故障余量;更多 headroom 提升韧性却增加成本,需由 SLO 与扩容时延决定 |
错误表达
- ❌ “CPU 没到 70% 就有容量;单 Pod 5000 QPS,20 Pod 必然线性到 10 万;统一预留 30%。”
- ✅ “吞吐会受共享 DB、热点、队列和负载均衡影响;比例和余量都必须由场景压测证明。”
自测追问:Little 定律为什么用平均系统时间而不是 P99?如何测试单 AZ 故障同时滚动发布?
10 分钟版(原理 + 图示)¶
flowchart LR
Forecast[业务预测 QPS] --> Single[单 Pod 压测]
Single --> Formula["N = peak load / tested safe capacity × scenario factor"]
Formula --> Cluster[集群压测验证]
Cluster --> SLO{P99 & 错误率 OK?}
SLO -->|否| Tune[优化/扩容]
SLO -->|是| Prod[容量基线文档]
Little 定律
并发数 N = 到达率 λ × 平均响应时间 W
- Little 定律使用的是长期平均在系统时间 W,不是 P99。例:到达率 1000/s、平均响应时间 200ms,则平均在途请求约 200;连接池和并发上限还要结合分布、排队、下游 fan-out 与目标分位单独压测。
容量估算模板
| 项 | 公式/数值 |
|---|---|
| 峰值 QPS | 业务预测 × 季节性/活动模型 × 预测误差;倍率来自历史或演练 |
| 单 Pod QPS | 满足该服务既定延迟/错误 SLO 时的最大稳定负载 |
| Pod 数 | ceil(peak_load / tested_safe_capacity × scenario_factor);factor 覆盖故障域、发布与扩容时延 |
| DB 连接 | Pod 数 × 每 Pod 池上限 ≤ 数据库经压测确认的安全连接预算 |
| 带宽 | QPS × 响应字节 × 8 |
| Redis | 按命令类型、value 大小、pipeline、网络和持久化配置实测分片能力 |
计算示例(变量来自实测或预测,不提供通用默认值)
- 若预测峰值为
Q_peak、单 Pod 满足 SLO 的安全能力为Q_safe,基础副本数是ceil(Q_peak / Q_safe)。 - 再按“损失一个故障域 + 滚动发布重叠 + 扩容生效前增长”分别验算场景;不要把这些风险
不加区分地压成固定
×1.3。 - 带宽、数据库回源和缓存容量还要代入 payload 分布、命中率、fan-out、协议开销和重试, 不能由 API QPS 单独推出“必须读写分离 + 缓存”。
压测类型
| 类型 | 目的 |
|---|---|
| 基准 | 建立单元能力与资源成本基线 |
| 负载 | 目标 QPS 下 SLO |
| 压力 | 找到 SLO 拐点、饱和点与失效模式 |
| 耐久(soak) | 观察随时间累积的泄漏、碎片、连接和队列问题;时长按风险决定 |
| 故障 | 在依赖降级、实例/AZ 损失、发布重叠下验证容量 |
生产场景¶
- 活动容量评审:从历史同类活动、业务计划和预测误差得到峰值范围,再在 MQ/DB/缓存等 共享依赖参与的情况下验证。
- Go 服务扩容:HPA 指标、target、min/max replicas 与 stabilization window 来自 压测曲线和扩容时延;CPU 不是 I/O、连接池或队列饱和服务的充分信号。
- 可观测:压测期间 RED、GC pause、DB slow query。
排查与工具¶
| 工具 | 用途 |
|---|---|
| k6 / Vegeta / wrk | HTTP 压测 |
go test -bench |
微基准 |
| pprof / trace | 瓶颈分析 |
| 生产 shadow traffic | 真实流量形状 |
架构取舍¶
| 方案 | 适用 | 不适用 |
|---|---|---|
| 线性外推 | 只用于形成待验证的初始估算 | 不能替代集群与共享依赖压测 |
| 生产压测 | 最真实 | 风险需隔离 |
| 独立压测环境 | 安全 | 数据/规模不一致 |
| 仅 CPU 扩容 | CPU bound | IO/DB bound |
深挖问答¶
- 压测数据哪来? → 生产采样脱敏;合成数据注意热点分布。
- 安全余量如何定? → 分别量化故障域损失、滚动发布、预测误差和扩容时延,再验证最坏 组合;没有“互联网 ×1.3、金融 ×2”的通用常数。
- Go 压测看哪些? → QPS、P99、GC、goroutine、heap、syscall。
- 压测通过上线仍挂? → 流量形状不同(热点 Key)、依赖未 mock、数据量不同。
- 如何压 DB? → 独立从库;限制连接;或用影子表。
反模式与事故¶
- 只压 HTTP 不压 MQ 消费者,lag 爆炸。
- 用 4 核笔记本压测推断 32 核生产。
- 无阶梯加压,瞬间打满触发 DDoS 防护。
- 压测账号打生产 DB 脏数据。
代码示例¶
// Vegeta 目标函数示例 — 也可 go test benchmark
func BenchmarkHandler(b *testing.B) {
h := NewHandler(testDeps)
req := httptest.NewRequest(http.MethodGet, "/api/v1/item/1", nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
b.Fatalf("status %d", rec.Code)
}
}
}
// 容量记录结构
type CapacityBaseline struct {
Service string
PodSpec string // 8C16G
WorkloadID string // payload/命中率/fan-out/数据分布版本
SafeQPS int // 满足该服务既定 SLO 的最大稳定值
Bottleneck string // 实测首个饱和资源或依赖
TestedAt time.Time
}