什么情况使用redis实现延时队列
相较于使用mq实现延时队列使用redis更加轻量简单,并且redis读写性能更高,所以一些简单的场景很适合使用redis实现延时队列
redis实现延时队列的基本原理
redis的zset数据类型是有序、不可重复的,我们可以将消息关键键(订单id)作为member,消息到期时间作为score存储到zset,能满足消息不重复消费、按时消费、按顺序消费。
往zset塞入消息之后开一个线程监控redis,获取zset中到期的消息的member完成相应业务。
基于springboot实现
队列类
定义了设置消息、删除消息、监听队列完成业务三个方法。
@Component
@Slf4j
public class RedisDelayQueue<T> {
/**
* 延迟队列名称
*/
private String delayQueueName = "delayQueue";
@Autowired
private RedisTemplate redisTemplate;
/**
* 删除消息
* @param msg
* @return
*/
public Boolean deleteDelayTask(T msg){
if (redisTemplate.opsForZSet().remove(delayQueueName, JSONObject.toJSONString(msg)) > 0) {
return true;
}
return false;
}
/**
* 设置延迟消息
*/
public boolean setDelayTasks(T msg, long delayTime) {
Boolean addResult = redisTemplate.opsForZSet().add(delayQueueName, JSONObject.toJSONString(msg), System.currentTimeMillis() + delayTime);
if(addResult) {
log.info("delayQueue添加任务成功!"+JSONObject.toJSONString(msg)+"当前时间为"+ LocalDateTime.now());
return true;
}
return false;
}
/**
* 监听延迟消息
*/
public void listenDelayLoop() {
//每隔一秒去队列中获取过期的消息
while (true) {
// 获取一个到点的消息
Set<String> set = redisTemplate.opsForZSet().rangeByScore(delayQueueName, 0, System.currentTimeMillis(), 0, 1);
// 如果没有,就等等
if (set.isEmpty()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 继续执行
continue;
}
// 获取具体消息的key
String it = set.iterator().next();
// 删除成功
if (redisTemplate.opsForZSet().remove(delayQueueName, it) > 0) {
// 拿到任务member
String bookId = JSONObject.parseObject(it, String.class);
//处理业务
}
}
}
}
监控线程类
用于监控队列的线程
@Component
public class ListenThread extends Thread{
@Autowired
RedisDelayQueue queue;
@Override
public void run(){
queue.listenDelayLoop();
}
}
启动线程
根据需求启动线程监控队列,这里是项目启动就开启监控线程
@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {
@Autowired
ListenThread listenThread;
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("项目启动开启redis延时消息监控线程");
listenThread.start();
}
}
本文介绍了如何在SpringBoot项目中利用Redis的ZSet数据类型创建一个轻量级的延时队列,包括消息设置、删除和定时监听机制。作者详细展示了如何定义队列类和监控线程,以及如何启动监控线程来确保消息的及时处理。





