削峰填谷

场景

某个大型活动期间,流量暴增。

活动概况

活动
双 11 促销
客户类型
大量电商客户
持续时间
24 小时
平时流量
10 万次/天
活动流量
100 万次/天
10 倍增长
峰值流量
平时 QPS 的 20 倍

问题分析

流量分析

流量对比:
平时
日均 10 万次/天
QPS 1.2 次/秒
活动期间
日均 100 万次/天
QPS 11.5 次/秒
峰值 200 次/秒(持续 10 分钟)
系统容量:
数据库
50 次/秒
应用服务器
100 次/秒
结论: 峰值流量(200 次/秒)远超系统容量(数据库 50 + 应用 100 = 150 次/秒)

解决方案:消息队列

架构演进:同步 vs 异步

同步处理(之前)
用户请求
应用服务器
数据库(阻塞等待)
异步处理(现在)
用户请求
应用服务器
消息队列
立即返回(接受)
后端消费 & 写入数据库

实现

1. 消息队列选择

使用 RabbitMQ

为什么选择 RabbitMQ:
- 可靠性高(持久化、确认机制)
- 支持多种消息模式
- 社区活跃
- 有管理界面
选型边界
为什么用 RabbitMQ 做削峰
触发问题
活动流量在短时间内冲高,后端处理能力稳定但入口瞬时请求远超容量,需要把“接收请求”和“处理任务”解耦。
候选方案
应用内队列、Redis Stream、RabbitMQ、Kafka、直接扩容应用实例。
选择理由
RabbitMQ 的确认、持久化和死信队列更适合当前这种任务可靠投递场景,运维复杂度也低于 Kafka。
代价
用户无法立即拿到最终结果,需要设计任务状态查询、重试、超时和失败提示。
暂不解决
暂不做大规模日志流式处理;如果未来吞吐变成百万级持续写入,再评估 Kafka。

2. 队列设计

设计流程
2. 队列设计
  1. 步骤 1:写入队列并异步消费任务
  2. 步骤 2:准备流量入口、防护规则、队列容量和降级开关
  3. 步骤 3:写入队列并异步消费任务
  4. 步骤 4:写入队列并异步消费任务
关注点:入口保护、核心服务可用性、误伤率和容量余量。

3. API 处理改为异步

设计流程
3. API 处理改为异步
  1. 步骤 1:识别突发流量或攻击特征,并执行防护策略
  2. 步骤 2:更新限流、排队、降级或防护策略
  3. 步骤 3:写入队列并异步消费任务
  4. 步骤 4:刷新防护规则、热点数据或排队状态
关注点:入口保护、核心服务可用性、误伤率和容量余量。

4. 查询结果

设计流程
4. 查询结果
  1. 步骤 1:更新限流、排队、降级或防护策略
  2. 步骤 2:刷新防护规则、热点数据或排队状态
  3. 步骤 3:写入队列并异步消费
  4. 步骤 4:校验身份、密钥或权限
关注点:入口保护、核心服务可用性、误伤率和容量余量。

队列管理

监控队列长度

设计流程
监控队列长度
  1. 步骤 1:检查健康状态并触发告警
  2. 步骤 2:写入队列并异步消费
  3. 步骤 3:采集健康状态并触发告警
关注点:入口保护、核心服务可用性、误伤率和容量余量。
上线前多想一步
  • 队列最多能堆多少? 堆积不是越多越好,超过某个数量就应该限流或降级。
  • 任务失败重试几次? 一直重试会拖垮队列,重试完还失败要进入人工可查的列表。
  • 用户怎么看进度? 异步处理后,页面要能告诉用户“处理中、成功、失败”,不能只让用户等。

当前架构