如何基于Redis实现延时任务?
延迟任务要同时满足「到时触发」与「至少一次执行」。Redis 提供多种轻量实现,但可靠性与精确度不同。
方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| ZSet | score=执行时间 | 简单 | 单点需抢任务 |
| Keyspace 过期 | 过期事件通知 | 省结构 | 不保证触发、易丢 |
| Redisson DelayQueue | 内部队列 | 封装好 | 依赖组件 |
| Stream | 定时扫描+消费组 | 可 ACK | 需调度器 |
1 | ZADD delay:tasks 1735689600000 "order:1001" |
实践建议
执行端幂等;任务状态机落 DB;多实例用 Lua/Redlock 抢任务;监控 pending 堆积。
与 MQ 分工
短延迟、量不大用 Redis;长延迟、堆积、审计要求用 RocketMQ 定时/延迟消息。
时钟依赖
多机 NTP 同步;延迟队列比较的是 Redis 所在机器时间。
实践复习清单
ZSet 延迟队列 Lua 原子;幂等消费;pending 监控;NTP 同步;与 MQ 边界;Redisson 方案评估。
常见坑
- 只靠 key 过期事件做金融级延迟扣款。
- ZSet 轮询无分布式锁导致重复执行。
- 时间戳单位混用秒与毫秒。
总结与自测
ZSet 延迟队列步骤;过期通知为何不可靠;幂等必须;与 MQ 边界。延迟任务要先定义「允许重复执行吗」。
原理延伸
Redis 的工程价值在于用内存数据结构换取极低延迟,但单线程命令执行模型决定了任何 O(N) 大 key 操作都会放大为全局延迟。持久化、主从复制与 Cluster 分片分别解决数据安全、读扩展与写扩展,没有银弹。使用 Redis 时要先定义数据丢失窗口与一致性 SLA,再选 RDB/AOF 组合;缓存层必须设计穿透、击穿、雪崩与双写不一致的预案。监控应覆盖内存、碎片率、连接数、blocked clients、repl lag 与 slowlog,而不是只看 QPS。
一句话带走
把本文要点写进你的排查 checklist,下次遇到类似问题先对照机制再动手,比临时搜索命令高效得多。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Dai Wei!
评论

