如何实现Redis ZSet滑动窗口限流_通过ZREMRANGEBYSCORE清理过期数据

胖墨同学_1770

胖墨同学_1770

2026-06-17

715人浏览

原创

zremrangebyscore单独使用会出错,因其不保证原子性,需用lua脚本封装zremrangebyscore+zcard+zadd实现滑动窗口限流,否则并发下必然出现超限放行、统计失真等问题。

如何实现redis zset滑动窗口限流_通过zremrangebyscore清理过期数据

为什么ZREMRANGEBYSCORE单独用会出错

ZREMRANGEBYSCORE本身不保证限流逻辑的原子性。你先删旧数据、再ZCARD统计、最后ZADD新请求,这三步之间存在时间窗口:并发请求可能在清理后、统计前插入,导致ZCARD漏数;也可能在统计后、ZADD前被其他客户端抢先写入,造成超限放行。生产环境里这类竞态不是“可能”,而是“必然发生”。

常见错误现象包括:监控看到QPS偶尔冲高超标、同一IP短时内被反复放过、压测时限流阈值形同虚设。

  • 别把ZREMRANGEBYSCORE当限流主干逻辑,它只是辅助清理动作
  • 清理范围必须严格匹配窗口定义:比如60秒窗口,ZREMRANGEBYSCORE key 0 (now-60000) 中的 (now-60000) 要加括号表示开区间,否则边界请求会被误删
  • score 单位统一用毫秒(time.Now().UnixMilli()),避免秒级精度下多个请求撞同一score,导致ZCARD统计失真

必须用Lua脚本封装ZREMRANGEBYSCORE+ZCARD+ZADD

Redis执行Lua脚本是原子的,整个脚本内所有命令按顺序串行执行,中间不会被其他客户端打断。这才是滑动窗口能落地的前提。

典型脚本结构(保存为sliding_window.lua):

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window_ms = tonumber(ARGV[2])
local max_count = tonumber(ARGV[3])
local req_id = ARGV[4]
<p>redis.call('ZREMRANGEBYSCORE', key, 0, now - window_ms)
local count = redis.call('ZCARD', key)</p><p>if count </p>
  • KEYS[1] 是限流key(如 "rate:login:192.168.1.100"),必须由调用方传入,不能硬编码
  • ARGV[4] 是请求唯一标识,不能为空;若漏传,ZADD 不报错但写入失败,脚本仍返回1,等于直接绕过限流
  • EXPIRE 时间设为窗口时长+30秒,是兜底策略——防止因网络抖动导致ZREMRANGEBYSCORE没执行完就断连,残留key长期占用内存

ZSet内存暴涨的两个隐藏原因

高频服务下,ZSet成员数增长远超预期,不是因为脚本写得不对,而是两个常被忽略的设计点:

  • ZSet不会自动压缩:哪怕窗口只保留最近1秒数据,每毫秒一个请求,1秒就是1000个member;ZSet底层是跳表+哈希表双结构,每个member至少占几十字节,万级/秒请求一天就能吃掉GB级内存
  • 没设TTL或TTL太长:仅靠ZREMRANGEBYSCORE清理不够,网络分区或客户端崩溃会导致部分key永远不被访问,EXPIRE必须写进Lua,且不能依赖外部定时任务补救
  • score用毫秒但业务允许秒级精度?改用秒级时间戳(time.Now().Unix())+ HINCRBY分桶,内存可降两个数量级——滑动窗口越“滑”,代价越高

Go/Python调用时参数类型最容易踩的坑

go-redis和redis-py对Lua参数的类型映射有隐式规则,传错类型会导致脚本静默失败:

  • Go中time.Now().UnixMilli()返回int64,传给Lua的ARGV[1]会被自动转为number,没问题;但若传string("1716734280000"),tonumber()会返回nil,后续所有redis.call都失败
  • Python里用redis.eval(script, 1, key, now, window_ms, max_count, req_id),注意now必须是int,不能是float或str
  • 脚本返回值是0或1,但go-redis默认解析为interface{},需显式断言:result.(int64) == 1,否则类型错误panic

真正难的不是写对ZREMRANGEBYSCORE,而是让每一次调用都在正确的时间、以正确的类型、触发正确的原子路径——漏掉任意一环,滑动窗口就从闸门变成筛子。

相关专题

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

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

2023.11.02

4309

19

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

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

2023.11.14

3815

11

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

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

2024.04.02

6932

6

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

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

2024.04.07

623

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

736

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

6582

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1140

6

redis的8种数据类型有哪些
redis的8种数据类型有哪些

redis 提供 8 种数据类型:字符串(文本、数字、二进制)、哈希(键值对)、列表(有序集合)、集合(无序唯一元素)、有序集合(按分数排序)、地理空间(地理位置)、hyperloglog(估计大数据基数)和位图(位序列存储)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1016

6

redis主要作用有哪些
redis主要作用有哪些

redis 的主要作用包括:1. 缓存数据,提高访问速度;2. 充当消息队列,实现消息传递;3. 存储各种数据类型,如字符串、散列和集合;4. 管理会话信息,确保可靠性和可用性;5. 限制请求速率,防止服务器超载等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

5838

6

热门下载

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

精品课程

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

共0课时 | 0人学习