当遇到并发的客户端请求时,为了缓解服务端的处理压力,当请求对响应的处理的实时性要求不高时,可以实现一个异步的请求消息队列。
一种实现策略是使用redis的zset,将消息的到期处理时间作为score,然后用多个线程去轮训获取zset中的任务并进行处理。
需要提前考虑一个问题:
如何避免一个任务被多次处理?
一种解决方案是当多个线程获取到任务时,调用redis的zrem命令,将该任务从指定的zset中移除(利用了redis处理命令时是顺序执行的)。
环境
- JDK17
- 两个jar包
- Jedis
- fastjson2
代码
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import redis.clients.jedis.Jedis;
import java.lang.reflect.Type;
import java.util.List;
import java.util.UUID;
// 基于Redis实现的延迟队列
public class RedisDelayingQueue<T> {
static class TaskItem<T> {
public String id;
public T msg;
}
// fastjson序列化对象时如果存在泛型,需要使用TypeReference
private Type TaskType = new TypeReference<TaskItem<T>>(){
}.getType();
private Jedis jedis;
private String queueKey;
public RedisDelayingQueue(Jedis jedis, String queueKey) {
this.jedis = jedis;
this.queueKey = queueKey;
}
// 将任务添加到 zset 中
// 分数是延时的时间
public void delay(T msg) {
TaskItem<T> task = new TaskItem<T>();
task.id = UUID.randomUUID(