深色模式
容量演练
容量模型算得再准,不演练就是纸上谈兵。演练的目标是:验证单机能力、找到全链路最弱环节、验证扩容与限流真的生效。
适用环境
- 独立的压测环境与生产同规格(最低要求:预发环境 + 流量隔离)
- 压测机 2 台以上,独立于被测环境
- 已有监控大盘与告警
bash
# 演练前环境确认
kubectl get deploy -n prod | head
kubectl get hpa -n prod1
2
3
2
3
操作步骤
1. 明确演练目标与停止条件
text
目标:
1) 验证峰值 3000 QPS 下 P99 < 300ms
2) 找到全链路第一个饱和的组件
3) 验证 HPA 在 3 分钟内完成扩容
4) 验证限流在 5 倍流量下保护核心链路
停止条件(任一触发立即停止):
- 错误率 > 1%
- P99 > 1s 持续 2 分钟
- DB 连接数 > 90% 上限
- 任何组件 OOM 或不可用1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
停止条件必须提前写进文档并指定执行人,避免现场争论。
2. 做流量染色与数据隔离
bash
# 压测请求带标记头,服务端据此写入影子库/影子表
wrk -t8 -c400 -d300s \
-H 'X-Load-Test: true' \
-H 'X-Shadow-DB: true' \
http://lb.example.com/api/order1
2
3
4
5
2
3
4
5
数据隔离三选一:影子库表(推荐)、压测账号白名单、流量录制回放后丢弃写请求。
禁止对生产做无隔离写入
未做数据隔离的压测会污染真实订单数据和统计报表,且清理成本极高。任何写接口压测必须先确认影子链路已生效。
3. 准备压测脚本
lua
-- wrk 脚本:动态构造请求参数,避免全部命中同一条缓存
-- order.lua
local counter = 0
request = function()
counter = counter + 1
local uid = 100000 + (counter % 50000)
local path = "/api/order?uid=" .. uid .. "&sku=" .. (counter % 2000)
return wrk.format("GET", path, {["X-Load-Test"] = "true"})
end1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
bash
wrk -t8 -c400 -d300s --latency -s order.lua http://lb.example.com1
4. 全链路观测清单
压测期间同时盯以下指标,逐层记录"谁先饱和":
promql
# LB 层
sum(rate(nginx_http_requests_total[1m]))
# 应用层
sum(rate(process_cpu_seconds_total{process="order-api"}[5m]))
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 缓存层
redis_connected_clients / redis_config_maxclients
# 数据库层
mysql_global_status_threads_connected / mysql_global_variables_max_connections
rate(mysql_global_status_slow_queries[5m])
# 消息层
sum(rate(kafka_topic_messages_in_total[1m]))1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
bash
# 同时盯系统层
ssh app-01 'vmstat 1 5; iostat -x 1 3'1
2
2
5. 阶梯加压执行
bash
for c in 100 300 600 1000 1500; do
echo "=== $(date +%T) concurrency=$c ==="
kubectl get hpa order-api --no-headers | awk '{print "replicas="$6" "$7}'
wrk -t8 -c"$c" -d120s --latency -s order.lua http://lb.example.com \
| grep -E 'Requests/sec|99%|Non-2xx'
sleep 60 # 留给扩容与恢复
done1
2
3
4
5
6
7
2
3
4
5
6
7
每一档记录:并发、QPS、P99、错误率、实例数、各层水位。
6. 验证扩容与限流
bash
# 扩容验证:加压后看副本数变化
kubectl get hpa order-api -w
# 限流验证:加大到 5 倍目标流量,确认返回 429 而非 5xx
wrk -t16 -c3000 -d60s http://lb.example.com/api/order \
| grep -E 'Non-2xx|Requests/sec'1
2
3
4
5
6
2
3
4
5
6
7. 演练后恢复
bash
# 恢复副本数、清理影子数据、关闭压测开关(逐项打勾)
kubectl patch hpa order-api -p '{"spec":{"minReplicas":3,"maxReplicas":20}}'
kubectl scale deploy order-api --replicas=31
2
3
2
3
验证
演练产出必须包含一张表:
| 并发 | QPS | P99 | 错误率 | 实例数 | 首个饱和组件 |
|---|---|---|---|---|---|
| 300 | 900 | 45ms | 0% | 3 | 无 |
| 600 | 1750 | 62ms | 0% | 5 | 无 |
| 1000 | 2600 | 180ms | 0.05% | 8 | DB 连接 78% |
| 1500 | 2900 | 780ms | 1.2% | 10 | DB 连接池耗尽 |
结论要写清:容量上限是多少、瓶颈在哪、下一步做什么。
常见坑
在业务高峰期演练
突发压测流量叠加真实流量会直接造成故障。演练必须选低峰期(如凌晨),并提前通知相关方。
压测数据不真实
全部请求同一个 uid/sku 会命中缓存,QPS 虚高数倍。必须用脚本构造离散参数,并预热出接近生产的缓存命中率。
只压不观测
只跑压测不记录各层水位,演练完只知道"扛不住",不知道"哪里扛不住"。观测清单必须提前准备好。
演练后忘记恢复
minReplicas 忘调回、影子开关忘关闭、限流阈值忘还原,都会在真实大促时造成意外。演练结束必须有恢复检查清单并逐项打勾。