← 返回题目列表

固定窗口、滑动窗口和滑动日志限流有什么区别?

高频 中等 第 2 / 26 题 更新于 2026/07/28
固定窗口滑动窗口滑动日志限流算法

简化版

固定窗口按固定时间段计数,实现简单但有边界突刺问题;滑动窗口把时间切成多个小格,统计最近一段时间内的请求,更平滑;滑动日志记录每次请求时间戳,最精确但存储和清理成本最高。

详细版

三种算法对比:

算法原理优点缺点
固定窗口每个固定周期内最多 N 次简单、高性能窗口边界可能放过 2N 突刺
滑动窗口计数把窗口切成多个小时间片滚动统计比固定窗口平滑,成本可控精度取决于时间片粒度
滑动日志记录每次请求时间戳,统计最近窗口精确存储、清理和并发成本高

固定窗口适合简单限流,滑动窗口适合多数在线接口,滑动日志适合额度较小、精度要求高的场景。分布式实现时通常依赖 Redis 计数器、ZSet、Lua 脚本或网关限流组件。

完整版教学

一、固定窗口为什么会有边界突刺

固定窗口把时间切成固定周期,比如每分钟最多 100 次。实现很简单:当前分钟计数小于 100 就放行,超过就拒绝。问题出在窗口边界。

假设用户在 12:00:59 发了 100 个请求,在 12:01:00 又发了 100 个请求。按固定窗口看,每分钟都没有超过 100;但从 12:00:59 到 12:01:00 这一秒内,系统实际承接了 200 个请求。这就是边界突刺。

如果下游只能承受平稳的 100/min,固定窗口会在边界处放过过量请求。所以固定窗口适合简单、低成本、对边界突刺不敏感的场景。

二、滑动窗口计数如何缓解突刺

滑动窗口计数把一个大窗口拆成多个小格。比如 1 分钟窗口拆成 6 个 10 秒小格,每次请求只统计最近 6 个小格的总数。时间不断向前滑动,旧格子过期,新格子加入。

这样比固定窗口更接近“最近 60 秒”的真实请求量。小格越细,越平滑,精度越高;但小格越多,存储和计算成本也越高。

滑动窗口计数是工程里很常见的折中方案。它不像滑动日志那么精确,但性能更好;比固定窗口更平滑,边界突刺更小。

三、滑动日志为什么最精确

滑动日志会记录每次请求的时间戳。请求到来时,删除窗口外的旧时间戳,统计剩余数量,如果数量小于阈值就放行并记录当前时间,否则拒绝。

例如限制 60 秒内最多 100 次,那么每次都看最近 60 秒真实发生了多少请求。它没有固定窗口的边界问题,精度最高。

但代价也明显。每个限流 key 都要保存多个时间戳,高流量下内存和清理成本很高。Redis 里常用 ZSet 实现滑动日志,score 是时间戳,成员是请求唯一值。每次请求要删除旧数据、计数、插入新数据,操作成本高于简单计数器。

四、Redis 中常见实现方式

固定窗口通常用 INCR + EXPIRE。第一次请求创建 key 并设置过期时间,后续请求递增计数。要注意 INCREXPIRE 最好原子化,否则设置过期失败可能留下永久 key。可以用 Lua 脚本保证原子性。

滑动窗口计数可以用多个时间片 key,比如 rate:user:123:202607241830,再累加最近几个时间片。也可以用一个 Hash 保存各时间片计数。实现时要清理旧时间片,避免 key 膨胀。

滑动日志可用 ZSet:先 ZREMRANGEBYSCORE 删除窗口外记录,再 ZCARD 判断数量,再 ZADD 当前请求。多个命令要用 Lua 包起来,保证并发下不会超放。

五、算法精度和系统成本要平衡

很多场景不需要绝对精确。比如普通接口每分钟 1000 次,偶尔多放几个请求影响不大,滑动窗口计数足够。对于短信验证码、登录失败次数、支付风控这类风险敏感场景,滑动日志或更严格的计数更合适。

还要考虑限流 key 的数量。按用户限流可能有百万级 key;按 IP、接口、租户组合限流,key 数更多。算法越精确,存储和 CPU 成本越高。限流系统本身不能成为瓶颈。

工程上常用分层策略:入口粗粒度限流用低成本算法,安全敏感点用高精度算法,核心资源保护再加并发数和熔断。

六、窗口算法容易忽略时间一致性

分布式限流依赖时间窗口时,要注意多节点时钟不一致。如果每个应用节点本地计数,本机时间差会影响窗口边界。使用 Redis 统一计数时,最好使用 Redis 服务器时间或统一时间源,减少客户端时钟漂移影响。

窗口过期也要谨慎。固定窗口 key 的 TTL 如果每次请求都刷新,会从固定窗口变成另一种滑动效果;如果只首次设置 TTL,要确保异常情况下 key 不会永久存在。小细节会改变算法语义。

七、面试追问里的答题层次

面试官问窗口算法时,先讲定义,再讲边界突刺和精度成本。高分答案会补上实现细节:固定窗口用计数器但要原子设置过期;滑动窗口用时间片折中;滑动日志用 ZSet 精确但成本高;分布式场景要用 Lua 保证原子性。

如果问“为什么不用最精确的滑动日志”,答案是成本。高 QPS、大量限流 key 下,保存每个请求时间戳会占用大量内存和 CPU,清理旧日志也有开销。限流算法要够用,而不是盲目追求最精确。

八、常见误区与追问

这道题要紧扣「固定窗口与滑动窗口」本身回答,不能把它混成泛泛的流量控制套话。面试官通常不是只听定义,而是看你能不能把适用场景、关键流程、失败边界和工程取舍串起来,尤其要说明限流位置、算法窗口、阈值来源、拒绝策略、退避降级和观测指标。

回答层次要讲清的内容容易漏掉的边界
核心结论固定窗口实现简单但有边界突刺,滑动窗口统计更平滑但成本更高不要停在名词解释
流程机制请求到达 -> 计算所属时间窗口 -> 更新计数或桶 -> 判断是否超阈值 -> 返回放行或限流 -> 清理过期窗口要说清触发点、状态变化、确认点和失败兜底
工程取舍固定窗口限制每分钟 100 次,用户可在 00:59 发 100 次、01:00 再发 100 次,2 秒内实际通过 200 次限流保护系统稳定性,但会牺牲一部分请求成功率或响应实时性
固定窗口与滑动窗口 面试拆解:
1. 请求到达
2. 计算所属时间窗口
3. 更新计数或桶
4. 判断是否超阈值
5. 返回放行或限流
6. 清理过期窗口

记忆钩子:先给结论,再拆流程,再讲数字例子和失败边界;回答「固定窗口与滑动窗口」时要围绕题目问法收束,不要把相邻概念堆成一段没有重点的名词清单。

  • 误区:限流就是简单拒绝请求。 合格答案要区分放行、排队、快速失败、降级、退避和熔断,而不是只说“挡住流量”。
  • 误区:全局平均流量低就没有风险。 热点 key、单实例、单下游资源仍可能先被打满,所以要看局部水位。
  • 误区:限流阈值可以拍脑袋配置。 阈值要来自压测容量、依赖水位、错误率、P99 延迟和业务优先级。
  • 追问:限流应该放在哪里? 入口网关、服务内部、客户端和下游资源侧可以分层配置,分别保护不同边界。
  • 追问:触发限流后怎么处理? 核心写请求可排队,非核心读请求可降级,用户侧要给明确失败或稍后重试。
  • 追问:如何验证流控策略有效? 看 QPS、并发、延迟、拒绝率、队列长度、下游错误率和恢复时间。

九、加强记忆

固定窗口最简单但怕边界突刺;滑动窗口计数把时间切小格,精度和成本折中;滑动日志逐条记录请求,最精确但最贵。选算法时看限流精度、QPS、key 数量、实现成本和误放风险。