限流
限流约束进入系统的速率或并发。本文负责算法、配额与分布式执行。
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 对齐窗口结束,避免每次请求延长窗口。故障转移后的状态完整性还需另行保证。