问题
问题:为什么需要使用消息队列?
问题:消息队列一般是如何起作用的?
答:可以理解为原先调用方发起调用并阻塞等待被调用发返回消息。如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/bdc2cf97f749b1325a4f550e2bab78e5.png)
现在是调用方把调用的数据封装成消息放到队列中,同时一般调用方不会阻塞而是继续进行接下来的业务。之后中间队列会将消息发送给被调用方或者被调用方主动从中间队列中获取消息执行业务操作。(注:使用消息队列后,我们一般称调用方为生产者,是生产消息的;被调用方成为消费者,是消费信息的;调用数据被封装成了一个消息)。如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/fd25cae03a924072f6e494c910887838.png)
可以看到,消息队列的使用是对原先业务的重构,所以消息队列的使用首先需要对原先的业务进行解耦,之后才能使用消息队列完成架构优化,而不是消息队列的使用完成了原先业务的解耦。消息队列只是业务解耦最常用的实现手段。
问题:消息队列是如何保证高可用的?
答:集群化是任何组件实现高可用的现有的唯一方式。但消息队列的集群化后回出现一些新的问题,核心就是如何保证信息被唯一处理,包括以下几个问题:
如何保证生产者生产的消息在集群中只保存了一份?
消息传递到集群后,如何保证储存了不止一份?
为保证消息不在集群中丢失,如何在集群中的各节点实现消息的持久化?
如果消费者也是集群,在消息从中间件和消费者之间传递的过程中如何保证只消费一次?
问题:如何保证消息在生产者和消息队列之间传递的效率?
答:这里效率的评判标准是一定量的消息全部发送所耗费的时间。
问题:如何保证消息在生产者和消息队列之间传递的安全,也就是不丢失?
答:这里涉及到几个问题,比如:
生产者生产的消息是否需要持久化?
消息的在发送前一定是放到一个缓存中的,问题是什么时候完成消息删除?
如果放消息的缓存满了,生产者新生产的消息该怎么做?
问题:如何平衡消息在生产者和队列之间传递的效率与保证在高可用情况下各节点的一致性之前的矛盾?
答:这里主要是这个问题:消息队列高可用性的需要保证消息在集群中储存多份,那么就会遇到集群是何时通知生产者已接到消息可以在本地删除。是在完成一个实例的持久化后,还是一个实例都没有完成持久化就可以通知,还是完成了全部实例的持久化后才可以通知生产者已接到可删除。
这里的矛盾点主要在持久化可能耗费的时间与可能造成的生产者阻塞,如果等所有实例都持久化完成会造成大量的时间浪费,如果不等持久化就直接返回可能会造成信息的丢失。
问题:消息从队列中是如何传递到消费者一侧的?
答:从队列到消费者有两种模式,推模式和拉模式。
推模式就是队列主动将消息推给消费者。
好处是能保证消息处理的及时性,配合恰当的架构可以将时间控制在微秒级。若没有消息,不要消费者一直探测队列是否有消息浪费资源。
坏处是不能一定保护消费者,在消费者能力达到极限的时候还会给消费者传输消息可能导致消费者奔溃。
拉模式就是消费者主动从队列中拉消息。
好处是可以控制消费消息的频率,保证消费者不会奔溃。
坏处就是需要不断的向队列发送探询消息,确定是否有新消息。
问题:如果消费者是集群,如何保证消息不被重复消费?
答:常用方式是为消息传递构建一个通道。有两种实现方式:
其一是保证一个通道只对接一个消费者,所以当生产者将消息发送到该通道后,只有对接该通道的消费者可以消费保证一次消费。
其二是一个通道可以对接多个消费者,但消息的发送需要轮询,一个只发送一次。