当前位置: 首页 > news >正文

限流算法详解:固定窗口、滑动窗口、令牌桶与漏桶算法全面对比

限流(Rate Limiting)是保障系统稳定性和服务质量的关键机制,尤其在高并发、突发流量、攻击防护等场景中至关重要。

本文将详细介绍四种主流限流算法:

  • 固定窗口(Fixed Window)

  • 滑动窗口(Sliding Window)

  • 令牌桶(Token Bucket)

  • 漏桶算法(Leaky Bucket)

我们将从原理、实现方式、优缺点和适用场景四个维度进行深入分析和对比。


一、固定窗口(Fixed Window)

原理:将时间划分为固定长度窗口,统计每个窗口内的请求数,超过上限则拒绝。

实现方式(常用 Redis INCR + EXPIRE):

key = f"req:{user_id}:{current_minute}"
count = redis.incr(key)
if count == 1:redis.expire(key, 60)
if count > threshold:reject()

优点

  • 实现简单,性能高。

  • Redis 支持天然适配。

缺点

  • 临界突刺问题:在两个窗口交界点,可能放行两倍请求。

适用场景

  • 精度要求不高的接口。

  • 管控类后台系统。


二、滑动窗口(Sliding Window)

1. 滑动日志(Sliding Log)

原理:记录每次请求时间戳,实时清理超出时间窗口的旧请求,判断窗口内数量。

优点

  • 流量限制更精确。

  • 避免突刺。

缺点

  • 需要维护时间戳列表,内存消耗较大。

2. 滑动窗口计数器(Sliding Window Counter)

原理:将一个窗口拆分为多个小窗口,每个子窗口统计请求数,根据时间加权合并。

优点

  • 性能和精度之间较好平衡。

适用场景

  • 高并发、登录、敏感操作等流控要求较高的业务。


三、令牌桶算法(Token Bucket)

原理

  • 系统以固定速率放入“令牌”到桶中;

  • 每次请求需要“取一个令牌”才能通过;

  • 桶容量有限,超过上限的令牌被丢弃;

  • 若桶为空,请求被限流(或排队等)。

示意图

+----------+
| 令牌桶    |
|          |<-- 固定速率生成令牌
|   [ ]    |
+----------+↓请求来取令牌 -> 成功 or 被限流

优点

  • 支持突发流量(令牌可积累)。

  • 灵活控制平均速率与突发能力。

  • Guava / Nginx 都有成熟实现。

缺点

  • 实现较复杂。

  • 依赖精准时间调度。

适用场景

  • 接口限频,突发高并发业务。

  • LLM API 限流 / OpenAI、Stripe 等系统。


四、漏桶算法(Leaky Bucket)

原理

  • 所有请求先进入一个桶中;

  • 桶以固定速率“漏水”处理请求;

  • 桶满时,新请求要么被丢弃,要么排队等待。

示意图

请求 → 桶(队列) → 以恒定速率处理(漏水)↑桶满则拒绝或排队

实现方式

  • 可以用一个队列存储请求;

  • 后台定期以固定速率出队并处理请求。

优点

  • 平滑处理请求流量,保持处理速率稳定。

  • 防止服务被瞬时流量压垮。

缺点

  • 不支持突发流量(桶中积压,排队延迟)。

  • 实现复杂度略高于令牌桶。

适用场景

  • 网关、负载均衡器的请求调度。

  • 强调处理速率恒定的后台任务系统。


五、算法对比总结

特性固定窗口滑动窗口令牌桶漏桶
实现复杂度⭐(简单)⭐⭐(中等)⭐⭐⭐(中高)⭐⭐(中等)
限流精度中等
是否支持突发请求
是否平滑
是否常用✅(Redis)✅(Sentinel)✅(Guava、Nginx)✅(调度系统)

六、实战建议

  • 简单限流场景(如后台管理):使用 固定窗口 + Redis 即可。

  • 高并发接口限频:推荐 滑动窗口令牌桶,后者更适合突发请求。

  • 需要平滑处理队列任务:选择 漏桶算法


七、结语

限流并不是一刀切的“阻止请求”,而是为系统争取喘息空间。不同的限流算法背后体现的是不同的设计哲学与业务权衡。

选对限流算法,既可以保护系统,又能优化用户体验。

http://www.lryc.cn/news/605214.html

相关文章:

  • 力扣-543.二叉树的直径
  • 【LeetCode】链表反转实现与测试
  • (补题)小塔的饭
  • sqLite 数据库 (3):以编程方式使用 sqLite,4 个函数,以及 sqLite 移植,合并编译
  • linux 执行sh脚本,提示$‘\r‘: command not found
  • C语言:函数指针、二级指针、常量指针常量、野指针
  • 【Kubernetes 指南】基础入门——Kubernetes 201(二)
  • Vite 模块动态导入之Glob导入
  • Cursor MCP搭建入门
  • 力扣热题100---------35.搜索插入为位置
  • jQuery UI Tabs切换功能实例
  • Python在自动化与运维领域的核心角色:工具化、平台化与智能化
  • Jaeger理论、实战、问题记录
  • TikTok 视频审核模型:用逻辑回归找出特殊类型的视频
  • Elasticsearch 文档操作管理:从增删改查到批量操作与数据类型
  • 硬性巩膜镜市场报告:深度解析行业现状与未来趋势
  • Java项目:基于SSM框架实现的济南旅游网站管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
  • 同一雷达不同样式的pdw数据
  • FFmpeg:因码流采集与封装不同步导致录制出来的MP4文件会出现黑屏、绿屏的问题
  • 达梦数据库(DM Database)角色管理详解|了解DM预定义的各种角色,掌握角色创建、角色的分配和回收
  • 实现了加载 正向 碰撞 雅可比 仿真
  • 第十九周-文档数据库MongoDB、消息队列和微服务
  • I Built an Offline-Capable App by Myself: React Native Frontend, C# Backend
  • WebSocket 简介与在 Vue 中的使用指南
  • Python正则表达式精准匹配独立单词技巧
  • ACL 2025 第二弹:维也纳风情舞会点燃学术之夜
  • 论文阅读:《多目标和多目标优化的回顾与评估:方法和算法》
  • Three.js + AI:结合 Stable Diffusion 生成纹理贴图
  • 如何在 Ubuntu 24.04 或 22.04 LTS 上安装 Deepin 终端
  • 微软OpenAI展开深入谈判