Redis延迟队列实现与Redisson RDelayedQueue
如何使用Redis实现延迟队列?请介绍ZSet实现延迟队列的方案(Score作为执行时间戳),以及Redisson的RDelayedQueue的原理。和RocketMQ的延迟消息相比有什么优缺点?
回答
Yahuda
ZSet实现延迟队列:
// 生产者:添加任务,score为执行时间戳
redisTemplate.opsForZSet().add("delay_queue", taskJson, executeTime);
// 消费者:轮询获取到期的任务
while (true) {
Set<String> tasks = redisTemplate.opsForZSet()
.rangeByScore("delay_queue", 0, System.currentTimeMillis(), 0, 1);
if (tasks != null && !tasks.isEmpty()) {
String task = tasks.iterator().next();
// 原子性移除(避免多个消费者重复消费)
Long removed = redisTemplate.opsForZSet().remove("delay_queue", task);
if (removed > 0) {
// 执行业务逻辑
process(task);
}
}
// 短暂休眠,避免空转
Thread.sleep(100);
}
Redisson RDelayedQueue:
- 封装了上述ZSet实现,提供便捷API
- 使用RQueue作为目标队列,RDelayedQueue监听
- 元素到期时自动从RDelayedQueue转移到目标RQueue
RQueue<String> queue = redisson.getQueue("my_queue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(queue);
delayedQueue.offer("task1", 10, TimeUnit.SECONDS); // 10秒后入队
// 从queue中poll消费
String task = queue.poll();
Redis延迟队列 vs RocketMQ延迟消息:
| 对比 | Redis(ZSet/Redisson) | RocketMQ |
|---|---|---|
| 精度 | 依赖轮询间隔,秒级 | 毫秒级 |
| 可靠性 | 消息可能丢失(宕机) | 持久化,可靠 |
| 延迟等级 | 任意时间 | 固定18个等级(1s/5s/10s/30s/1m...) |
| 海量消息 | 内存限制,容量有限 | 磁盘存储,量大 |
| 实现复杂度 | 简单 | 复杂(需部署RocketMQ集群) |
| 适用场景 | 小规模、轻量需求 | 大规模、高可靠性需求 |
总结:小规模轻量需求用Redis延迟队列(如订单30分钟未支付取消);大规模高可靠用RocketMQ。