如何利用Redis ZSet滑动窗口算法实现API接口精准限流

小丽君_7315

小丽君_7315

2026-09-16

922人浏览

原创

如何利用redis zset滑动窗口算法实现api接口精准限流

直接用 ZADD + ZREMRANGEBYSCORE + ZCARD 三步就能实现,但必须用 Lua 脚本原子执行,否则并发下计数会漂移——这是最常被忽略的致命点。

为什么单条命令组合不行?

限流本质是「先删旧、再查数、最后加新」三个动作。如果拆成三次 Redis 请求:

  • 两个并发请求同时执行 ZCARD,都读到 99,都判断“还能进”
  • 接着都执行 ZADD,结果变成 101 —— 超限了却没拦住
  • 更糟的是,ZREMRANGEBYSCORE 如果放在 ZCARD 之后,可能刚删完旧数据,另一个请求就插进来写入,导致窗口统计错位

必须用 Lua 脚本保证原子性

把整个逻辑封装进一个 Lua 脚本,由 Redis 串行执行。例如限流 key 为 limit:ip:{ip},60 秒窗口、100 次上限:

local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])  -- 60
local max = tonumber(ARGV[3])     -- 100
<p>-- 删除窗口外数据
redis.call('ZREMRANGEBYSCORE', key, 0, now - window <em> 1000)
-- 计数
local count = redis.call('ZCARD', key)
-- 如果未超限,添加当前时间戳(用毫秒避免重复)
if count  2)  -- 过期设为窗口两倍,防冷 key 残留
end
return count </em></p><p>调用时传入:<code>KEYS = ["limit:ip:192.168.1.1"]</code>,<code>ARGV = ["1725513420123", "60", "100"]</code></p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2199" title="Redis 8.2.3"><img
														src="https://img.php.cn/upload/manual/001/589/237/69f31fe50f56d421.png" alt="Redis 8.2.3" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/xiazai/gongju/2199" title="Redis 8.2.3" class="overflowclass">Redis 8.2.3</a>
													<p class="overflowclass">Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。</p>
												</div>
												<a rel="nofollow" href="/xiazai/gongju/2199" title="Redis 8.2.3" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div><h3>IP 维度 key 设计与内存控制</h3><p>key 必须带 IP,但不能裸用 <code>limit:ip:{ip}</code> —— IPv6 地址含冒号,Redis key 不支持;且公网 IP 可能被 NAT 共享,需结合 User-Agent 或 token 做二次区分:</p>
  • 推荐 key 格式:limit:ip_v4:<code>sha256(ip),或对 IPv6 做规范化(如压缩+base32)
  • EXPIRE 时间建议设为 window * 2,不是 window:避免刚过期就新请求进来,触发重建开销
  • 不手动 DEL 空 key:ZCARD 返回 0 后,key 自然随过期消失,无需额外清理

精度取舍:用秒级还是毫秒级 score?

score 用秒还是毫秒,取决于你的容忍误差和存储压力:

  • 用秒(time()):每秒最多存 1 个 member,内存省,但同一秒内第 101 次请求会被误拒
  • 用毫秒(System.currentTimeMillis()):精度高,但极端场景(如压测)可能在 1ms 内涌入大量请求,member 数暴涨
  • 折中方案:score 用毫秒,member 用 requestIdip:ts:rand,避免 score 相同导致覆盖

真正难的不是写对脚本,而是确认业务能否接受「窗口内统计延迟 100ms」或「冷 key 多占 2 分钟内存」——这些细节不提前对齐,上线后就会卡在监控告警里反复调参。

大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

3028

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

4189

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3649

9

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

2026.01.19

366

15

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

2023.08.14

4576

4

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

3989

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

3495

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

6152

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

583

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习