RabbitMQ面试题:如何确保消息不丢失? --- 2022-04-03

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RabbitMQ面试题:如何确保消息不丢失? --- 2022-04-03相关的知识,希望对你有一定的参考价值。

参考技术A RabbitMq如何确保消息不丢失?

RabbitMQ主要通过持久化机制,确保消息不丢,RabbitMQ持久化机制分为队列持久化、消息持久化、交换器持久化。

下面从多个方面确保消息不丢:

RabbitMQ 的消息默认存放在内存上面,如果不特别声明,消息不会持久化保存到硬盘上面,如果节点重启或者意外crash掉,消息就会丢失。

要想做到消息持久化,必须满足以下三个条件:

默认情况消费者收到消息,MQ就会从队列中删除消息,如果消费者没处理成功,消息就丢了,可以使用手动ACK机制,处理完成手动调用MQ的ACK方法通知MQ删除消息。

使用集群模式部署RabbitMQ,实现消息的高可用,避免单个MQ节点挂了,消息就没了。

有时候可能是因为消息过期(TTL)、或者消费者异常导致消息丢了,这个时候需要从业务数据角度,写个脚本重新生成消息,投递到消息队列中。

关于RabbitMQ的一些面试题

目录

0. 什么是RabbitMQ

RabbitMQ采用AMQP高级新消息队列协议的一种消息队列技术,最大的特点是消费并不需要确保提供方实现,实现了服务之间的高度解耦

1. 延时队列底层实现

2. 使用RabbitMQ需要注意什么

3. RabbitMQ效率

4. 插入延时队列的过期时间是单调的麻?

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

5.1 发送方确认模式

将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后,信道会发送一个确认给生产者(包括消息的ID)。

如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack消息。

发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。

当确认消息到达生产者应用程序,生产者应用的回调方法就会被触发来处理确认消息。

5.2 接收方确认机制

消费者接受每一条消息后都必须进行确认,只要有消费者确认了消息,MQ才能安全的把消息从队列中删除。

这里并没有用到超时机制,MQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证了数据的最终一致性。

还有几种情况:

  • 如果消费者接受到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消费重复的隐患,需要去重)
  • 如果消费者接受到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙。则不会给该消费者分发更多的消息。

6. 如何避免消息重复投递或重复消费?

在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列,在消息消费时,要求消息体中 必须要有一个bizID(对于同一个业务全局唯一) 作为去重的依据,避免同一条消息被重复消费。

7. 消息基于什么传输?

由于 TCP 连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制

8、消息如何分发?

  • 一个生产者,多个消费者
  • 多个消费者时,是轮询机制,依次分发给消费者(每个消费者按顺序依次消费)

no_act设置是否确认消息处理完?

  • no_act = True , 消费者不发送确认信息,RabbitMQ从发送消息队列后,不管消费者是否处理完,删除queue
  • 设置no_act=False,RabbitMQ等待消费者的callback处理完,发送确认信息,如果此时消费者down了,则RabbitMQ把消息轮询发送给下一个消费者,等待确认才会删除queue
  • 去掉no_act=True,需要在回调函数中新增代码,手动向RabbitMQ发送确认信息

9、消息怎么路由?

  • Direct:直连模式

  • Topic: 转发模式
    Topic 模式下可以使用统配符表示bingKey:’*'表示匹配一个单词, '#'则表示匹配没有或者多个单词。由此可以实现一个queue接收多个路由的消息。

  • Fanout :广播模式
    广播模式下,不用理会routing keyFanout Exchange 会将消息传递到 exchange 绑定好的 queue list 上去。

10、如何确保消息不丢失?

10.1 生产者丢失消息

可以选择使用 RabbitMQ 提供事务功能,就是生产者在发送数据之前开启事务,然后发送消息,如果消息没有成功被RabbitMQ接收到,那么生产者会受到异常报错,这时就可以回滚事物,然后尝试重新发送;如果收到了消息,那么就可以提交事物。

缺点: RabbitMQ 事务已开启,就会变为同步阻塞操作,生产者会阻塞等待是否发送成功,太耗性能会造成吞吐量的下降。

还有就是上面的第五点

10.2 RabbitMQ自己丢了数据

持久化

10.3 消费者弄丢了数据

使用 RabbitMQ 提供的 ACK 机制,首先关闭 RabbitMQ 的自动ACK,然后每次在确保处理完这个消息之后,在代码里手动调用 ACK。这样就可以避免消息还没有处理完就ACK。

11、RabbitMQ的集群

12、使用RabbitMQ有什么好处?

12.1 削峰

把消息压入RabbitMQ中可以缓冲系统压力。比如现在系统只能接受2000请求,但是一下子有10000个请求过来,那么这个请求就会压在RabbitMQ中,那么就可以慢慢进行消费了。

12.2 异步

以前是先去发短信,再去发邮件。引入RabbitMQ之后,我们就可以进行在发短信的同时再去发邮箱。

12.3 解耦

当多个系统耦合在一起的时候,系统的消息会发送给连在一起的系统,但是这个消息有些系统可能是不需要的。所以引入了之后,很方便将这个系统进行解耦,每个系统需要的就在消息队列解耦。

13、MQ 的缺点

虽然能提供削峰,异步,解耦,但是这个还是有很多要考虑的问题,消息丢失,重复消费。

14、介绍Rabbitmq的手动ACK和自动ACK

当消息一旦被消费者接收,队列中的消息就会被删除。那么问题来了:RabbitMQ怎么知道消息被接收了呢?

这就要通过消息确认机制(Acknowlege)来实现了。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。不过这种回执ACK分两种情况:

  • 自动ACK:消息一旦被接收,消费者自动发送ACK
  • 手动ACK:消息接收后,不会发送ACK,需要手动调用

这两ACK要怎么选择呢?这需要看消息的重要性:

  • 如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便
  • 如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK,否则接收消息后就自动ACK,RabbitMQ就会把消息从队列中删除。如果此时消费者宕机,那么消息就丢失了。

参考连接

分布式消息中间件-RabbitMQ面试题(必问)
RabbitMQ-解耦、异步、削峰

以上是关于RabbitMQ面试题:如何确保消息不丢失? --- 2022-04-03的主要内容,如果未能解决你的问题,请参考以下文章

2023春招面试:消息中间件面试题整理

2023春招面试:消息中间件面试题整理

RabbitMQ面试题:如何解决消息的顺序问题? --- 2022-04-03

关于RabbitMQ的一些面试题

RabbitMQ如何确保消息不丢失?

分享一波 RabbitMQ 面试题有答案