秒级窗口滑动窗口请求限流算法理解与实现疑问
问题根源
你当前使用的是固定窗口加权近似的滑动窗口实现,存在精度缺陷:核心假设是「前一个窗口内的请求均匀分布」,但实际请求集中在前序窗口的末尾,导致加权计算结果完全失真。
你案例中请求#1发生在34.321,到请求#3的35.451已经间隔1.13秒,符合1秒间隔的要求,但你的算法默认前序34秒窗口有55%的请求落在当前滑动窗口范围内,误算出1.55 RPS的结果,本质是粗粒度整秒窗口的设计误差。
正确实现方案
方案1:精确滑动窗口(滑动日志)
适合阈值低、精度要求高的场景,实现逻辑最简单:
- 存储所有最近1秒内的放行请求时间戳,不需要固定窗口计数
- 新请求到达时,先删除所有早于
当前时间 - 1秒的历史时间戳 - 统计剩余时间戳的数量:
- 数量小于阈值(此处为1):放行请求,将当前时间戳加入存储
- 数量大于等于阈值:拒绝请求
你的案例计算逻辑:
请求#3到达时间为35.451,计算窗口左边界为34.451,34.321早于左边界被清除,剩余请求数为0,直接放行,完全符合预期。
方案2:分块滑动窗口(细粒度拆分)
适合高QPS场景,不需要存储全量请求,性能更高:
- 将1秒的大窗口拆分为N个等大小的小窗口(通常拆分10~100个,比如10个100ms的小窗口,粒度越细精度越高)
- 每个小窗口独立存储计数和窗口起始时间
- 新请求到达时,先定位到当前所属的小窗口更新计数,再删除所有起始时间早于
当前时间 - 1秒的小窗口 - 统计剩余所有小窗口的计数总和:
- 总和小于阈值:放行
- 总和大于等于阈值:拒绝
你的案例如果拆分为10个100ms小窗口:
请求#1落在[34.300, 34.400)的小窗口,计数为1;请求#3到达时,所有早于34.451的小窗口都会被清除,[34.300, 34.400)窗口不在统计范围内,总计数为0,直接放行。
选型建议
如果你的业务限流阈值很低(比如1~100 QPS),直接用滑动日志实现即可,没有精度误差;如果是高QPS场景,拆分10个以上的小窗口即可满足绝大多数业务的精度要求。
内容的提问来源于stack exchange,提问作者hardhypochondria
相关产品推荐
相关产品推荐

