Redis用SortedSet实现延时任务调度,核心是将执行时间设为score、任务标识设为member,通过ZADD入队、ZRANGEBYSCORE取到期任务并ZREM删除,配合定时扫描或监听预取优化执行,失败时重新ZADD兜底。

Redis 用 SortedSet 实现延时任务调度,核心是把“什么时候执行”变成分数(score),把“执行什么”变成成员(member),靠 Redis 自带的有序性自动排队,再配合定时轮询或监听机制触发执行。
SortedSet 结构怎么设
每个任务存成一条 ZSET 记录:
-
member:任务唯一标识,比如
task:1001,或者序列化后的任务数据(如 JSON 字符串) -
score:任务的绝对执行时间戳(单位秒),例如
time() + 300表示 5 分钟后执行 -
key:统一队列名,比如
delay_queue
这样所有任务按执行时间自然升序排列,最早该执行的在最前面。
任务怎么入队
用 ZADD 命令插入,确保不覆盖已有同名任务(可选 NX 参数):
- PHP(Predis):
$client->zadd('delay_queue', ['task:123' => time() + 60]) - Java(Jedis):
jedis.zadd("delay_queue", System.currentTimeMillis()/1000 + 60, "task:123") - 命令行:
ZADD delay_queue 1722956040 "task:123"(对应 2026-08-06 15:34:00)
怎么取出到期任务
用 ZRANGEBYSCORE 查所有 score ≤ 当前时间戳的任务:
- 查最多 100 条:
ZRANGEBYSCORE delay_queue 0 (current_timestamp) WITHSCORES LIMIT 0 100 - 查完立刻用
ZREM删除已取任务,避免重复消费 - 建议加锁或用 Lua 脚本保证「查询 + 删除」原子性,防止多个消费者取到同一任务
怎么高效执行与兜底
不能靠被动轮询等太久,推荐两种落地方式:
- 定时扫描 + 批量处理:每 1–5 秒查一次到期任务,适合中低频场景
-
监听 + 预取优化:先用
ZRANGE delay_queue 0 0 WITHSCORES拿最早任务的 score,算出距现在还有多久,休眠对应时间后再查——减少空转 -
失败重试兜底:任务执行失败时,重新
ZADD回队列,score 设为当前时间 + 重试延迟(如 60 秒)


















