深色模式
突发流量应对
突发流量打挂系统的原因往往不是"容量不够",而是"扩容速度跟不上"和"冷启动太慢"。本文从弹性速度、预热、兜底三条线给出方案。
适用环境
- Kubernetes 集群(HPA/KEDA)或云弹性伸缩组
- 服务有 LB 与健康检查
- 已有基础监控与限流能力
bash
# 确认弹性组件状态
kubectl get hpa
kubectl get deploy order-api -o jsonpath='{.spec.template.spec.containers[0].readinessProbe}{"\n"}'1
2
3
2
3
操作步骤
1. 算清突发增长速率(决定扩多快)
promql
# 观察历史上最快的一次流量上涨:1 分钟内的 QPS 增幅
deriv(sum(rate(http_requests_total[1m]))[30d:1m])1
2
2
text
扩容所需时间 = 镜像拉取 + 启动 + 预热 + 健康检查
≈ 60 ~ 180 秒(Java 更久)
安全垫容量 = 增长速率 × 扩容耗时1
2
3
2
3
若 1 分钟涨 2000 QPS、扩容要 3 分钟,则必须常备 ≥ 6000 QPS 的冗余,否则必然被打穿。
2. 提高弹性速度:镜像与启动优化
多阶段构建减小镜像(拉取时间是大头),并在节点上预热镜像:
dockerfile
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app ./cmd/api
FROM gcr.io/distroless/base-debian12
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
bash
# 用 DaemonSet 或镜像预热服务在所有节点预拉取,省掉最耗时的拉取阶段
kubectl get nodes -o name | wc -l1
2
2
3. 配置 HPA 快速扩容、慢速缩容
yaml
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100 # 允许一次翻倍
periodSeconds: 30
- type: Pods
value: 8
periodSeconds: 30
selectPolicy: Max # 取最激进策略
scaleDown:
stabilizationWindowSeconds: 9001
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
4. 预热:避免冷启动打挂
yaml
readinessProbe: # 就绪检查通过才接流
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 2
failureThreshold: 3
startupProbe: # 慢启动应用用 startupProbe 兜底
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 51
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
yaml
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "curl -s localhost:8080/warmup"]1
2
3
4
2
3
4
预热内容:JIT 热点代码、本地缓存、DB 连接池、下游 RPC 连接、配置拉取。
5. 提前扩容(计划性突发)
大促/活动前按预估手动扩容,不要依赖自动扩容:
bash
kubectl scale deploy order-api --replicas=12
kubectl patch hpa order-api -p '{"spec":{"minReplicas":12}}'1
2
2
活动结束后再调回:
bash
kubectl patch hpa order-api -p '{"spec":{"minReplicas":3}}'1
6. 兜底:限流与降级
yaml
# Nginx 限流示例
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
server {
location /api/ {
limit_req zone=api burst=200 nodelay;
limit_req_status 429;
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
优先级:保核心链路(下单、支付),降级非核心(推荐、评论、报表)。降级开关要提前埋点并可热开关。
7. 兜底:队列削峰
text
入口 QPS 10000 → MQ 缓冲 → 消费端按 3000 QPS 匀速处理1
适用于可异步的场景(发券、通知、写日志),对强一致读请求无效。
验证
bash
# 阶梯式突增压测:10 秒内把并发从 50 拉到 800,观察 5 分钟
wrk -t8 -c50 -d30s http://lb/api/order
wrk -t8 -c800 -d300s --latency http://lb/api/order1
2
3
2
3
关注指标:错误率是否 > 0.1%、P99 是否短暂恶化后恢复、HPA 是否在 2 分钟内完成扩容、DB 是否被拖垮。
常见坑
冷启动即接流
JVM 刚启动 JIT 未优化、连接池为空,此时接流会让首批请求超时并触发重试风暴。必须有 readiness 门槛 + 预热 + 慢启动权重。
缩容过快造成抖动
流量小幅回落就缩容,随后又涨回来,反复扩缩导致持续抖动。缩容稳定窗口至少 10~15 分钟。
只扩应用不扩依赖
应用扩了 20 台,缓存和 DB 没扩,结果 DB 被打挂。突发预案必须覆盖全链路依赖。
无限流兜底
弹性再快也有上限。没有限流时流量涨到 10 倍会直接把 DB 压垮,全站不可用;有限流时只损失部分请求。