2021面试准备-RabbitMQ

168 阅读10分钟

9.RabbitMQ

9.1 什么是RabbitMQ

RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的,消息中间件

9.2 为什么要使用RabbitMQ?Rabbit有什么优点

解耦、异步、削峰

9.3 RabbitMQ有什么缺点

​ 1、降低了系统的稳定性:本来系统运行的好好的,现在非要加入个消息队列,那消息队列挂 ,你的系统就呵呵了,因此系统可用性降低

​ 2、增加了系统的复杂性:加入了消息队列,要考虑很多方面的问题,比如:一致性问题,如何保证消息不被重复消费,如何保证消息可靠性传输等,因此,需要考虑的东西更多,复杂性增大、

9.4 RabbitMQ的工作模式

1、简单模式

一个生产者,一个消费者

2、work模式(常用)

一个生产者,多个消费者,每一个消费者获取到的消息唯一

3、订阅模式

一个生产者发送的消息会被多个消费者获取

4、路由模式

发送消息到交换机并且要指定路由key ,消费者将对垒绑定到交换机时需要指定路由key.

5、topic 模式(常用)

将有键和某模式进行匹配,此时队列需要绑定一个模式上,“#”匹配一个或多个词,“*”只匹配一个词

9.5 如何保证RabbitMQ消息不被重复消费?

​ 先说为什么会重复消费:正常情况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。

​ 但是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将消息分发给其他的消费者。

​ 针对以上问题,一个解决思路是:保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响,保证消息等幂性。

​ 比如:在写入消息队列的数据做唯一标示,消费消息时,根据唯一标识判断是否消费过。

9.6 如何保证RabbitMQ消息可靠传输

​ 消息不可靠的情况可能是消息丢失,劫持等原因。丢失又分为:生产者丢失消息、消息列表丢失消息、消费者丢失消息

生产者丢失消息

​ 从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。

​ transaction模式:发送消息前,开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事务就会回滚(channel.txRollback()),如果发送成功则提交事channel.txCommit())。然而,这种方式有个缺点,吞吐量下降。

confirm 模式: 一旦channel进入confirm模式,所有在改信道上发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后。RabbitMQ就会发送一个ACK给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果 rabbitMQ 没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。

消息队列丢数据

消息持久化。处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和 confirm 机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个 Ack 信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。那么如何持久化呢?这里顺便说一下吧,其实也很容易,就下面两步:

  1. 将queue的持久化标识durable设置为true,则代表是一个持久的队列。

  2. 发送消息的时候将deliveryMode=2。 这样设置以后,即使rabbitMQ挂了,重启后也能恢复数据

消费者丢失消息

消费者丢数据一般是因为采用了自动确认消息模式,改为手动确认消息即可!消费者在收到消息之后,处理消息之前,会自动回复 RabbitMQ 已收到消息。如果这时处理消息失败,就会丢失该消息。 解决方案:处理消息成功后,手动回复确认消息。

9.7 如何保证RabbitMQ消息的顺序性?

单线程消费保证消息的顺序性。对消息进行编号,消费者处理消息是根据编号处理消息。

9.8 如何确保消息正确地发送至RabbitMQ?如何确保消息接收 方消费了消息?

发送方确认模式 将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一ID)。如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(not acknowledged,未确认)消息。发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

接收方确认机制

​ 消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。这里并没有用到超时机制,RabbitMQ 仅通过 Consumer 的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证数据的最终一致性。

下面罗列几种特殊情况

​ 如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重)。

​ 如果消费者接收到消息却没有确认消息,连接也未断开,则 RabbitMQ 认 为该消费者繁忙,将不会给该消费者分发更多的消息

9.9 RabbitMQ消息堆积处理

  1. 增加消费者的处理能力(例如优化代码),或减少发布频率。

  2. 考虑使用队列最大长度限制。

  3. 给消息设置年龄,超时就丢弃。

  4. 默认情况下,rabbitmq消费者为单线程串行消费,设置并发消费两个关 键属性 concurrentConsumers 和 prefetchCountoncurrentConsumers 设置 的是对每个listener在初始化的时候设置的并发消费者的个数,prefetchCount 是每次一次性从broker里面取的待消费的消息的个数。

  5. 建立新的queue,消费者同时订阅新旧queue,采用订阅模式。

  6. 生产者端缓存数据,在mq被消费完后再发送到mq,打破发送循环条件, 设置合适的qos值,当qos值被用光,而新的ack没有被mq接收时,就可以 跳出发送循环,去接收新的消息;消费者主动block接收进程,消费者感受到接 收消息过快时主动 block,利用 block 和 unblock 方法调节接收速率,当接收 线程被block时,跳出发送循环。

9.10 RabbitMQ消息丢失解决方案

​ 消息持久化 ​ Exchange 设置持久化:durable:true。 ​ ueue 设置持久化;Message持久化发送。 ​ ACK确认机制 ​ 消息发送确认。 ​ 息接收手动确认ACK

9.11 RabbitMQ宕机了怎么处

​ RabbitMQ提供了持久化的机制,将内存中的消息持久化到硬盘上,即使重启RabbitMQ,消息也不会丢失。

​ 持久化队列和非持久化队列的区别是,持久化队列会被保存在磁盘中,固定并持久的存储,当Rabbit服务重启后,该队列会保持原来的状态在RabbitMQ中被管理,而非持久化队列不会被保存在磁盘中,Rabbit 服务重启后队列就会消失

​ 非持久化比持久化的优势就是,由于非持久化不需要保存在磁盘中,所以使用速度就比持久化队列快。即是非持久化的性能要高于持久化。

​ 而持久化的优点就是会一直存在,不会随服务的重启或服务器的宕机而消 失。

9.12 RabbitMQ的集群

Rabbitmq有3种模式,但集群模式有2中,详情如下: 单一模式 即单机情况不做集群,就单独运行一个rabbitmq而已。 普通模式 默认模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。 所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢 失的现象。 镜像模式 把需要的队列做成镜像队列,存在与多个节点属于RabbitMQ的HA案。该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

9.13 如何解决分布式事务问题?

1.2PC:两阶段提交 执行阶段: 当创建订单时,向所有微服务发送消息,可以开始执行了,执行成功后,不直接 提交,而是返回一个消息告诉我,执行成功还是执行失败。 第二阶段: 如果所有人都执行成功,再发一个消息,你们可以提交了; 如果第一阶段有人执行失败,你就告诉所有人都回滚。 缺点:当锁定的表很多时,性能差。 3.TCC:补偿性事务(一般采用) try-confirm-concel 每个服务执行完后都提交,集中返回给自己,如果都执行成功了那就不管 如果提交失败,就采用失败服务的补偿方法去补偿,但若补偿方法也失败,那你还 需要进行重试写重试方法或者人工介入。 优缺:解决了性能问题,但是业务复杂,写一个事务还需要写补偿方法。 异步确保:利用mq实现分布式事务。