一、业务场景:什么情况下必须限流?
1. 突发流量场景(秒杀 / 抢购)
活动期 QPS = 2000日常 QPS = 10-50→ 突发 40 倍流量,必须限流
项目实战:
"季度结息活动 ,凌晨 0 点开放 ------QPS 从 50 飙到 3000 ------没有限流系统就崩了。"
2. 恶意攻击防护
恶意 IP 疯狂请求 → 限流保护压测得到系统最大 QPS → 设上限
"系统压测最大 QPS = 1500 ------限流阈值设 1200 ------保留 20% 缓冲给突发流量。"
二、Nginx 限流(2 大经典场景)
1. 控制速率(漏桶算法)
应对突发流量 --- 让请求以固定速率处理:
# nginx.confhttp { # 定义限流区域:10MB 内存,每秒 1 个请求 limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; server { location /api/ { # ⚠️ burst=5 允许突发 5 个请求,nodelay 不延迟立即处理 limit_req zone=one burst=5 nodelay; proxy_pass http://backend; } }}
关键参数:
rate=1r/s= 每秒 1 个请求burst=5= 允许突发 5 个 (漏桶缓冲)nodelay= 突发请求立即处理 ,不排队
Mavis 实战注释:
- ⚠️
$binary_remote_addr= 按 IP 限流 - ⚠️
zone=one:10m= 10MB 内存够记 16 万 IP
2. 控制并发数
http { # 限制每个 IP 并发连接数 = 10 limit_conn_zone $binary_remote_addr zone=addr:10m; server { location /api/ { limit_conn addr 10; proxy_pass http://backend; } }}
"limit_req 控制速率,limit_conn 控制并发数"
三、网关限流(Spring Cloud Gateway + Sentinel)
1. 核心配置
# application.ymlspring: cloud: gateway: routes: - id: limit_route uri: lb://backend-service predicates: - Path=/api/** filters: # ⚠️ 令牌桶算法,每秒填充 100 个,桶容量 200 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 100 # ⚠️ 每秒填充速率 redis-rate-limiter.burstCapacity: 200 # ⚠️ 令牌桶总容量 key-resolver: "#{@ipKeyResolver}" # ⚠️ 按 IP 限流
2. KeyResolver 配置(按 IP 或路径)
@Configurationpublic class RateLimiterConfig { @Bean public KeyResolver ipKeyResolver() { return exchange -> Mono.just( exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() ); } @Bean public KeyResolver pathKeyResolver() { return exchange -> Mono.just( exchange.getRequest().getPath().value() ); }}
"按 IP 限流防恶意攻击 ,按路径限流保护热点接口 ------两个 KeyResolver 配合用。"
四、限流 4 大经典算法
1. 固定窗口计数器 (最简单)
时间窗口:1 秒限流阈值:100 QPS第 1 秒:请求 1-100 通过,第 101 个拒绝第 2 秒:计数器清零,重新开始
优点 :实现简单 缺点 :窗口边界突刺 (1 秒末 + 2 秒初 = 200 QPS ,超阈值 2 倍)
2. 滑动窗口计数器 (改进版)
把 1 秒分成 5 个 200ms 小窗口每个小窗口独立计数总请求 = 最近 5 个小窗口之和
优点 :平滑限流 ,避免边界突刺 缺点 :窗口越多,内存越大
3. 漏桶算法 (Nginx 用这个)
请求 → 漏桶 → 处理(固定速率) ↓ 桶满 → 拒绝
特点 :强制恒定速率处理 ------保护下游 ------适合流量整形
Mavis 注解:
- ⚠️ 漏桶 = "整流" ------ 流量再大,出去也是匀速
- ⚠️ 适合保护下游系统 ------不能让下游被打挂
4. 令牌桶算法 (Spring Cloud Gateway 用这个)
令牌桶 → 匀速生成令牌 → 请求拿令牌 → 处理 ↓ 桶满 → 丢弃令牌
特点 :允许突发流量 ------桶里存多少就能突多少
Mavis 注解:
- ⚠️ 令牌桶 = "蓄洪" ------ 平时攒令牌,大流量来了能扛一阵
- ⚠️ 秒杀 / 抢购 首选------应对突发
5. 4 大算法对比表
| 算法 | 原理 | 优点 | 缺点 | 适用 |
|---|---|---|---|---|
| 固定窗口 | 1 个大窗口计数 | 实现简单 | 边界突刺 | 不推荐生产 |
| 滑动窗口 | N 个小窗口求和 | 平滑 | 内存占用 | 金融首选 |
| 漏桶 | 匀速处理 | 保护下游 | 无法应对突发 | 流量整形 |
| 令牌桶 | 匀速生成令牌 | 可突发 | 实现复杂 | 秒杀抢购 |
记忆口诀:
"漏桶整流,令牌蓄洪" "固定窗口有边界突刺,滑动窗口平滑" "秒杀用令牌,金融用滑动"
五、3 大经典面试追问
追问 1:为什么用令牌桶不用漏桶?
"秒杀场景允许突发 ------令牌桶攒令牌能扛突发流量 。漏桶强制匀速 ------秒杀高峰用户体验差。"
追问 2:限流阈值怎么定?
"压测得到系统最大 QPS = 1500 ,限流阈值设 1200 ------保留 20% 缓冲 ------给 GC / 网络抖动留余量。"
追问 3:网关限流和 Nginx 限流什么区别?
"Nginx 限流在最外层 ------防大流量直接打挂网关 。网关限流在业务层 ------按用户 / IP / 路径细粒度控制 。两层配合用 ------Nginx 先挡 80% 恶意流量 ,网关再细控业务。"
六、记忆口诀
"秒杀令牌,流量整形漏桶"
"Nginx 外层挡恶意流量,网关内层细控"
"limit_req 速率,limit_conn 并发"
"令牌桶 replenishRate + burstCapacity"
"QPS = 1500 时限流设 1200,留 20% 缓冲"
"滑动窗口防边界突刺,金融首选"
"高并发限流体系建设"
- 双层限流 :Nginx(最外层)+ Spring Cloud Gateway + Sentinel(业务层)
- 算法选型 :令牌桶(应对突发)+ 滑动窗口(金融合规)
- 实战 :季度结息 QPS 从 50 飙到 3000 ,限流后系统稳定
- 配置 :replenishRate=100 + burstCapacity=200 ,保留 20% 缓冲
- 按 IP + 路径双维度限流 ,防恶意攻击 + 保护热点接口