rabbitmq面试题话术

1、介绍一下rabbitmq

RabbitMQ是Erlang语言开发的基于AMQP的一款消息中间件,核心思想是生产者不会将消息直接发送给队列,消息在发送给客户端时先发送给交换机,然后由交换机转发给对应的队列。对路由(Routing),负载均衡(Load balance)、数据持久化都有很好的支持。
它里边有5种数据传递方式

第一种是简单模型,一个生产者,一个队列,一个消费者,队列只能被一个消费者监听,所以生产者将消息发给队列之后,只能有一个消费者收到消息

第二种是工作模型,一个生产者,一个队列,多个消费者,队列可以被多个消费者监听,但是生产者将消息发给队列之后,还是只能有一个消费者接收到消息

后边三种都叫订阅模型,这三种里边引入了交换机的概念,具体的区分是根据交换机的类型区分的,在这三种模式种,生产者把消息发送给交换机,交换机不负责存储消息,由交换机发送给指定的队列,消费者监听队列消费消息。

首先是fanout类型,这种叫广播模式,生产者将消息发送给交换机,交换机会将消息转发给所有绑定到到当前交换机的队列中,对应监听队列的消费者都能收到消息,但是,如果没有队列绑定到这个交换机,消息会被mq丢弃。

接着是direct类型,这种叫定向模式,也叫路由模式,这种模式中,队列在绑定交换机的时候,同时指定了自己的routing key,可以理解为一个路由标示,生产者在发送消息给交换机的时候,同时指定要发送给的routing key,这时候,交换机就会根据这个routing key来定向的发送给对应的队列,对应监听该routing key的队列的消费者就能收到消息,但是如果交换机没有找到对应的routing key,消息会被丢弃。

最后是topic模式,这种叫通配符模式,队列在绑定交换机的时候,同时指定了自己的routing key,生产者在发送消息给交换机的时候,同时指定要发送给的routing key 的通配符,一般这个routing key是由多个单词用.的方式隔开的,通配符中,#号可以匹配一个或者多个单词,*号只能匹配一个单词,例如生产者指定的通配符为a.#,可以匹配到的routing key有:a.b、a.b.c等,如果是a.*的话,只能匹配a.b或者是a.c这样的routing key。每个队列绑定到交换机的时候可以定义多个routing key,交换机会跟据指定的通配符,发送到匹配通配符的routing key 对应的队列中,对应的消费者就可以收到消息了,但是,如果没有符合通配符的routing key ,消息会被丢弃

当然,在生产中使用的时候,为了避免mq宕掉等造成消息丢失的问题,我们都会配置持久化措施,在rabbitmq里,需要将交换机持和队列和消息持久化,这样消息就会被持久化到磁盘中,不会因为突发的断电等情况导致消息丢失

2、如何保证消息确定消息发送成功,并且被消费成功,有什么保障措施

第一部分是确保发送成功,还可以被问成:消息发送失败了怎么办,或者如何保证消息可靠传输

第二部分是确保消费成功,还可以被问成:消息消费时,发生异常了,消息已经被消费了,怎么办等

首先,需要确保消息被发送成功,rabbitmq中提供了事务和confirm的机制,事务的话,就类似于数据库的事务,开启,执行,提交,如果过程中发生任何异常,就会触发回滚机制,我们可以在回滚中加入一些逻辑处理,重新发送或者日志记录,同时配置生产者确认的机制,就是在消息发送之后,该消息会被指定唯一的ID,如果有消息成功被交换机转发到队列之后,mq会给生产者发送ack确认,如果没有队列接收消息,那么会发送错误回执消息给生产者,生产者可以尝试重试发送,或者日志记录。通过这些可以看出,mq会增加一些保障性措施,必然会导致性能有一些下降,如果要保证消息的严格一致性,那么可以配置这些,如果消息不重要,或者允许有丢失的情况,那么可以不用配置,这样的话能提升mq的性能。

其次就是,消息确保发送成功之后,还要确保消息被消费成功,因为在消费者端,如果消息消费时发生异常,又没有做一些处理,那么消息就会丢失,这种情况,可以采取两种方式解决

第一种就是消费端配置手动ACK确认机制,消息被消费完成的时候,手动确认告诉mq消费成功,mq才会删除消息,如果消息被接收了,但是mq没有收到ack确认,那么消息在mq中会变为unacked状态,我们可以通过项目日志或者mq面板监控,当消费者断开连接之后,消息会重新回到队列中,消费者重新连接之后,会再次收到消息。

第二种就是可以结合数据库解决,生产者端发送成功之后,可以在数据库中存储发送的消息和发送时间,并标记状态为未消费状态,消费者端消费完成之后,标记mysql中数据的状态为已经消费。消费者端通过定时任务去数据库跑批检索超时未被消费的消息并重新发送,这种方式可以很好的解决消费失败的问题,但是增加了生产者和消费者之间的耦合度,以及会造成消息重复消费的问题,我们可以在保证消息发送成功的基础上,将上述逻辑放在消费者端,生产者正常发送消息,消费者在收到消息之后,存储到myqsl中,标记状态为未消费,同时ack通知mq确认,然后再消费消息,消息消费成功之后,改变mysql状态为已消费,消费端同时配置定时任务跑批检索数据库,定时重新执行超时未消费的消息。

以上的解决办法都是需要根据实际的业务需求来的,如果消息需要保证强一致性,不能出现任何差错,那么就需要按照前面说的添加对应的配置

我们项目中的mq主要用于数据同步使用的,mysql数据发生变化之后,需要同步到es索引库以及静态化页面中,这里我们配置了生产者确认模式,和消费者手动ack确认机制。

3、如何保证消息不被重复消费

我们可以在生产者端,发送消息时,数据的变动部分,进行md5加密处理,同时配置上一个唯一id,每次发送的数据的唯一id是递增的,相当于版本号的功能,在消费者端,收到消息之后,首先去数据库匹配一下md5值如果数据库中记录的当前记录已经被消费,那么就不进行消费,如果发现数据库没有记录当前消息,或者记录的状态没有被消费,那么才会重新消费该消息

4、RabbitMQ 宕机了怎么处理

RabbitMQ 提供了持久化的机制,将内存中的消息持久化到硬盘上,即使重启 RabbitMQ,消息也不会丢失。持久化队列和非持久化队列的区别是,持久化队列会被保存在磁盘中,固定并持久的存储,当 Rabbit 服务重启后,该队列会保持原来的状态在RabbitMQ 中被管理,而非持久化队列不会被保存在磁盘中,Rabbit 服务重启后队列就会消失。非持久化比持久化的优势就是,由于非持久化不需要保存在磁盘中,所以使用速度就比持久化队列快。即是非持久化的性能要高于持久化。而持久化的优点就是消息会一直存在,不会随服务的重启或服务器的宕机而消失。使用的时候需要根据实际需求来判断具体如何使用。

5、Rabbitmq的应用场景

主要有三个解耦、异步、削峰
解耦:假设现在:日志不光要插入到数据库里,还要在硬盘中增加文件类型的日志,同时,一些关键日志还要通过邮件的方式发送给指定的人。那么,如果按照原来的逻辑,A可能需要在原来的代码上做扩展,除了B服务,还要加上日志文件的存储和日志邮件的发送。但是,如果你使用了MQ,那么,A服务是不需要做更改的,它还是将消息放到MQ中即可,其他的服务,无论是原来的B服务还是新增的日志文件存储服务或日志邮件发送服务,都直接从MQ中获取消息并处理即可。这就是解耦,他的好处就是提高系统灵活性,扩展性。
异步:可以将一些非核心流程,如日志,短信,邮件等,通过MQ的方式异步处理。这样做的好处是缩短主流程的响应时间,提升用户体验。
削峰:MQ的本质就是业务的排队,所以,面对突然到来的高并发,MQ也可以不用慌装,先排好队,不要着急,一个一个来,削峰的好处就是避免高并发压垮系统的关键组件,如某个核心服务或者数据库等。

6、RabbitMQ防⽌消息堆积

1.优化消费端的代码,提升消费端处理消息的速度,同时再多写点消费,实现消费的负载
2.RabbitMQ实现集群,让服务器的性能得到扩容,消费端项⽬也实现集群
3.更好MQ中间件,如果消息堆积过多,可以考虑更换为kafka或RocketMQ,因为RabbitMQ消息堆积的性能⼀般(海量消息堆积)

7、RabbitMQ实现延迟队列

场景:超时⾃动处理(订单超时、预约挂号超时等)
实现:有两种⽅式
1.代码实现延迟队列:采⽤死信机制实现延迟,具体流程如下:
在这里插入图片描述

2.使⽤RabbitMQ的延迟插件,需要再RabbitMQ上安装延迟插件,就可以操作延迟队列

8、如何保证消息的顺序性?

顺序会错乱的俩场景:
RabbitMQ:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者2先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。
在这里插入图片描述
解决方案:
拆分多个 queue,每个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。
在这里插入图片描述

  1. 单一队列:将所有相关有消息发送到同一个队列中,并且只使用单个消费者来处理这个队列。这样可以确保消息按照发送顺序依次被消费。
  2. 消息排序标识:在每条消息中添加一个排序标识字段,在消费端根据该字段对消息进行排序和处理。
  3. 优先级队列:使用RabbitMQ提的优先级插件(Priority Queueing Plugin)来创建具有优先级的队列。将所有相关有序消息发送到该队列,并设置合适的优先级值以确保按照预期顺序被消费。

10、RabbitMQ做延迟,如何实现的?

通常采用"死信队列"(Dead Letter Exchange,DLX)和TTL(Time-To-Live)相结合的方式。下面是具体的实现步骤:
定义两个交换机和两个队列: 一个用于处理正常业务,一个用于处理延迟消息。延迟消息首先进入延迟队列,延迟时间到期后转发到正常业务队列进行处理。
配置TTL和DLX: 在延迟队列上设置消息的TTL,并指定死信交换机。当消息在延迟队列中达到TTL时间后,会被转发到指定的死信交换机。
实现过程:
消息首先发送到延迟交换机,进入延迟队列。
消息在延迟队列中等待TTL时间到期。
当TTL时间到期后,消息会被转发到死信交换机。
死信交换机会将消息转发到正常业务队列,由消费者进行处理

11、如何保证消息队列的高可用?

镜像集群模式(高可用性)
这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。
在这里插入图片描述
那么如何开启这个镜像集群模式呢?其实很简单,RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。
这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值