使用Lpush和Rpop命令来放入和读取消息。
缺点:当List中无数据时候,由于代码中会不断循环读取数据,Rpop命令不会停止,会一直运行,浪费cpu。
改进:
1、设置休眠时间,没隔一段休眠时间再读取。
2、使用BRPOP阻塞式,当有消息来的时候才会读取。
但仍有缺陷:1、不支持多个消费者消费同一条消息,2、消息丢失。当有消费者使用pop命令之后,这条消息就从链表中删除了,其他消费者也无法消费。
使用 SUBSCRIBE queue命令订阅queue这个消息队列,在多个redis客户端使用就能使得多个消费者订阅queue这个消息队列,而且是阻塞式读取。
然后使用PUBLISH queue msg1命令,让生产者在queue队列中生产msg1这条消息,于是订阅了queue这个队列的消费者就能读取到了。
而且还能够实现匹配订阅比如: PSUBSCRIBE queue.*,使用*匹配格式相同的消息队列,
当发布消息PUBLISH queue.p1 msg1,PUBLISH queue.p2 msg2,时候,消费者会收到来自queue.p1和queue.p2这两个消息队列的消息。
优点:多生产者,多消费者
缺点:数据丢失(Pub/Sub没有提供存储消息的机制,只是一个通道)
三种情况会导致数据丢失:1.消费者下线,重新启动后,只能接收最新的消息。
2.Redis宕机,消息会丢失。(不支持持久化)
3.消息积压。消费者有个缓冲区,redis先将消息放置这个缓冲区,然后消费者从缓冲区读取消息。当缓冲区内存不够了,消费者会被强制下线。
通过命令XADD queue * name zhangsan 发布消息,*表示让redis生成一个id【时间戳-自增序列号】
通过XREAD COUNT 5 STREAMS queue 0-0读取消息,
1.可以阻塞式读取,XREAD COUNT 5 BLOCK 0 STREAMS queue 1618469127777-0,会阻塞读取这个id后的消息。
2.支持发布/订阅模式
生产者发布两条消息:
XADD queue * name zhangsan
XADD queue * name lisi
创建两个消费者组来消费,每个消费者组下都有一个消费者,>表示读取最新消息
XREADGROUP GROUP group1 consumer COUNT 5 STREAMS queue >
XREADGROUP GROUP group2 consumer COUNT 5 STREAMS queue >
3.stream能保证消息不丢失
当消费者消费完消息后,消费者会使用这个命令
XACK queue group1 1618472043089-0
表示该条消息已经被消费类,如果消费者宕机,则不会发出这条命令,redis就会将这个消息保存下来。当消费者重新启动后,redis便会将消费者没处理的消息重新发送给消费者。
4.Stream数据会通过RDB和AOF进行数据持久化
5.消息堆积时候,Stream也有应对策略:1.生产者限流。2.丢弃消息,丢弃旧的消息,保留固定长度的新消息。但消息堆积有容量限制。(也会有丢失消息的风险)
总的来说redis消息队列与专业的消息队列(Kafka、RabbitMQ)相比仍有差距;
1.Redis本身可能会丢弃数据(无论是RDB还是AOF策略,都有一定的时间间隔,有可能丢失数据)
2.有消息堆积的风险。(Kafka、RabbitMQ会将数据保存到硬盘上)。