跳到主要内容
约 4 分钟3 张卡

限流

限流约束进入系统的速率或并发。本文负责算法、配额与分布式执行。

1. 面试核心​

先记住这几条,再读正文
  • 固定窗口。 固定窗口在相邻边界允许接近两倍阈值的短突发。
  • 滑动窗口。 滑动日志精确计数,滑动计数器用较少状态近似窗口。
  • 漏桶与令牌桶。 排队式漏桶平滑输出,令牌桶允许桶容量内的突发。卡 · 固定窗口
  • 速率与并发。 稳定系统中,平均在途数等于吞吐率乘平均逗留时间。卡 · 并发限制
  • 分布式额度。 分布式配额需要原子扣减,本地保护需独立于中心服务。卡 · 原子扣减与失效

2. 固定窗口​

固定窗口按秒或分钟计数,达到上限就拒绝。实现简单,但边界处存在突发。

例如每秒上限 100 次。前一秒末尾通过 100 次,后一秒开头再通过 100 次。很短的跨窗口区间就能通过接近 200 次。

它适合粗粒度配额。需要平滑保护时,应选择其他算法或叠加并发上限。

3. 滑动窗口​

滑动日志保存最近窗口内的请求时间。它能精确计数,状态随请求量增长。

滑动计数器分格保存计数。整格累计与边界加权是不同的近似方式。加权估算依赖边界格内流量分布,仍会有误差。

格子变细能降低时间粒度误差,也会增加状态成本。

4. 漏桶​

本文讨论排队整形式漏桶。请求进入有界队列,处理方按固定速率取出。队列满时拒绝。

该方式平滑输出,但增加等待。队列需同时设置长度和最大等待时间。漏桶也有计量判定式实现,未必实际排队。

5. 令牌桶​

令牌按速率 r 补充,容量 B 限制积累上限。请求消耗令牌后立即通过,无令牌时等待或拒绝。

初始满桶时,时间 t 内最多放行约 B + r × t 个单位。B 决定短突发,r 决定长期速率。

昂贵请求可消耗多个令牌。额度单位需与 CPU、查询量等保护对象对应。

6. 并发限制​

并发限制直接约束正在处理和排队的工作。稳定系统中,Little's Law 写为 L = λ × W。L 是平均在途数,λ 是平均吞吐率,W 是平均逗留时间。

例如吞吐 1000 次/秒,平均耗时 20 ms,则 L 为 20。耗时变为 2 s 且吞吐保持时,L 增为 2000。

计算需使用相同边界下的平均值。P99 不适合直接代入这个等式。估算值再结合突发、资源上限与压测确定额度。

7. 限流键​

限流键按可信主体、租户或 API 划分。共享 IP 会误伤同网用户,伪造 header 会绕过配额。

入口全局上限与租户配额共同使用。高成本接口单独计量。每个实例仍设置本地并发与队列上限。

键状态需限制数量和保留时间,防止低频键无限增长。

8. 分布式限流​

共享计数器便于执行全局配额,但增加远程依赖。节点本地额度可降低延迟,但需协调总量。

严格预分配时,中心只发放未占用额度。安全回收和避免重复发放可保持总上限。异步统计后再纠偏的方案则会产生短时超额。

中心故障时,接口按风险选择拒绝或保守本地额度。本地并发上限始终独立生效。

9. 限流响应​

调用方超额可返回 429,并附 Retry-After。整体服务临时过载也可用 503 表达。接口契约需说明是否建议再次尝试。

等待时间超出剩余预算时,直接拒绝。排队式削峰仍要保持队列有界。

10. 原子扣减与失效​

读取额度、判断和扣减必须原子执行。独立 GET 与 SET 会让并发请求同时通过。

Redis Lua 可把检查、计数和过期设置放在同一次执行。脚本保持短小,避免长时间阻塞 Redis。

固定窗口的 TTL 应覆盖窗口结束。若每次请求都续成完整 TTL,窗口边界会被不断推迟。故障转移和状态丢失还需单独评估,原子执行只解决并发竞态。

11. 常见问题​

11.1 令牌桶与漏桶​

排队式漏桶强调平滑输出。令牌桶强调受控突发与长期速率。后端可承受突发、请求难以等待时,令牌桶更合适。

11.2 QPS 与线程池饱和​

12 · 面试题卡片​

12.1 固定窗口、滑动窗口、漏桶和令牌桶如何选择​

出现公司:字节跳动、阿里巴巴、滴滴

考察重点

  • 理解窗口边界、状态成本、平滑输出与突发额度。
  • 理解速率限制和并发限制的差异。
  • 理解全局配额、本地保护与失败策略。

相关内容:固定窗口至限流响应。

参考回答

固定窗口适合粗配额,滑动日志适合精确窗口计数。

滑动计数器用较少状态换取近似结果。排队式漏桶平滑输出,令牌桶允许受控突发。

保护资源时,还需独立设置并发与队列上限。分布式额度要权衡精度、协调成本和故障行为。租户配额保护公平,本地额度保护单实例。

12.2 1000 QPS 的接口变慢后,怎样估算在途请求数量?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:平均值、系统边界与并发容量。

相关内容:并发限制。

参考回答

在稳定系统中,用 L = λ × W 估算平均在途数。

1000 次/秒乘 20 ms 得到 20。平均耗时升到 2 s,保持吞吐时得到 2000。实际限额还需考虑突发、资源成本与压测结果。

12.3 Redis 实现限流时,为什么检查额度和扣减要一起执行?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:并发竞态、Lua 原子性与 TTL。

相关内容:原子扣减与失效。

参考回答

原子检查与扣减能防止多个请求消费同一剩余额度。

Redis Lua 可同时完成判断、计数和过期设置。固定窗口 TTL 对齐窗口结束,避免每次请求延长窗口。故障转移后的状态完整性还需另行保证。

13. 参考资料​