Redis中如何实现延迟队列?

Redis 可以通过以下方式实现延迟队列:

  1. 使用有序集合sorted set并根据分数排序实现:
  • 将消息发布时间作为元素的分数,消息内容作为元素的成员。
  • 每次取出分数最小的元素,即最早发布的消息。
  • 通过 ZREM 命令删除已取出元素,实现消息的非阻塞取出。

例如:

Jedis jedis = new Jedis("localhost");

// 发布消息,当前时间戳作为分数
jedis.zadd("delay_queue", System.currentTimeMillis(), "message1");

// 阻塞等待2秒后获取最早的消息
String message = jedis.zrangeByScore("delay_queue", 0, System.currentTimeMillis()-2000, 0, 1).get(0);
jedis.zrem("delay_queue", message);   // 删除已取出消息
  1. 使用有序集合实现并通过pexpire为其设置过期时间:
  • 每次取出过期时间最短,且已过期的元素,实现延迟效果。
  • 同时通过脚本定期重新设置过期时间,防止元素被永久移除。

例如:

// 发布消息,设置5秒后过期 
jedis.zadd("delay_queue", 0, "message1"); 
jedis.pexpire("delay_queue", 5000);  

// 定期重置过期时间的脚本 
String script = "if redis.call('exists', KEYS[1]) == 1 then redis.call('pexpire', KEYS[1], 5000) end";
jedis.eval(script, Collections.singletonList("delay_queue"), Collections.emptyList());

// 等待消息过期后取出 
String message = jedis.zrangeByScore("delay_queue", 0, 0, 0, 1).get(0);
jedis.zrem("delay_queue", message);  // 删除已取出消息