Redis ZSet如何实现延时任务队列_利用ZSET分值作为时间戳排序

云磊君_8070

云磊君_8070

2026-06-11

646人浏览

原创

直接用毫秒时间戳作zset的score会导致浮点精度丢失和并发重复投递;应将时间戳左移10位并添加自增序列号,兼顾精度、顺序与安全性。

redis zset如何实现延时任务队列_利用zset分值作为时间戳排序

为什么不用 ZSet 的 score 做延时任务调度会出问题

Redis 的 ZSET 确实天然适合做延时队列:把执行时间戳作为 score,任务内容作为 member,用 ZRANGEBYSCORE 就能查出所有到期任务。但直接这么用容易翻车——score 是 double 类型,精度只有 52 位有效位,当时间戳用毫秒(如 1717023456789)时,超过约 2^52 ≈ 4.5e15(即时间戳大于 2255-06-01)后,相邻整数无法被精确表示,导致 ZRANGEBYSCORE 0 1717023456789 漏掉部分任务。

更现实的问题是并发消费:多个 worker 同时 ZRANGEBYSCORE + ZREM,没有原子性,必然重复投递。

必须用 EVAL 或 lua 脚本封装“查+删”逻辑,且 score 设计要预留精度余量。

如何设计 score 避免浮点精度丢失

核心是不直接存毫秒时间戳。推荐两种方案:

  • 用秒级时间戳 + 微秒低 6 位拼接成整数,例如 1717023456.789123 → 1717023456789123,再转为 string 再转 double 存入 —— 但 Redis 不支持 string score,这条路走不通
  • 更可靠的做法:用毫秒时间戳左移 10 位(相当于乘以 1024),再加一个自增序列号(0–1023)作为低位,保证同一毫秒内多个任务顺序可区分,且整体值仍在 2^52 安全范围内(当前时间戳 × 1024

示例:任务计划在 1717023456789 毫秒执行,当前已插入 3 个同毫秒任务,则 score = 1717023456789 = <code>1758221999749123。这样既保序,又规避了 double 对大整数的截断。

用 Lua 脚本原子获取并删除到期任务

这是最关键的一步。不能分两步:ZRANGEBYSCORE 后再 ZREM,中间可能被其他 client 修改。

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

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

下载

以下脚本从 delayed:queue 中取出最多 n 个 score ≤ now 的任务,并返回它们:

eval "local ms = tonumber(ARGV[1]) local n = tonumber(ARGV[2]) local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', ms, 'LIMIT', 0, n) if #tasks > 0 then redis.call('ZREM', KEYS[1], unpack(tasks)) end return tasks" 1 delayed:queue 1717023456789 10

注意点:

  • ARGV[1] 必须传入数字类型(不是字符串),否则 tonumber() 返回 nil,比较失败
  • unpack(tasks) 在 Redis 7.0+ 已废弃,若用新版需改用 table.unpack(tasks)
  • 如果任务内容本身含空格或特殊字符,ZRANGEBYSCORE 返回的是原始 member 字符串,无需额外 decode

怎么处理执行失败的任务重入队列

延时队列必须支持失败回滚。常见错误是:任务取出后执行失败,直接丢弃或仅 log,导致消息丢失。

正确做法是定义一个重试策略,比如最大重试 3 次,每次延迟翻倍:

  • 消费端拿到任务后,先解析出原始 payload 和 retry_count(可编码在 member 里,如 "{\"id\":\"abc\",\"retry\":2}")
  • 执行失败时,计算下次执行时间戳:now + (2^retry_count * 1000),然后 ZADD delayed:queue <next_score><payload></payload></next_score>
  • 避免无限重试:在 payload 中记录初始入队时间,超时(如 24h)则投递到死信队列 dlq:delayed

特别注意:重入队列时 score 必须用新计算的时间戳,且仍要套用前面说的“时间戳 × 1024 + seq”编码方式,否则可能因精度问题错序。

实际部署时,score 编码、Lua 原子操作、失败重入这三环缺一不可。最容易被忽略的是 score 的整数编码——很多人图省事直接塞毫秒时间戳,上线跑几个月没事,某天突然发现定时任务批量漏触发,排查半天才想到 double 精度问题。

相关专题

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

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

2023.11.02

4289

19

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

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

2023.11.14

3795

11

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

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

2024.04.02

6872

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

6482

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

5778

6

热门下载

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

精品课程

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

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习