MQ面试总结
为什么要使用MQ
点击展开
- MQ的核心:解耦、异步、削峰
- 解耦:A系统发送数据到BCD三个系统,通过接口调用发送。如果此时E系统也想要这个数据呢?C系统不想要这个数据了呢?A系统的负责人直接崩溃,因为现在A系统跟其他各种乱七八糟的系统严重耦合在了一起。A系统产生了一条比较关键的数据,很多系统都需要A系统将这个数据发送过来。如果使用MQ,A系统将这条数据发送到MQ里去,哪个系统需要数据自己就去MQ里消费,哪个系统不需要这条数据了,就取消对MQ消息的消费。这样下来,A系统就不用去考虑给谁发送数据了,不需要维护这个代码,也不用考虑别的系统是否调用成功、失败超时等情况。核心思想就是舍弃同步调用其他接口,使用MQ异步化解耦。
- 异步:A系统接收到一个请求,需要在自己本地写库,还需要在BCD三个系统写库。自己本地写库要3ms,BCD三个系统分别写库要300ms、400ms、500ms。最终总延时接近1.2s,给用户的体验极差。用户通过浏览器发起请求,如果使用MQ,假如A系统连续发送3条消息到MQ队列中耗时5ms,那么A系统从接受一个请求到返回响应给用户,总时长是3 + 5 = 8ms
- 削峰:减少高峰时期对服务器的压力
MQ有什么优缺点
点击展开
- 优点:解耦、异步、削峰
- 缺点如下:
系统可用性降低:系统引入的外部依赖越多,越容易挂掉,万一MQ挂了,那么整套系统都崩溃了。
系统复杂度提高:硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?
一致性问题:A系统处理完了直接返回成功了,用户就真的以为你这个请求成功了。但是问题是:要是BCD三个系统里,BC两个系统写库成功了,D系统写库失败了,那么此时数据就会出现不一致性问题。
如何保证消息传输的可靠传输?消息丢失怎么办?
点击展开
- 首先这个消息丢失,有三处都可能发生
- 生产者丢失:生产者将数据发送到RabbitMQ的时候,由于网络的原因,可能数据半路就丢了。此时可以选择使用RabbitMQ提供的事务功能,就是生产者发送数据之前开启RabbitMQ事务channel.txSelect,然后发送消息,如果消息没有被RabbitMQ接收到,那么生产者会收到异常报错,此时可以回滚事务channel.txRollback,然后重试发送消息;如果收到了消息,那么可以提交事务channel.txCommit。吞吐量会下来,因为太耗性能。所以一般来说,如果你要确保写RabbitMQ的消息别丢,在生产者那里设置开启confirm模式,每次写消息都会分配一个唯一id,如果写入了RabbitMQ中,RabbitMQ会给你回传一个ack消息,告诉你说这个消息ok了。如果RabbitMQ没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息id的状态,如果超过一定时间没有接收到这个消息的回调,那么你可以重发。 还有一种方案是 发消息前先将消息存到生产者消息表中。发送成功后记录状态。这样即使发送失败了,也可以重新发送
- MQ中丢失:这种情况必须开启RabbitMQ的持久化,就是消息写入之后会持久化到硬盘,哪怕RabbitMQ自己挂了,恢复之后也会自动读取之前存储的数据,一般数据不会丢失。设置持久化有两个步骤:第一个是创建queue的时候将其设置为持久化,这样可以保证RabbitMQ持久化queue的元数据,但是不会持久化queue里的数据。第二个是发送消息的时候,将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时RabbitMQ就会将消息持久化到磁盘上去。必须同时设置这两个持久化才行,
- 消费端丢失:消费的时候,刚消费到,还没处理,此时服务挂了,服务重启了,那么就尴尬了,RabbitMQ人为你消费了,这数据就丢了。这个时候需要使用RabbitMQ提供的ack机制,简单来说就是,关闭RabbitMQ的自动ack,然后在服务处理消息完毕后再手动ack,这样的话,如果消息还没处理完,那么就不会ack,消息就不会丢了。
如何保证消息的顺序性
点击展开
一个队列 只有一个消费者(Consumer ) 不能并发消费或者 一个队列对应多个消费者
消息在MQ里积压,该如何解决?
点击展开
- 消息挤压的本质是:生产速度 > 消费速度 。首先看挤压的消息数据 是否特别多
- 挤压不是很多: 增加消费者Consumer 的数量 并行消费
- 挤压特别多: 紧急扩容
- 第一步 排查消费者Consumer 是否有问题。确保消费者可以正常消费 - 第二步 将消费者紧急停止。不在消费 - 第三步 创建一个新的交换机(topic),队列(queue)数量需要比原来多。最好是倍数 - 第四步 将原本挤压的消息 轮询发到新的队列中 - 第五步 创建多个消费者去处理挤压消息
MQ中规定消息过期失效了怎么办?
点击展开
- 使用死信队列
- 什么是死信队列:门存放处理失败 / 过期 / 被拒绝消息的兜底队列
- MQ消息过期后会进入死信队列。死信队列中删除。则这条消息彻底丢失在MQ中
1
正常队列 → 过期 → 死信队列
- 发消息前记录消息到数据库中 即使死信队列中删除了也可以补偿回来
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Little Monste'Blog!
评论






