【Redis 开发】Redis消息队列

消息队列

博主前面讲过各个消息队列的基础入门,那么处于成本考虑,Redis中也提供了三种不同的方式来实现消息队列:

  1. List结构:基于list结构模型模拟消息队列
  2. PubSub:基本的点对点消息模型
  3. Stream:比较完善的消息队列模型

基于list结构模型模拟消息队列

Redis的list模型是一个双向链表,很容易模拟出队列效果
我们可以通过LPUSH结合RPOP,或者RPUSH结合LPOP来实现
但是队列中没有消息的话会返回null,并不像JVM的阻塞队列那样会阻塞并等待消息
因此这里应该使用BRPOP或者BLPOP来实现阻塞效果

优点:

  1. 利用Redis存储,不限于JVM内存上限
  2. 基于Redis的持久化机制,数据安全性有保证
  3. 可以满足消息有序性

缺点:

  1. 无法避免消息丢失
  2. 只支持单消费者(同一条消息无法被多个消费者消费)

基于PubSub的消息队列

PubSub(发布订阅),消费者可以订阅一个或多个channel,生产者向对应channel发送消息后,所有的订阅者都能够收到相关信息
SUBSCRIBE channel [channel]:订阅一个或多个频道
PUBLISH channel msg:向一个频道发送消息
PSUBSCRIBE pattern[pattern]:订阅与pattern格式匹配的所有频道

优点:

采用发布订阅模型,支持多生产,多消费

缺点:

  1. 不支持数据持久化
  2. 无法避免消息丢失
  3. 消息堆积有上限,超出时数据丢失

基于stream的消息队列

Stream是Redis 5.0 引入的一种新数据模型,可以实现一个功能非常完善的消息队列
XADD:发送消息的命令
在这里插入图片描述
XREAD:读取消息的命令
在这里插入图片描述
读取最新消息的命令:
XREAD COUNT 1 BLOCK 1000 STREAMS users $
在java代码中我们可以持续监听队列中最新的消息

while(true)
{
   Object msg = redis.execute("XREAD COUNT 1 BLOCK 1000 STREAMS users $");
   if(msg==null){
      continue;
   }
   //处理消息
   handleMessage(msg);
}

但是这种方式存在弊端,当我们指定ID为$的时候,如果我们在执行handleMessage操作时一下传过来四五条消息,这时就会出现漏读的情况,针对这个我们采用一下方案

基于Stream的消息队列-消费者组

将多个消费者划分到一个组当中,监听同一个队列
特点:

  1. 消息分流:队列中的消息会分流给组内的不同消费者,而不是重复消费,从而加快消息处理的速度
  2. 消息提示:消费者组会维护一个标示,记录最后一个被处理的消息,哪怕是消息者宕机重启,还会从标示之后读取消息,确保每一个消息都会被消费
    消费者组会将所有信息已经消费但未确认的消息放在pending-list中

创建消费者组:XGROUP CREATE key groupName ID [MKSTREAM]
key:队列名称
groupName消费者组名称
ID起始ID标示,$代表队列的最后一个消息,0则代表队列中的第一个消息
MKSTREAM队列不存在的时候自动创建队列

其他常见命令
在这里插入图片描述
从消费者组读取消息:
在这里插入图片描述
group:消费者组名称
consumer:消费者名称,如果消费者不存在,会自动创建一个消费者
count:本次查询的最大数量
NOACK:无需手动ACK,获取消息后自动确认
STRWAMS key:指定队列名称
ID: >:从下一个未消费的消息开始
其它:根据指定的id从pending-list中获取已消费但未确认的消息,例如0,是从pending-list中的第一个消息开始

XACK 队列名 消费者组名 ID名称:确认消息以完成
如何查看pending中的消息:
XPENDING 队列名 组名 - + 10:标示从开头到结尾读10个

基于Stream消费者监听消息的基本思路:

while(true){
   // 尝试监听队列,使用阻塞模式,最长等待2000毫秒
   Object msg= redis.call("XREADGROUP GROUP g1 c1 COUNT 1 BLOCK 2000 STREAMS s1 >");
   if(msg == null){
     continue;
   }
   try{
     //处理消息,完成后一定要ACK
     handleMessage(msg);
   }catch(Exception e){
      while(true){
          Object msg=redis.call("XREADGROUP GROUP g1 c1 COUNT 1 STREAM s1 0");
          if(msg==null){
           break;
          }
         try{
            //说明有异常消息,再次处理
            handleMessage(msg);
         }catch(Exception e){
           //再次出现异常,记录日志,继续循环
           continue;
         }
      }
   }
}

采用消费者组的特点:

  1. 消息可回溯
  2. 可以多消费者争抢消息,加快消费速度
  3. 可以阻塞读取
  4. 没有消息漏读的风险
  5. 有消息确认机制,保证消息至少被消费一次

在这里插入图片描述

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值