Skip to content

限流

四种限流算法、分布式限流、限流粒度。

Updated View as Markdown
For humans

限流

限流是保护系统的第一道闸门:主动拒绝过量请求,保护自己不被冲垮。面试必考四算法和分布式限流。

四种算法

令牌桶与滑动窗口

算法 机制 优点 缺点
固定窗口 每窗口计数,超阈值拒绝 实现简单(INCR + EXPIRE) 窗口边界突刺:交界处可双倍流量
滑动窗口 细粒度窗口滚动计数 精确,无突刺 存储开销(每请求记时间戳)
令牌桶 匀速补令牌,有令牌才放 允许突发、平滑 实现稍复杂(Lua)
漏桶 恒定速率流出 绝对平滑 不允许突发,队列积压

面试要点:

  • 固定窗口的突刺问题必答(前后窗口交界瞬间可放行 2 倍)
  • 令牌桶是生产主流:允许突发符合业务直觉(秒杀前 1 秒允许集中请求)
  • 漏桶适合必须匀速的场景(写入下游、定时任务)

分布式限流

单机限流(进程内计数)在多实例下各自为政,总量失控。分布式限流:

方案 机制 特点
Redis + Lua 计数存 Redis,Lua 原子操作 标准方案,见 Redis 事务与 Lua 篇
网关限流 Nginx/API 网关统一限 第一道防线,全局视角
消息队列削峰 请求入队按能力消费 不拒绝而是排队(见异步化篇)
-- Redis 固定窗口限流(Lua 原子)
local current = redis.call("INCR", KEYS[1])
if current == 1 then
    redis.call("EXPIRE", KEYS[1], ARGV[1])
end
if current > tonumber(ARGV[2]) then
    return 0
end
return 1

要点:Redis 是单线程,INCR + EXPIRE 天然原子;分布式限流引入 Redis 依赖,Redis 挂了要降级(本地限流兜底),别因限流组件变单点。

限流粒度

粒度 例子 目的
接口级 登录接口 10 次/分钟 防刷
用户级 每用户 100 次/分钟 公平使用
IP 级 每 IP 1000 次/分钟 防爬
全局限流 系统总 QPS 上限 保护系统

分层组合:网关按 IP/全局限,应用按用户/接口限。限流要有反馈:被限的请求返回 429 + 重试头(Retry-After),客户端才知道退避。

面试追问

  1. 四种算法的区别? 固定窗口简单有突刺,滑动窗口精确有开销,令牌桶允许突发,漏桶绝对匀速
  2. 令牌桶怎么实现? Lua 维护令牌数和上次补充时间,按速率补令牌,有令牌才放行。允许突发
  3. 固定窗口的突刺? 窗口交界瞬间:前窗口尾和后窗口头各能放满,双倍流量。滑动窗口解决
  4. 分布式限流怎么做? Redis + Lua 原子计数。注意限流组件本身的可用性,挂了下沉本地限流
  5. 被限流返回什么? 429 Too Many Requests,带 Retry-After。客户端按指示退避重试
Navigation

Type to search…

↑↓ navigate↵ selectEsc close