缓冲与流量塑形
→ 返回 高并发
数据层外面的缓冲指:在请求进入 MySQL / 核心 Redis 写路径之前,用队列、限流、异步与丢弃策略吸收流量形状。高并发系统里,入口形态往往比数据库选型更决定生死。
流量塑形目标
| 目标 | 手段 |
|---|---|
| 削峰 | 队列积压 + 消费者匀速处理 |
| 隔离 | 线程池 / 舱壁,慢依赖不拖垮全局 |
| 快速失败 | 超限直接 429,保护线程 |
| 背压 | 下游慢时上游减速 |
| 合并 | 窗口内多次写合并一次 |
分层缓冲示意
用户
▼
[CDN / 静态] ← 静态资源不进业务
▼
[L7 网关 / API Gateway] ← 全局限流、鉴权、WAF
▼
[应用接入层] ← Tomcat 队列、异步 Servlet、本地队列
▼
[消息队列] ← 核心削峰(Kafka / RocketMQ / 内存队列)
▼
[聚合 / 计算服务] ← 合并写、批量刷 Redis
▼
[数据层] ← MySQL / Redis 持久结构
网关与限流
算法选择
| 算法 | 特点 | 场景 |
|---|---|---|
| 令牌桶 | 允许一定突发 | API 全局限流 |
| 漏桶 | 输出匀速 | 保护下游固定吞吐 |
| 滑动窗口 | 精确计数 | 按用户 / IP 每分钟 N 次 |
| 固定窗口 | 实现简单,边界双倍 | 不推荐单独用于资金类 |
# 示意:Spring Cloud Gateway 限流
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter
# Redis 实现分布式计数分布式限流需 Redis / 网关集群共享计数器,见 Redis 限流 Lua。
按维度限流
| 维度 | 示例 |
|---|---|
| 全站 | 保护整体 |
| 用户 ID | 防刷、午夜步数上报 |
| 接口 | /report 单独配额 |
| 租户 | SaaS 隔离 |
应用层缓冲
同步改异步
@PostMapping("/report")
public DeferredResult<ApiResp> report(@RequestBody Req req) {
DeferredResult<ApiResp> dr = new DeferredResult<>(3000);
executor.submit(() -> {
mq.send(req);
dr.setResult(ApiResp.ok());
});
return dr;
}或:先返回 202 Accepted,客户端轮询 / WebSocket 推送结果。
本地内存队列(轻量削峰)
请求 → LinkedBlockingQueue(有界)
→ 单线程 / 小线程池批量消费 → Redis / MQ
| 优点 | 风险 |
|---|---|
| 极快 | 进程挂则丢;需有界防 OOM |
| 减少 RTT | 多实例间不共享,需 MQ 兜底 |
Disruptor(环形队列)用于超低延迟金融场景;一般业务 有界 BlockingQueue + 批量 flush 即可。
线程池隔离(舱壁)
| 池 | 用途 |
|---|---|
http-worker | 接口逻辑 |
mq-send | 发消息 |
db-io | 落库 |
慢 DB 占满 db-io 不影响接口接请求。
消息队列作为核心缓冲
峰值 10 万 QPS 写入
消费者 2 万 QPS 处理
→ MQ 积压上升,但**不打挂 DB**
→ 扩容消费者或容忍 lag
| 选型 | 说明 |
|---|---|
| Kafka | 高吞吐、日志型、可回溯 |
| RocketMQ | 业务 MQ、定时消息 |
| Redis Stream | 轻量、内存受限 |
监控:消费 lag、入队速率、拒绝率。
背压与过载保护
| 策略 | 行为 |
|---|---|
| 排队超时 | 等待 N ms 后 503 |
| 熔断 | 下游错误率超阈值,直接失败 |
| 降级 | 关排行榜、只记步数 |
| 负载丢弃 | 非核心请求优先丢(需产品定义) |
Little 定律:队列长度 = 到达率 × 平均停留时间。只加机器不控到达率,队列仍会爆。
与排行榜结合
微信步数场景:
- 网关:每用户每秒 1 次上报限流
- 接入:校验后 只发 MQ,同步路径 < 10ms
- MQ:分区扩容消费
- 消费端:500ms 合并窗口 再写 Redis
见 排行榜与实时计数。