八股训练--RabbitMQ
一、经典问题
1.为什么要用MQ?
MQ的作用主要是3个,
第一个是流量削峰:当某个活动举行时,访问量可能是平时的几百倍,可能一下会把服务器弄崩溃,所以通过MQ的形式,引入中间者,客户端将请求都发到MQ这里,服务器根据自身的容量去MQ中取请求进行处理,这样起了流量削峰的作用。
第二个是应用解耦:当一个应用中有许多系统,订单系统,库存系统,支付系统等,任何一个子系统出现了故障,都会造成下单操作的故障,引入了MQ之后,一个子系统故障了,另外的子系统仍然可以进行相应的操作。
第三个是异步处理:当A调用了B方法之后,B方法要执行很久,但A还有许多方法还要执行,就可以使用MQ进行异步的方式执行B方法,A继续执行其他方法,之后B方法执行完成之后就通知A一次,就节省了运行时间。
2.常见MQ的区别
区别 | RabbitMQ | RocketMQ | KafKa |
语言 | Erlang | Java | Scala & Java |
支持语言 | 几乎支持所有语言 | Java,C++不成熟 | 多种语言 |
单机吞吐量 | 万级3 | 十万级1 | 十万级2 |
消息延迟 | 微秒级 | 毫秒级 | 毫秒以内 |
可用性 | 高,基于主从架构 | 非常高,分布式结构 | 非常高,分布式结构,一个数据多个副本 |
消息可靠性 | - | 可以做到零丢失 | 可以做到零丢失 |
优势 | 支持所有语言,吞吐量万级,功能齐全 | 接口简单易用,吞吐量大,分布式使用方便 | 超高吞吐量,ms的延迟,可用性有保障 |
劣势 | 吞吐量较低,erlang语言不易定制开发,二次开发 | 只支持Java和C++,C++还不成熟 | 有可能进行消息的重复消费 |
应用 | 都有使用 | 大规模,复杂的业务 | 大数据的实时计算和日志采集 |
3.RabbitMQ各组件功能
1.Server:接收客户端的连接,实现AMQP的实体服务。
2.Connection:连接,应用程序和Server的网络连接,TCP连接
3.Channel:一个信道中有多个Connection,减轻了TCP connection的开销
4.Message:消息
5.VirtualHost:虚拟主机,可以有多个,一个虚拟主机里面有许多交换机和队列,但名称不能相同
6.交换机:按照路由规则将消息映射到对应的队列中。如果路由不到,就返回给消费者或者直接丢弃,常见类型有direct,fanout,topic,headers四种
7.队列:保存消息,给消费者消息
8.绑定:交换机和队列之间的路由规则
4.RabbitMQ的工作原理
生产者连接到Server,并开启一个信道,建立许多连接,生产者将消息发送给broker server,然后brokersever根据virtualhost中的交换机和队列的路由规则保存在队列中,消费者和中间者建立连接了之后,从队列中取消息进行一定的消费。
5.RabbitMQ的工作模式
1.simple模式:
生产者将消息直接发送到队列中,消费者监听队列中存在消息,就直接取出消费掉,队列之后将消息删除。
隐患:消息可能没有被消费者正确处理,但队列仍然将消息删除了,造成了消息的丢失,这时候设置手动的ack比较合适。
2.work Queues模式:
生成者将消息发送到队列中,有多个消费者去抢夺这个消息,多并发的情况下就设置一个开关,保证消息只能被一个消费者消费
3.publish/subscribe发布订阅模式
消费者监听队列,生产者将消息发给broker,由交换机将消息转发到绑定每个交换机的每个队列,每个绑定交换机的队列都会收到消息
4.routing路由模式
只有当交换机和队列的key能够匹配之后,交换机才将消息转发到对应的队列中,之后绑定队列的消费者才能消费
5.topic主题模式(路由模式的一种)
存在模糊匹配的方式
6.RabbitMQ消息丢失的情况有哪些?
1.生产者发送消息到broker server时发生丢失
2.broker server 存储的消息丢失
3.broker server 存储的消息分发给消费者时丢失
7.消息丢失的原因和解决方法
1.生产者发送消息到broker server时发生丢失:
原因:1.发送过程中存在网络问题 2.代码本身逻辑问题
解决方法:发送方确认机制(publisher confirm):生产者将信道设置成confirm模式,一旦信道进入这个confirm模式,信道上面的消息就会被指派一个唯一id,一旦消息被投递到队列中,broker就会返回一个确认消息给生产者(包含消息的唯一id),这就确保了消息的成功传递(confirm模式最大的好处就是它是异步的,一旦发布了一条消息,生产者可以继续发送消息,消息被确认了之后,生产者会调用回调方法来确认,如果broker server因为自身错误丢失了消息就会返回一个nack,生产者之后再重新做相应的处理)
发布确认的情况:
1.单独发布确认:一条消息只有被确认了之后,才能继续发送消息,如果指定时间没有返回确认信息就会抛异常
2.批量发布确认:一次性发布一批消息,但如果发送故障导致发布出现问题之后,就无法知道是哪个消息出现了问题,就导致需要重新发一整批消息,同步操作,会阻塞消息的发布
3.异步发布确认:逻辑虽然比前两个复杂,但是因为异步提高了许多效率,将消息的确认异步处理,发送消息之后仍然可以继续发送消息。
还可以使用AMQP的事务处理,但是这样的方式效果不是特别的好,因为这个事务是同步的,一旦有一条消息丢失了之后,就会阻塞整个发送的过程。跟单独发布类似了
2.Broker Server 中存储的消息丢失:
原因:消息没有持久化,服务器重启的时候导致消息丢失
解决方式:1.消息回退:通过设置mandatory参数可以在当消息传递过程中不可达目的地时将消息返回给生产者。对于这些无法路由的消息就设定一个备份交换机,然后将消息存储到备份交换机的队列中,这时候之后就手动地对这些队列中的消息进行处理
2.设置持久化:当MQ接收到消息的时候,通过持久化的方式将消息存储到硬盘中
3.RabbitMQ 发给消费者时消息丢失:
原因:1.消费者接收到消息之后,还没来得及处理消息,消费者机器就宕机了
2.处理消息存在异常
解决方案:默认采用了自动应答的方式,要想消息在消费过程中不丢失,需要把手动应答转换成自动应答。
8.RabbitMQ消息基于什么传输
由于TCP连接的创建和销毁开销较大,且并发数会受到系统资源的限制,RabbitMQ采用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,每个tcp上的信道数量是没有限制的。
9.RabbitMQ支持消息幂等性?
支持的,当生产者给mq发送一条消息的时候,mq内部都会生成一个inner-msg-id,作为去重的依据(消息投递失败并重传),防止重复的消息进入队列。消费同理,要求消费体中必须要有一个bizid,避免一条消息被重复消费。
10.RabbitMQ消息持久化的条件
1.声明队列必须设置为持久化durable设置为true
2.消息推送投递模式必须设置持久化,deliveryMode设置为2(持久)
3.消息到达持久化的交换机
4.消息到达持久化的队列
11.RabbitMQ死信队列的介绍
定义:由于一些原因导致queue种的某些消息无法被正常消费,这些消息没有后续的处理,就变成了死信消息
来源:消息TTL过期,(队列达到最大值,消息无法加入到队列中),消息被拒绝
用处:用于实现延迟队列
12.RabbitMQ延迟队列的介绍
用来存放在指定时间被处理的队列
使用场景:
1.订单在10分钟内未支付自动取消
2.用户注册之后,3天没有登录就发短信提醒
3.用户发起退款,3天内商家没有处理,就直接通知运营人员
4.预定会议后,开始前10分钟通知各个人员进行参会
实现条件:1.消息设置TTL 2.存在死信队列
13.RabbitMQ如何处理消息堆积
当出现消息挤压之后,先处理宕机的消费者,然后创建原先N倍的队列,将堆积的消息都轮询到这些队列中,然后再创建N倍的消费者,每一个消费者对应一个队列,快速地把堆积的消息给消费了之后,恢复到原来的模式。(这种做法就相当于临时将queue的资源和消费者的i资源扩大了N倍,消费的速度也变为了N倍)
14.RabbitMQ如何处理消息中丢失的数据
在流量的低峰期的时候,写一个程序去手动查询那些丢失的信息,然后将消息重新发送到mq中,让消费者进行消费
15.RabbitMQ如何处理长时间未处理导致写满的情况?
和上面的情况类似,先写一个程序直接去MQ中消费消息,消费一个就丢弃一个,先降低MQ的压力,等到流量低峰期时,就去手动地查询丢失的数据
16.如何设计一个消息队列
这个问题可以观看我以前的博客:Java项目--仿RabbitMQ的消息队列_04Koi.的博客-CSDN博客
这里面详细讲解了如何简单设计一个消息队列,感谢观看!