1、 什么是 rabbitmq
釆用AMQP高级消息队列协议的一种消息队列技术撮大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦
2、 为什么要使rabbitmq
(1) 在分布式系统下具备异步,削峰,负载均衡等一系列高级功能;
(2) 拥有持久化的机制,进程消息,队列中的信息也可以保存下来。
(3) 实现消费者和生产者之间的解耦。
(4) 对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作。
(5) 可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单。
3、 使用rabbitmq的场景
(1) 服务间异步通信
(2) 顺序消费
(3) 定时任务
(4) 流量削峰
(5) 解耦(为面向服务的架构(SOA)提供基本的最终一致性实现)
4、 如何确保消息正确地发送至RabbitMQ?如何确保消息接收方消费了消息?
发送方稣模式
将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。
—旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道 会发送一个确认给生产者(包含消息唯一ID)。
如果RabbitMQ发生内部错误从皿导致消息丢失,会发送一条nack
(notacknowledged,未确认)消息。
发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。
接收方稣机制
消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。
这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了 Consumer足够长的时间来处理消息。保证数据的最终一致性;
以下是常见的源豚清况
(1) 如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重)
(2) 如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多的消息。
5 .如何避免消息重复投递或重复消费?
在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重的依据(消息投递失败并重侍),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个bizld (对于同一业务全局唯一,如支付ID、订单ID、 帖子ID等)作为去重的依据,避免同一条消息被重复消费。
6、消息基于什么传输?
由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能菰颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。
7、消息如何分发?
l>round-robin 轮询分发)
若该队列至少有一个消费者订阅,消息将以循环的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。通过路由可实现多消费的功能
2>Fair dispatch (公平分发) 使用basicQos(prefetchcount = 1)方法,来限制RabbitMQ只发不超过1条的消息 给同一个消费者。当消息处理完毕后,有了反馈,才会进行第二次发送。
注:使用公平分发,必须关闭自动应答,改为手动应答
8、 消息怎么路由?
消息提供方->路由->—至多个队列消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列路由键,可以把队列绑定到交换器 上。消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则);
常用的交换器主要分为一下三种:
fanout:如果交换器收到消息,将会广播到所有绑定的队列上
direct:如果路由键完全匹配,消息就被投递到相应的队列
topic:可以使来自不同源头的消息能够到达同一个队列。使用topic交换器时,可以使用通配符
9、 如何确保消息不丢失?
消息持久化,当然前提是队列必须持久化
RabbitMQ确保持久性消息能从服务器重启中恢复的方式是,将它们写入磁盘上的 —个持久化日志文件,当发布一条持久性消息到持久交换器上时,Rabbit会在消息提交到日志文件后才发送响应。一旦消费者从持久队列中消费了一条持久化消息,RabbitMQ会在持久化日志中把这条消息标记为等待垃圾收集。如果持久化消息在被消费之前RabbitMQ重启,那么Rabbit会自动重建交换器和队列(以及绑定),并重新发布持久化日志文件中的消息到合适的队列。
10、 使用RabbitMQ有什么好处?
(1) 服务间高度解耦
减少强依赖
(2) 异步通信性能高
可以使用线程池解决,但是缺点很明显:要自己实现线程池,并且强耦合
大多数是使用消息队列来解决
(3) 流量削峰
通过消息队列设置请求最大值,超过阀值的抛弃或者转到错误界面.
(4)釆用信道通信,不釆用tcp直接通信
lj.tcp的创建和销毁开销大,创建3次握手,销毁4四次分手
2) .高峰时成千上万条的槌接会造成资源的巨大浪费,而且操作系统没秒处理 tcp的数量也是有数量限制的,必定造成性能瓶颈
3) .—条线程一条信道,多条线程多条信道,公用一个tcp连接。一条tcp连接可以容纳无限条信道(硬盘容量足够的话),不会造成性能菰颈。
11、 RabbitMQ 的集群
镜像集群模式
你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
好处在于,你任何一个机器宕机了,没事儿,别的机器都可以用。
坏处,第一,这个性能开销也太大了吧,消息同步所有机器,导致网络带宽压力和消耗很重!
第二,这么玩儿,就没有扩展性可言了,如果某个queue负载很重,你加机器,新増的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue
12、 Rmq的缺点
(1) 系统可用性降低
系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ 挂了咋整? MQ挂了,整套系统崩溃了,你不就完了么。
(2) 系统复杂性提高
硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已
(3) 一致性问题
A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。
13、 RabbitMQ的工作模式
Simple模式(即最简单的收发模式)
1. 消息产生消息,将消息放入队列
2. 消息的消费者(consumer)监听消息队列,如果队列中有消息就消费掉,消息被拿走后,自动从队列中删除(隐患消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失,这里可以设置成手动的ack但如果设置成手动ack,处理完后要及时发送ack消息给队列,否则会造成内存溢岀)。
-•work工作模式(资源的竞争)
1. 消息产生者将消息放入队列消费者可以有多个,消费者1,消费者2同时监听同一 个队列,消息被消费。C1C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息(隐患:高并发情况下默认会产生某一个消息被多个消费者共同使用,可以设置一 个并关(syncronize)保证一条消息只能被一个消费者使用)。
三,publish/subscribe发布订阅(共享资源)
2、生产者将消息发给broker,由交换机将消息賴发到绑定此交换机的每个队 列,每个绑定交换机的队列都将接收到消息。
四.routing路由模式
amqp.gen-S9b…
1.消息生产者将消息发送给交换机按照路由判断,路由是字符串(inf。)当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息; 2.根据业务功能定义路由字符串
3. 从系统的代码逻辑中获取对应的功能字符串,将消息任务扔到对应的队列中。
4. 业务场景:error通知:EXCEPTION;错误通知的功能;传统意义的错误通知; 客户通知;利用key路由,可以将程序中的错误封装成消息传入到消息队列中, 开发者可以自定义消费者,实时接收错误;
五.topic主题模式(路由模式的一种)
Topic模式
1 )生产者发送消息到交换机;
2 )交换机消息送达队列为topic方式;
3 )消费者扌莫糊匹配路由Key ,进行消息消费;
#匹配一个或多个
*匹配一个
—般使用#号匹配多个,*号用的t:做少
交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费
14. 如何保证RabbitMQ消息的顺序性?
拆分多个queue,每个queue —个consumer,就是多一些queue而已,确实是麻烦点;或者就一个queue但是对应一个consumer,然后这个 consumer内部用内存队列做排队,然后分发给底层不同的worker来处理
15. 如何保证RabbitMQ消息的可靠传输?
消息不可靠的情况可能是消息丢失,劫持等原因;
丢失又分为:生产者丢失消息、消息列表丢失消息、消费者丢失消息;生产者丢失消息:从生广者弄丢数橢这个用度来看,RabbitMQ提供 transaction和confirm模式来确保生产者不丢消息;
transaction机制就是说:发送消息前,开启事务(channel. txSelect ()), 然后发送消息,如果发送过程中岀现什么异常,事务就会回滚 〔channel. txRolIback ()),如果发送成功则提交事务 (channel. txCommit ())。然而,这种方式有个缺点:吞吐量下降;
confirm模式用的居多:一旦channe 1进入confirm模式,所有在该信道上发布的消息都将会被指派一个唯一的ID (从1开始),一旦消息被投递到所 有匹配的队列之后;
rabbitMQ就会发送一个ACK给生产者(包含消息的唯一 ID),这就使得生产者知道消息已经正确到达目的队列了;
如果rabbitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。
消息队列丢数据:消息持久化。
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。
这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack 信号,生产者会自动重发。
那么如何持久化呢?
1. 将queue的持久化标识durable设置为true,则代表是一个持久的队列
2. 发送消息的时候将deliveryMode=2
这样设置以后,即使rabbitMQ挂了,重启后也能恢复数据
消费者丢失消息:消费者丢数据一般是因为釆用了自动确认消息模式,改为手动确认消息即可!
消费者在收到消息之后,处理消息之前,会自动回复RabbitMQ已收到消息;
如果这时处理消息失败,就会丢失该消息;
解决方案:处理消息成功后,手动回复确认消息。
16.如何解决消息队列的延时以及过期失效问题?消息队列满了以后该 怎么处理?有几百万消息持续积压几小时,说说怎么解决?
消息积压处理办法:临时紧急扩容:
先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都胃掉。
新建一个topic, partition是原来的10倍,临时建立好原先10倍的 queue数量。
然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍 数量的queue。
接着临时征用10倍的机器来部署consumer,母一批consumer消费一个临时queue的数据。这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据。
等快速消费完积压数据之后,得恢复原先部署的架构,重新用原先的 consumer机器来消费消息。
啊中消息失效:假设你用的是RabbitMQ, RabbtiMQ是可以设置过期时间的,也就是TTLo如果消息在queue中积压超过一定的时间就会被 RabbitMQ给清理掉。这就不是说数据会大量积压在mq里,而是大量的数据会直接搞丢。可以釆取一个方案,就是批量重导。
就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晩上12点以后,用户都睡觉了。这个时候 我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查岀 来,然后重新灌入mq里面去,把白天丢的数据给他补回来。也只能是这样了。假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢 了,你只能手动写程序把那1000个订单给查岀来,手动发到mq里去再补 —次。
mq消息队列块满了:如果消息积压在mq里,你很长时间都没有处理掉,此时导致mq都快写满了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晩上再补数据吧。
17. 设计MQ思路
比如说这个消息队列系统,可以从以下几个角度来考虑一下:
首先这个mq得支持可伸缩性吧,就是需要的时候快速扩容,就可以増加吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下kafka的设寸理念,broker -> topic -> partition,母个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给topic増加 partition,然后做数据迁移,増加机器,不就可以存放更多数据,提供更高的吞吐量了?
其次你得考虑一下这个mq的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是 kafka的思路。
其次你考虑一下你的mq的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的kafka的高可用保障机制。多副本-〉leader & follower -> broker挂了重新选举leader即可对外服务。
能不能支持数据0丢失啊?
通过offset commit来保证数据的不丢失,以及数据的不会重复消费。
kafka自己记录了每次消费的offset数值,下次继续消费的时候,接看上次的
offset进行;肖斐即可,可以通过手动的提交offset,保证数据的不会丢失。
18. rabbitmq怎么避免消息丢失
rabbitMQ消息可能丢失的情况:
L发送方发出消息但没有进入队列。
将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。一旦消息被投递到目的队列后,或者肖息被写入磁盘后
(可持久化的消息),信道会发送一个确认给生产者(包念肖息唯一ID )。
2. 接收者接到消息,但处理过程出现错误。
当消费者获取消息后,会向RabbitMQ发送回执ACK ,告知消息我被接收。不 过这种回执ACK分两种情况:
自动ACK :消息一旦被接收,消费者自动发送ACK
如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便
手动ACK :消息接收后,不会发送ACK ,需要手动调用
-如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK ,否则接收消息 后就自动ACK , RabbitMQ就会把消息从队列中删除。如果此时f肖费者宕机,那 么消,諷丢失了。
3. 队列或者列机。
消息持久化,当然前提是队列和交换机必须持久化
19.rabbitmq怎么实现延迟消息队列
使用RabbitMQ来实现延迟任务必须先了解RabbitMQ的两个概念:消息的TTL 和死信Exchange ,通过这两者的组合来实现上述需求。如果队列设置了,消息也 设置了,那么会取小的。所以一个消息如果被路由到不同的队列中,这个消息死亡 的时间有可能不一样(不同的队列设置)O
延迟任务通过消息的TTL和Dead Letter Exchange来实现。我们需要建立2个 队列,一个用于发送消息,一个用于消息过期后的转发目标队列。
生产者输出消息到Queuel,并且这个消息是设置有有效时间的,比如3分钟。 消息会在Queuel中等待3分钟,如果没有消费者收掉的话,它就是被转发到 Queue2 , Queue2有消费者,收到,处理延迟任务。
本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
如有侵权请发送邮件至1943759704@qq.com删除
码农资源网 » 常见Rabbitmq面试题及答案总结