Appearance
Redis 延迟队列怎么做更合适
先说结论
- Redis 可以做延迟队列,但更适合轻量、可补偿、可靠性要求没那么极端的场景
- 一般更常见的做法是
zset + score=执行时间 - 真正要考虑的重点不是“能不能延迟”,而是到点后怎么拉、怎么防重复、怎么补偿失败
一、Redis 延迟队列到底适合什么
更适合的场景通常是:
- 订单超时关闭
- 短信重试
- 优惠券到期处理
- 轻量异步提醒
这类任务的共同点通常是:
- 量不算离谱
- 允许秒级误差
- 有补偿空间
- 消费失败可以重试或人工兜底
如果你要做的是高可靠业务消息、严格投递确认、复杂消费组协作,那 Redis 往往不是第一选择。
二、最常见的实现方式
最常用的是 zset:
- key 存队列名
- member 存任务标识
- score 存执行时间戳
消费者逻辑通常是:
- 扫描当前时间之前的元素。
- 抢到后删除或标记处理中。
- 执行业务逻辑。
它的优点是简单直观,适合快速落地。
三、真正难的不是存进去,而是消费出来
很多人把重点都放在“延迟”本身,但线上真正容易出问题的是后半段:
1. 到点后谁来扫
是单实例扫、定时任务扫,还是多实例竞争消费。
2. 怎么避免重复执行
多实例并发拉取时,如果没有原子抢占,很容易重复消费。
3. 消费失败怎么办
任务被取出来后失败了,要不要重试、怎么回队、怎么避免无限重试。
四、什么时候不太建议继续用 Redis
下面这些场景更值得考虑专业 MQ:
- 延迟任务量特别大
- 消费链路很复杂
- 需要强投递语义
- 需要清晰的重试、死信、确认机制
Redis 做轻量延迟任务很顺手,但要把它硬扛成完整消息系统,后面维护成本会很高。
五、最容易踩的坑
1. 只扫,不抢占
多个实例同时扫描到同一批到期任务,很容易重复执行。
2. 消费后直接删,没有失败补偿
一旦业务执行中途失败,任务就丢了。
3. 把大对象直接塞进延迟队列
更稳的做法通常是只放任务 ID,再回业务库或缓存查详细内容。
总结
Redis 延迟队列更像“轻量延迟任务工具”,不是通用高可靠消息中间件。zset 方案足够常用,但真正要设计好的,是抢占、重试和补偿这三件事。只要你的场景还属于轻量可补偿型,用 Redis 做会很顺手。