1.RabbitMQ的消息发送流程
生产者往交换机中发送消息;
交换机通过规则绑定队列,通过路由键将消息存储到队列中;
消费者获取队列中的消息进行消费;
2.RabbitMQ如何保证消息发送不丢失
RabbitMQ提供了publisher confirm机制来避免消息发送到MQ过程中丢失。这种机制必须给每个消息指定一个唯一ID。消息发送到MQ以后,会返回一个结果给发送者,表示消息是否处理成功。
返回结果有两种方式:
-
publisher-confirm,发送者确认
-
消息成功投递到交换机,返回ack
-
消息未投递到交换机,返回nack
-
-
publisher-return,发送者回执
-
消息投递到交换机了,但是没有路由到队列。返回ACK,及路由失败原因。
-
3.RabbitMQ如何保证消息存储不丢失
生产者确认可以确保消息投递到RabbitMQ的队列中,但是消息发送到RabbitMQ以后,如果突然宕机,也可能导致消息丢失。
要想确保消息在RabbitMQ中安全保存,必须开启消息持久化机制。
-
交换机持久化
-
队列持久化
-
消息持久化
交换机持久化
RabbitMQ中交换机默认是非持久化的,mq重启后就丢失。
SpringAMQP中可以通过代码指定交换机持久化:
@Bean
public DirectExchange simpleExchange(){
// 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除
return new DirectExchange("simple.direct", true, false);
}
事实上,默认情况下,由SpringAMQP声明的交换机都是持久化的。
队列持久化
RabbitMQ中队列默认是非持久化的,mq重启后就丢失。
SpringAMQP中可以通过代码指定交换机持久化:
@Bean
public Queue simpleQueue(){
// 使用QueueBuilder构建队列,durable就是持久化的
return QueueBuilder.durable("simple.queue").build();
}
事实上,默认情况下,由SpringAMQP声明的队列都是持久化的。
消息持久化
利用SpringAMQP发送消息时,可以设置消息的属性(MessageProperties),指定delivery-mode:
-
1:非持久化
-
2:持久化
用java代码指定:
默认情况下,SpringAMQP发出的任何消息都是持久化的,不用特意指定。
4.RabbitMQ如何保证消息消费不丢失
RabbitMQ是阅后即焚机制,RabbitMQ确认消息被消费者消费后会立刻删除。
而RabbitMQ是通过消费者回执来确认消费者是否成功处理消息的:消费者获取消息后,应该向RabbitMQ发送ACK回执,表明自己已经处理消息。
设想这样的场景:
-
1)RabbitMQ投递消息给消费者
-
2)消费者获取消息后,返回ACK给RabbitMQ
-
3)RabbitMQ删除消息
-
4)消费者宕机,消息尚未处理
这样,消息就丢失了。因此消费者返回ACK的时机非常重要。
而SpringAMQP则允许配置三种确认模式:
•manual:手动ack,需要在业务代码结束后,调用api发送ack。
•auto:自动ack,由spring监测listener代码是否出现异常,没有异常则返回ack;抛出异常则返回nack
•none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
由此可知:
-
none模式下,消息投递是不可靠的,可能丢失
-
auto模式类似事务机制,出现异常时返回nack,消息回滚到mq;没有异常,返回ack
-
manual:自己根据业务情况,判断什么时候该ack
一般,我们都是使用默认的auto即可。
5.RabbitMQ中哪些信息会成为死信队列
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
-
消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
-
消息是一个过期消息,超时无人消费
-
要投递的队列消息满了,无法投递
6.RabbitMQ中死信如何再消费
将死信队列与一个新的交换机和队列进行绑定,并将其作为消费者监听的队列。
消费者从新的队列中接收并处理死信消息。
7.RabbitMQ中TTL实现方案有哪些
一个队列中的消息如果超时未消费,则会变为死信,超时分为两种情况:
-
消息所在的队列设置了超时时间
-
消息本身设置了超时时间
8.RabbitMQ延时队列如何实现
RabbitMQ中实现延时队列的方式有多种,其中一种常见的方式是通过插件(如rabbitmq_delayed_message_exchange)来实现。该插件允许声明一个特殊类型的交换机,消息被发送到该交换机时,可以设置消息的延迟时间。延时过的消息会根据设定的延迟时间被路由到对应的队列中进行消费。
9.RabbitMQ有几种消息模式
Rabbitmq的工作模式有六种:
1.simple简单模式
生产者直接发送消息给RabbitMQ队列,消费者从队列消费。未定义和指定Exchange的情况下,使用的是内置的AMQP default这个Exchange
2.work工作模式
生产者发送消息到队列中,多个消费者消费同一个队列的数据,可以达到负载均衡的效. 消费者之间对于同一个消息的关系是竞争的关系。
对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。例如:短信服务部署多个,只需要有一个节点成功发送即可
3.publish/subscribe订阅模式
发布订阅模式主要是使用fanout类型交换器,routingKey忽略。每个消费者定义生成一个队列并绑定到同一个Exchange,每个消费者都可以消费到完整的消息。消息广播给所有订阅该消息的消费者。
4.routing路由模式
路由模式主要使用direct类型的Exchange,发N条消费并使用不同的routingKey,消费者定义队列并将队列、routingKey、Exchange绑定。使用direct模式Exchagne必须要routingKey完全匹配的情况下消息才会转发到对应的队列中被消费
5.topic 通配符模式
Topics 通配符模式主要是使用topic类型的交换器,队列绑定到交换器、bindingKey时使用通配符,交换器将消息路由转发到具体队列时会根据消息routingKey模糊匹配,比较灵活
topic类型的交换器背后原理跟direct类型的类似:只要队列的bindingKey的值与消息的routingKey匹配,队列就可以收到该消息。
通配符规则:#匹配一个或多个词,*匹配不多不少恰好1个词
6.RPC模式
RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:
1、客户端即是生产者也是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。
2、服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果。
3、服务端将RPC方法 的结果发送到RPC响应队列。
4、客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。
10.RabbitMQ消息堆积该如何解决
解决消息堆积有二种思路:
思路一 : 提高消费者的消费能力 , 可以开启多线程消费 , 条件允许的情况下可以增加消费者的数量 , 提高消费速度
思路二 : 扩大队列容积,提高堆积上限 , 将来不及消费的消息保存在磁盘上 , 高峰期过了之后慢慢消费 , 可以使用RabbitMQ惰性队列
11.RabbitMQ如何实现高可用
RabbitMQ的是基于Erlang语言编写,而Erlang又是一个面向并发的语言,天然支持集群模式。RabbitMQ的集群有两种模式:
普通集群:是一种分布式集群,将队列分散到集群的各个节点,从而提高整个集群的并发能力。
- 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息。
- 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
- 队列所在节点宕机,队列中的消息就会丢失
镜像集群:是一种主从集群,普通集群的基础上,添加了主从备份功能,提高集群的数据可用性。
- 交换机、队列、队列中的消息会在各个MQ的镜像节点之间同步备份。
- 所有操作都是主节点完成,然后同步给镜像节点
- 主宕机后,镜像节点会替代成新的主