RabbitMQ 面试题

一、本文主旨

二、面试题

2.1 当消息消费速度赶不上生产速度,如何提高消费速度?

:优化消息消费速度,就要从其过程来分析,消息的消费速度主要是受到发送消息时间、消息处理时间、消息确认时间的影响;我们要做的就是降低在发送和确认过程消耗的时间,降低消息处理时间或者说提高相同时间内处理的消息数量;通过设置的prefetch count值控制RabbitMQ每次发送消息数量,减少发送、确认过程消耗的时间,同时可以在消费者内使用如多线程、优化SQL等操作,降低单条消息的处理时间,以此来提高消费速度,最后增加消费者数量的方式也是可行的;


  1. 提高 prefetch count
    因为消费速度主要收到发送消息时间、消息处理时间、消息Ack时间(确认)的影响;如果一个消息走完这个流程再重新发送的话,效率会非常低,所以通过设置合适的prefetch count值,控制RabbitMQ每次发送的消息数量,使消费者处于的消息处理状态的时间增加,以此来提高消费速度;
  2. 消费者多线程消费:
    prefetch count的思路,在消费者消费时,使用多线程的方式来处理消息,能增加相同时间内消息的数量,即prefetch count的值,以此提高消费速度;
  3. 增加消费者数量;

2.2 如何防止消息丢失?

:从消息的传递流程来看,无论是生产者发送消息、RabbitMQ异常,还是消费者消费时都有可能造成消息丢失;生产者发送造成丢失有两种方式解决,RabbitMQ事务和confirm机制,前者通过异常回滚,后者通过接受返回ack消息,或者失败回调nack接口决定是否重发确保消息不丢失,但前者会破坏解耦特性,并且同步阻塞会极大降低性能,而confirm机制则是异步的;RabbitMQ自身丢失信息可以采取对交换机、队列、消息进行持久化的方式,防止其异常造成消息丢失;消费者则可以通过手动返回ack消息的方式,保证消息被成功消费;

:从消息的传递流程,可以分析出,出现消息丢失一般分为以下几种:生产者发送丢失、RabbitMQ自身丢失、消费时丢失;那就针对每一点逐个击破:

  1. 生产者发送丢失:
    如果生产者发送消息的途中,出现网络问题,就会出现消息丢失,而这时生产者并不知道消息已经丢失,而RabbitMQ没接收到消息,也不会有相应的操作;

    解决方法:
    ①RabbitMQ事务:生产者开启事务,这会将生产者发送给broker (消息队列服务器实体)这一系列流程当作事务处理,一旦消息没有成功被RabbitMQ接收,生产者就会受到一场报错,从而回滚;但其缺点在于:a.破坏了解耦特性;b.开启事务会变为同步阻塞操作,等待返回结果会造成极大的性能下降;
    ②开启confirm模式:生产者开启confirm模式,就会对每次写的消息分配一个唯一id,如果正常写入RabbitMQ中就会返回一个Ack(确认)消息,否则会回调nack接口,这样就可以自定义重发等操作;confirm时异步的,所以使用更广。

  2. RabbitMQ自身丢失消息:
    如果RabbitMQ发生异常时,存储其中的数据可能会丢失,而这时我们可以采用持久化的手段,对交换机、队列、消息进行持久化,这样重启后才能恢复;同时我们可以把消息持久化与confirm机制结合起来,更增可靠性;

  3. 消费时丢失消息:
    消费者接受消息途中、处理时服务出现异常,都有可能造成数据的丢失,而此时RabbitMQ并不知道消息是否已经消费;

    解决方法:
    手动返回ack:我们都清楚,消费者在接受消息后,我们可以设置手动返回ack消息或者自动返回ack消息,这里要明确的就是,自动返回ack是在消费者接收到消息后就会返回,而手动返回ack可以让我们自定义消息被消费后再返回,由此避免出现接受而非消费的情况造成数据丢失;这里要注意的是ack机制可能会造成消息重复消费的情况,这里的解释就交给 2.3 小节吧。

2.3 如何防止消息重复消费(幂等性)?




:消息被重复消费有两种情况,一是生产者重复传递多条消息给RabbitMQ,生成多条重复消息,二是消费者重复消费一条消息,依然是逐个击破:

  1. 生产者重复传递多条消息给RabbitMQ,生成多条重复消息:
    如果生产者成功发送,但由于网络波动,RabbitMQ的ack回执并没有被生产者接收到,就会重新发送造成多条重复消息;

    其实这个严格来说只能算作是重复消费的起因,但是却无法在源头上避免,因为接收到ack消息才能确认消息被RabbitMQ成功接收,网络波动却是无法干预的;

  2. 同一条消息被多个消费者消费:
    如果消费处理成功后,返回ack消息时出现网络波动,导致broker未能成功接收到,那么消息就会被重新放到其他队列导致重复消费;

    解决方法:给消息分配一个全局id,只要消费过该消息,就将<id,message>以键值对的形式写入redis;那么在消费之前先去查询有无消费记录即可避免重复消费。

2.4 如何保证消息的有序消费?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mitays

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值