消息队列笔记

消息队列笔记

​ 本文部分图片摘自极客课程:消息队列高手课;部分概念摘自维基百科。


消息队列的概念

​ 任何技术的出现都是为了解决某个问题,消息队列是为了解决应用之间通信的需求,但是又不仅仅是这个需求。

​ 那么消息队列是什么,有什么作用呢?

​ 举个例子来说,就比如现在网购这么发达,最开始的快递行业是送货上门,你有个快递,快递小哥就会送到你家门口。但是问题来了,家里不一定有人啊。快递小哥就会直接把快递放在家门口,然后给你发个短信——xxx单号的快递放你家门口了,记得签收一下。如果没什么意外你下班回到家拿到快递,诶你很高兴。但是如果出现意外,比如说被偷走了,你就很生气,就会去投诉快递小哥。快递小哥也很委屈啊,我也不能蹲你家门口一直等你回来把快递给你我再走啊,那我剩下那一大堆快递可怎么整啊!那有什么地方可以存放快递,解放快递小哥的同时又保证快递不会丢呢——快递柜出现了。快递小哥把快递放到你楼下的快递柜,那么快递柜做了什么呢?一般去快递柜寄过快递的都知道啊:首先快递小哥会登陆,然后输入要存放的快递订单号,收件人电话,然后快递小哥就把快递放进去,在他关上快递柜门的同时,快递柜就会给你发个短信通知你:你的快递已经放到了快递柜,你下班记得来取一下!这样你什么时候有空就什么时候去取,快递小哥可以继续送他剩下的快递,你也可以安心的上你的班逛你的街,两边都很开心。那如果正好是双十一啊,你买了N多快递,这也没问题啊,快递小哥会按照快递送达的顺序,给你放到快递柜,你到时候按照去取就好啦。

​ 快递柜就好比消息队列,你的快递就好比是消息,你就好比是消费者。一个快递柜就实现了快递小哥跟你的解耦。

​ 消息队列也是一样,它可以实现两个应用之间的解耦——从名字上看,是用来发送消息的,存放消息的数据结构是队队列,也就是先放进去的会先被取出来。那么我们从名字上可以看出消息队列第一个功能:存放消息,并且保证消息严格有序。第二个功能:异步。

消息队列模型

好的架构不是设计出来的,而是演进出来的。 现代的消息队列呈现出的模式,一样是经过之前的十几年逐步演进而来的。

队列模型

​ 早期的消息队列,确实是按照队列这种数据结构设计的。在维基百科中,队列是这样定义的:

队列是先进先出(FIFO, First-In-First-Out)的线性表(Linear List)。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为 rear)进行插入操作,在前端(称为 front)进行删除操作。

在这里插入图片描述

​ 这有个显著的缺点:

​ 如果有多个消费者消费队列中的数据,这些消费者其实是竞争的关系。我把消息消费掉了,你就不能再消费了。除非生产者事先知道有N个消费者要消费,然后同样的数据往队列中放N份。

​ 那显然生产者跟消费者并没有解耦啊。为了解决这个问题,演化出了另一种消息模型:

发布订阅模型

在这里插入图片描述

​ 在发布 - 订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。发布者将消息发送到主题中,订阅者在接收消息之前需要先“订阅主题”。“订阅”在这里既是一个动作,同时还可以认为是主题在消费时的一个逻辑副本,每份订阅中,订阅者都可以接收到主题的所有消息。

​ 你会发现,发布订阅模型跟队列模型的区别就在于订阅者将自己需要订阅哪些数据这个信息交给消息队列去管理,生产者依旧是把数据发送给消息队列,然后订阅者告诉消息队列,我需要订阅哪些数据,由消息队列去给订阅者发送这些数据;而不是订阅者告诉生产者,我需要订阅xxx数据,你把这些数据往消息队列上发送N份。实际上就是把队列模型中,负责处理订阅者订阅数据的这个功能转交给消息队列去负责,从而实现了发布者与订阅者的解耦。

​ 而事实上,可以认为发布订阅模型在功能层面上是兼容队列模型的。而大部分消息队列都使用发布订阅模型,当然也有少数:RabbitMQ。

消息队列的消息模型实现

RabbitMQ的消息模型

​ RabbitMQ的消息模型是队列模型,它采用Exchange 模块去解决多个消费者的问题:

在这里插入图片描述

​ 在 RabbitMQ 中,Exchange 位于生产者和队列之间,生产者并不关心将消息发送给哪个队列,而是将消息发送给 Exchange,由 Exchange 上配置的策略来决定将消息投递到哪些队列中。同一份消息如果需要被多个消费者来消费,需要配置 Exchange 将消息发送到多个队列,每个队列中都存放一份完整的消息数据,可以为一个消费者提供消费服务。这也可以变相地实现新发布 - 订阅模型中,“一份消息数据可以被多个订阅者来多次消费”这样的功能。

RocketMQ的消息模型

​ RocketMQ的消息模型是标准的发布-订阅模型。同时,RocketMQ中也有队列的概念。

在这里插入图片描述

​ RocketMQ中,订阅者的概念是通过消费组(Consumer Group)来体现的。每个消费组都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,一条消息被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。

​ 消费组中包含多个消费者,同一个组内的消费者是竞争消费的关系,每个消费者负责消费组内的一部分消息。如果一条消息被消费者 Consumer1 消费了,那同组的其他消费者就不会再收到这条消息。

​ 在 Topic 的消费过程中,由于消息需要被不同的组进行多次消费,所以消费完的消息并不会立即被删除,这就需要 RocketMQ 为每个消费组在每个队列上维护一个消费位置(Consumer Offset),这个位置之前的消息都被消费过,之后的消息都没有被消费过,每成功消费一条消息,消费位置就加一。这个消费位置是非常重要的概念,我们在使用消息队列的时候,丢消息的原因大多是由于消费位置处理不当导致的。

消息队列的消费机制

​ 几乎所有的消息队列产品都使用一种非常朴素的“请求 - 确认”机制,确保消息不会在传递过程中由于网络或服务器故障丢失。具体的做法也非常简单。在生产端,生产者先将消息发送给服务端,也就是 Broker,服务端在收到消息并将消息写入主题或者队列中后,会给生产者发送确认的响应。

​ 如果生产者没有收到服务端的确认或者收到失败的响应,则会重新发送消息&#x

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值