分布式限流三种方案详解
一、概述在分布式系统中限流是保障服务稳定性的重要手段。本文详细对比三种基于 Redis 的分布式限流方案固定窗口、滑动窗口、令牌桶帮助你在不同场景下做出合理的技术选型。二、方案一固定窗口Fixed Window2.1 原理将时间划分为固定长度的时间窗口如 1 秒每个窗口独立计数。窗口内计数器累加超过阈值则拦截。时间轴 |--- 第1秒 ---|--- 第2秒 ---|--- 第3秒 ---| ① ② ③ ④ ⑤ ⑥ ① ② ③ ① ② ③ ④ ⑤ ↓ ↓ ↓ 计数6 计数3 计数5 阈值5 阈值5 阈值5 ❌ 拦截2个 ✅ 全部放行 ✅ 全部放行2.2 Redis 实现Lua 脚本localkeyKEYS[1]locallimittonumber(ARGV[1])localttltonumber(ARGV[2])-- 原子性自增localcurrentredis.call(INCR,key)-- 首次访问设置过期时间ifcurrent1thenredis.call(EXPIRE,key,ttl)endreturncurrent2.3 优缺点维度评价实现复杂度⭐ 极低代码简洁性能⭐⭐⭐ 最高单次 Redis 调用内存占用⭐⭐⭐ 最低每个窗口只存一个计数器流量均匀性⭐⭐ 存在边界突发问题2.4 边界突发问题时间线 |---- 第1秒 (阈值10) ----|---- 第2秒 (阈值10) ----| 请求 第9、10个在 999ms 到达 第1、2个在 1001ms 到达 结果在 2ms 内通过了 12 个请求超了 10 的限制2.5 适用场景场景是否适用说明API 防刷✅ 推荐正常用户不会卡时间边界边界问题可接受登录限流✅ 推荐防暴力破解简单高效IP 限流✅ 推荐最常见的防刷场景严格流量整形❌ 不推荐边界突发不符合要求秒杀/抢购⚠️ 慎用边界突发可能导致不公平2.6 代码示例ComponentpublicclassFixedWindowRateLimiter{privatestaticfinalStringLUA_SCRIPTlocal current redis.call(INCR, KEYS[1])\nif current 1 then\n redis.call(EXPIRE, KEYS[1], ARGV[2])\nend\nreturn current;publicbooleanallow(Stringkey,intlimit,intwindowSeconds){LongcountredisTemplate.execute(newDefaultRedisScript(LUA_SCRIPT,Long.class),Collections.singletonList(key),String.valueOf(limit),String.valueOf(windowSeconds));returncount!nullcountlimit;}}三、方案二滑动窗口Sliding Window3.1 原理使用 Redis 的Sorted SetZSET存储每个请求的时间戳通过移除窗口外的旧数据精确统计窗口内的请求数。时间轴 |---- 过去1秒 ----|现在 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ↓ ↓ ZSET 存储所有请求时间戳 ZREMRANGEBYSCORE 移除窗口外数据 ZCARD 统计窗口内数量3.2 Redis 实现Lua 脚本localkeyKEYS[1]localnowtonumber(ARGV[1])localwindowtonumber(ARGV[2])-- 窗口大小毫秒locallimittonumber(ARGV[3])-- 移除窗口外的旧数据redis.call(ZREMRANGEBYSCORE,key,0,now-window)-- 获取当前窗口内的请求数localcountredis.call(ZCARD,key)ifcountlimitthenreturncount-- 拦截end-- 添加当前请求使用毫秒时间戳 随机数作为 member避免重复redis.call(ZADD,key,now,now..:..math.random())-- 设置过期时间窗口 1 秒redis.call(PEXPIRE,key,window1000)return0-- 放行3.3 优缺点维度评价实现复杂度⭐⭐ 中等需要理解 ZSET 操作性能⭐⭐ 较高ZREMRANGEBYSCORE ZCARD ZADD内存占用⭐⭐ 较高每个请求存一条记录流量均匀性⭐⭐⭐ 最精确无边界问题3.4 滑动窗口精度示意固定窗口边界突发 第1秒 第2秒 |██████████| |██████████| 9 10 1 2 ← 2ms 内通过 12 个 滑动窗口精确控制 |◄─── 1秒 ───►|◄─── 1秒 ───►| 请求均匀分布任意 1 秒窗口内 ≤ 阈值3.5 适用场景场景是否适用说明严格 QPS 控制✅ 推荐需要精确控制每秒请求数金融交易限流✅ 推荐对流量均匀性要求高API 网关精确限流✅ 推荐用户感知要求高防刷场景⚠️ 可用但固定窗口更简单性价比更高高并发场景⚠️ 慎用内存占用随请求量线性增长3.6 代码示例ComponentpublicclassSlidingWindowRateLimiter{privatestaticfinalStringLUA_SCRIPTlocal window tonumber(ARGV[2])\nlocal now tonumber(ARGV[1])\nlocal limit tonumber(ARGV[3])\nredis.call(ZREMRANGEBYSCORE, KEYS[1], 0, now - window)\nlocal count redis.call(ZCARD, KEYS[1])\nif count limit then return count end\nredis.call(ZADD, KEYS[1], now, now .. : .. math.random())\nredis.call(PEXPIRE, KEYS[1], window 1000)\nreturn 0;publicbooleanallow(Stringkey,intlimit,intwindowMs){longnowSystem.currentTimeMillis();LongcountredisTemplate.execute(newDefaultRedisScript(LUA_SCRIPT,Long.class),Collections.singletonList(key),String.valueOf(now),String.valueOf(windowMs),String.valueOf(limit));returncount!nullcount0;}}四、方案三令牌桶Token Bucket4.1 原理系统以固定速率向桶中放入令牌每个请求需要消耗一个令牌。桶有容量上限允许一定程度的突发流量。┌─────────────────────┐ │ 令牌桶 (容量 20) │ │ │ │ │ │ │ └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ 固定速率填充 │ │ 10 令牌/秒 │ └─────────────────────┘4.2 Redis 实现Lua 脚本localkeyKEYS[1]locallimittonumber(ARGV[1])-- 桶容量localratetonumber(ARGV[2])-- 填充速率令牌/秒localnowtonumber(ARGV[3])-- 获取桶状态localstateredis.call(HMGET,key,tokens,last_time)localtokenstonumber(state[1])orlimitlocallastTimetonumber(state[2])ornow-- 计算应该补充的令牌数localdeltamath.max(0,now-lastTime)localfilledTokensmath.min(limit,tokens(delta*rate/1000))-- 判断是否有足够令牌iffilledTokens1then-- 消耗 1 个令牌localnewTokensfilledTokens-1redis.call(HMSET,key,tokens,newTokens,last_time,now)redis.call(EXPIRE,key,10)return1-- 放行else-- 更新状态不消耗redis.call(HMSET,key,tokens,filledTokens,last_time,now)redis.call(EXPIRE,key,10)return0-- 拦截end4.3 优缺点维度评价实现复杂度⭐⭐⭐ 最高需要维护桶状态性能⭐⭐ 较高HMGET HMSET 多次操作内存占用⭐⭐⭐ 低仅存两个字段流量均匀性⭐⭐⭐ 最平滑允许可控突发4.4 突发流量处理对比固定窗口 请求数 ▲ 20│ ████████ (瞬间突发被拦截) 10│ ████████ └─────────────────► 时间 令牌桶 请求数 ▲ 20│ ████████ (突发被平滑) 10│ ████████ └─────────────────► 时间4.5 适用场景场景是否适用说明秒杀/抢购✅ 推荐允许初期突发平滑后续流量消息队列消费✅ 推荐控制消费速率平滑处理第三方 API 调用✅ 推荐严格遵守对方限流规则网关流量整形⚠️ 可用功能强大但实现复杂收益不高简单防刷❌ 过度设计固定窗口足够没必要上令牌桶4.6 代码示例ComponentpublicclassTokenBucketRateLimiter{privatestaticfinalStringLUA_SCRIPTlocal limit tonumber(ARGV[1])\nlocal rate tonumber(ARGV[2])\nlocal now tonumber(ARGV[3])\nlocal state redis.call(HMGET, KEYS[1], tokens, last_time)\nlocal tokens tonumber(state[1]) or limit\nlocal lastTime tonumber(state[2]) or now\nlocal delta math.max(0, now - lastTime)\nlocal filled math.min(limit, tokens (delta * rate / 1000))\nif filled 1 then\n redis.call(HMSET, KEYS[1], tokens, filled - 1, last_time, now)\n redis.call(EXPIRE, KEYS[1], 10)\n return 1\nend\nredis.call(HMSET, KEYS[1], tokens, filled, last_time, now)\nreturn 0;publicbooleanallow(Stringkey,intcapacity,intratePerSecond){longnowSystem.currentTimeMillis();LongresultredisTemplate.execute(newDefaultRedisScript(LUA_SCRIPT,Long.class),Collections.singletonList(key),String.valueOf(capacity),String.valueOf(ratePerSecond),String.valueOf(now));returnresult!nullresult1;}}五、三种方案全景对比维度固定窗口滑动窗口令牌桶实现复杂度⭐ 低⭐⭐ 中⭐⭐⭐ 高性能 (Redis调用)1 次3 次2 次内存占用⭐⭐⭐ 低 (1个Key)⭐⭐ 中 (N个成员)⭐⭐⭐ 低 (2个字段)流量均匀性⭐⭐ 边界突发⭐⭐⭐ 最精确⭐⭐⭐ 最平滑允许突发❌ 突发即拦截❌ 突发即拦截✅ 可控突发时间精度秒级毫秒级毫秒级Key 过期处理自动过期自动过期需设置 TTL适用场景防刷、限流精确控制流量整形性能基准测试参考值方案单次请求耗时每秒处理能力固定窗口~0.5ms20000滑动窗口~1.2ms8000令牌桶~1.0ms10000六、选型决策树开始 │ ▼ 是否需要严格均匀的流量分布 │ ├── 是 ──► 是否允许突发流量 │ │ │ ├── 是 ──► 令牌桶 │ │ │ └── 否 ──► 滑动窗口 │ └── 否 ──► 是否需要毫秒级精度 │ ├── 是 ──► 滑动窗口 │ └── 否 ──► 固定窗口 ✅ 最推荐七、场景化推荐业务场景推荐方案理由API 防刷固定窗口简单、高效、够用IP 限流固定窗口最常见场景性价比最高登录暴力破解防护固定窗口3-5次/秒固定窗口足够秒杀/抢购令牌桶允许初期突发平滑后续消息队列消费令牌桶控制消费速率第三方 API 调用令牌桶遵守对方限流规则金融交易限流滑动窗口精确控制无边界问题严格 QPS 保证滑动窗口任意时刻都不超限网关通用限流固定窗口性能最优运维简单八、总结一句话选型大部分场景选固定窗口需要精确控制选滑动窗口需要流量整形选令牌桶。最终建议优先级方案说明首选固定窗口覆盖 80% 场景简单可靠按需滑动窗口对精度有严格要求时使用慎用令牌桶功能强大但实现复杂非必要不用记住过度设计是最大的敌人。先用最简单的方案解决问题等真正遇到瓶颈再升级。

相关新闻

Atmosphere大气层系统架构深度解析与实战部署指南

Atmosphere大气层系统架构深度解析与实战部署指南

Atmosphere大气层系统架构深度解析与实战部署指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable Atmosphere大气层系统是Nintendo Switch平台上最先进的开源自制固件解决方案,…

2026/10/19 5:38:07 阅读更多 →
财税公司如何把客单价从几千提升到几万?关键在进入企业治理业务

财税公司如何把客单价从几千提升到几万?关键在进入企业治理业务

财税公司提升客单价的核心,不是增加更多基础服务项目,而是从财务事务执行转向企业治理价值解决方案。几千元服务解决的是记账、申报等标准化需求,几万元服务解决的是企业主对风险控制、股权安排、财富延续和长期经营的复杂需求。问题&#xf…

2026/10/13 6:05:09 阅读更多 →
5分钟极速汉化GitHub Desktop:开源本地化工具完全指南

5分钟极速汉化GitHub Desktop:开源本地化工具完全指南

5分钟极速汉化GitHub Desktop:开源本地化工具完全指南 【免费下载链接】GitHubDesktop2Chinese GithubDesktop语言本地化(汉化)工具 【GitHub桌面客户端中文汉化】 项目地址: https://gitcode.com/gh_mirrors/gi/GitHubDesktop2Chinese 你是否曾因GitHub Des…

2026/10/18 17:12:28 阅读更多 →

最新新闻

开源真实世界数据集AGIBOT WORLD 2026:具身智能数据瓶颈与解法解析

开源真实世界数据集AGIBOT WORLD 2026:具身智能数据瓶颈与解法解析

如果问当前具身智能领域最缺什么,很多一线研发者会不约而同回答两个字:数据。语言模型和视觉模型这些年吃掉了海量互联网文本和图片,收益肉眼可见;但机器人操作模型完全不是这个玩法,它依赖的是机械臂在真实任务中记录…

2026/10/19 5:39:26 阅读更多 →
纯Python手写CNN:230行跑通MNIST,前向反向全透明

纯Python手写CNN:230行跑通MNIST,前向反向全透明

简介:本资源是一份面向深度学习初学者与原理探究者的纯Python卷积神经网络(CNN)实现方案,不依赖TensorFlow、PyTorch等框架,聚焦底层计算逻辑与反向传播机制的理解。适合高校学生、转行学习者及希望夯实CNN数学基础的开…

2026/10/19 5:39:26 阅读更多 →
大模型显存占用全解析:从训练到推理的算账指南

大模型显存占用全解析:从训练到推理的算账指南

跑大模型训练的人,多多少少都经历过这样的瞬间:显卡显存监控明明还剩二三十GB,任务却突然弹出一行“CUDA out of memory”;推理服务昨晚还好好的,今天并发一上来,就开始批量拒绝请求。很多人第一反应是“加…

2026/10/19 5:39:26 阅读更多 →
C# DocX库实战:免Office生成编辑Word并转PDF

C# DocX库实战:免Office生成编辑Word并转PDF

简介:面向.NET开发者的C#DocX资源包,随附源码、动态库与可直接运行的Demo工程,用于在不依赖Microsoft Office环境的前提下完成Word文档的创建、编辑、读取、内容替换以及PDF转换,能够支持自动化报告生成、在线文档编辑器、数据导出…

2026/10/19 5:39:26 阅读更多 →
MySQL 5.7定时任务实战:用事件调度器自动清理表记录

MySQL 5.7定时任务实战:用事件调度器自动清理表记录

很多做开发和运维的朋友都遇到过这类需求:业务跑着跑着,某张表的体积肉眼可见地往上涨,查了一下发现全是日志数据、临时缓存或者历史流水,留着碍事,删了又怕以后要查。尤其是 MySQL 5.7 环境里,表动不动几个…

2026/10/19 5:39:26 阅读更多 →
MCP协议深度解析:从设计思路到实战落地,智能体工具集成不再难

MCP协议深度解析:从设计思路到实战落地,智能体工具集成不再难

1. 为什么这一讲值得单独拿出来精讲MCP,全称 Model Context Protocol,是近两年在智能体工程圈子里被反复讨论的一个协议规范。如果你正在做 AI 应用开发,尤其是涉及工具调用、多智能体协作、外部数据源接入这类场景,那 MCP 基本是…

2026/10/19 5:38:26 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →