Hi,大家好,我是抢老婆酸奶的小肥仔。
最近在使用redis时,就想能不能用其实现消息队列?也在网上看了下其他小伙伴写的实现,结合自身业务实现了如下消息队列,希望对大家有用。
废话不多说,直接开撸。
1、为什么zset可以做消息队列?
首先我们来看下,设计消息队列需要考虑的需求:有序性,消息重复性,可靠性。
- 有序性:zset所有元素可以根据成员关联的score来进行从低到高的排序,例如,我们可以利用时间戳来进行排序
- 消息重复性:在zset中每个元素都是唯一的,这也保证了消息的唯一性
- 可靠性:zset会自动维护元素之间的顺序,在添加或删除元素时无需手动排序,提升操作速度。
2、使用的zset命令
命令 | 描述 |
---|---|
zadd | 将一个给定score的成员添加到有序集合中,返回添加元素的个数 |
zrange | 根据元素在有序排序中的位置,从有序集合中获取多个元素 |
rank(K key, Object o) | 获取指定元素在集合中的索引,索引从0开始 |
3、代码实现
使用zset实现消息队列时,具体的流程,如下:
生产者流程:
- 用户获取消息Id,并封装消息体
- 用户发送数据到生产者,先获取锁
- 如果获取到锁,则校验该消息体是否已添加到队列中,已添加则直接返回提醒。
- 若未添加则调用方法将数据保存到zset集合中,否则等到指定时间后再获取锁。
- 推送数据后,释放锁
消费者流程:
- 调用方法获取数据
- 获取到数据,则直接返回,否则到指定时间后再次获取数据,直到获取到数据并返回。
统一返回类:
/**
* @Author: jiangjs
* @Description:
* @Date: 2021/11/12 15:46
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResultUtil<T> implements Serializable {
private int code;
private String msg;
private T data;
public static <T> ResultUtil<T> success(){
return ResultUtil.<T>builder().code(1000).msg("成功").build();
}
public static <T> ResultUtil<T> success(T data){
return ResultUtil.<T>builder().code(1000).msg("成功").data(data).build();
}
public static <T> ResultUtil<T> error(String msg){
return ResultUtil.<T>builder().code(5000).msg(msg).data(null).build();
}
public static <T> ResultUtil<T> error(int code,String msg){
return ResultUtil.<T>builder