一)消息队列:从字面意思上来看是存储消息的队列,最简单的消息队列包含三个元素:
1)消息队列:存储和管理消息,也被称之为是消息代理
2)生产者:发送消息到消息队列
3)消费者:从消息队列中获取消息并处理消息
4)当有用户想要进行秒杀下单的时候,先要进行判断是否具有购买的资格,如果这个用户具有购买的资格,不是着急下单,而是把优惠卷信息和用户ID发送到消息队列里面
5)这个时候我们在开启一个独立的线程,我们再来创建一个消费者,不断地从消息队列中来进行获取消息,来进行接收消息并下单;
1)首先消息队列是在JVM以外的独立服务,是不受JVM内存的限制
2)消息队列不光进行数据存储,还进行数据安全问题,存入到消息队列中的所有消息要去做持久化,无论是服务宕机还是重启数据都不会丢失
3)而且消息队列中的数据投递给消费者之后,要求消费者做消息的确认,如果这个消息没有被确认,那么这个消息仍然被投递给消费者,让他继续处理,知道确保消息至少被消费一次
一)基于List结构来进行模拟消息队列
1)Redis中的list结构就是一个双向链表,是很容易模拟出队列的效果的
2)队列是当入口和出口不在同一边,因此我们可以利用lpush结合rpop,或者rpush结合lpop来进行实现,不过需要进行注意的是当队列中没有rpop或者是lpop的时候会返回null,并不会像JVM的阻塞队列那样并等待消息,因此此时我们应该使用bropop或者是blpop来实现阻塞效果
优点:
1)使用redis进行存储,是不受JVM内存上限的
2)基于redis的持久化机制,数据安全性是具有保障的
3)可以满足消息的有序性
缺点:
1)无法避免消息丢失的问题,假设说我从消息队列里面取出了一条消息,此时如果还没来得及处理这些消息服务器就挂掉了或者出现异常了,那么这条消息就丢失了(因为Blpop是直接将消息从队列中删除了)
2)只能支持但消费者,是无法支持一个消息被多个消费者消费的情况
二)基于PubSub实现的消息队列:
PubSub消息订阅是Redis2.0版本引入的全新的消息传递模型,顾名思义就是说消费者可以进行订阅一个或者多个PubSub,生产者向对应的channel发送信息之后,所有的订阅者是都可以收到相关的消息的
1)subscribe channel:订阅一个频道或者是多个频道,不同的消费者可以订阅相同的频道也是可以订阅不同的频道
2)publish channel msg:向一个频道发送一条信息
3)psubscribe pattern:订阅的是和pattern格式相匹配的所有频道,?代表一个字符,*是代表0个或者多个;
1)xadd users * name jack age 18
创建一个名字是users的队列,并向这个消息队列中发送一个消息,消息是
{name=jack,age=18},这个消息队列ID是由redis自动生成的
2)xlen users获取消息队列中消息的数量
3)xread读取消息队列中的信息
1)xread count 1 streams users 0
表示从users这个消息队列中读取从0号下标开始数量是1的消息
2)xread count 1 streams users *
3)xread count 1 block 0 streams users $,其中block要是0的话表示一直进行阻塞
在业务开发当中,我们可以循环的进行调用xread阻塞方式来进行查询最新消息,从而来实现持续监听队列的效果,永远进行监听消息
当我们进行指定起始ID是$的时候,代表读取最新的消息,但是如果我们进行处理一条消息的过程中发现又有超过1条以上的消息到达队列,那么下一次进行获取的时候也会读取最新的一条,也会出现消息漏读的问题
xread命令的特点:
1)消息是可以回溯的,也就是消息读取完毕之后永远不会消失,永久地保存在我们的队列中,随时想看随时可以回去看
2)一个消息可以被多个消费者读取
3)消息可以阻塞读取,可以写while(true)循环,一直读取
4)消息漏读的问题