参考:
MetaQ消息的可靠性、顺序和重复:https://github.com/killme2008/Metamorphosis/wiki/%E6%B6%88%E6%81%AF%E7%9A%84%E5%8F%AF%E9%9D%A0%E6%80%A7%E3%80%81%E9%A1%BA%E5%BA%8F%E5%92%8C%E9%87%8D%E5%A4%8D
MetaQ中间件原理 https://www.jianshu.com/p/b09bd8e8ee50
消息队列面试题: https://zhuanlan.zhihu.com/p/66424258
面试题:https://www.jianshu.com/p/88a4da652e23
https://blog.csdn.net/xy3233/article/details/95966230
MQ基础: 参考: https://blog.csdn.net/wqc19920906/article/details/82193316
- 消息中间件组成
①Broker 消息服务器 ②Producer 消息生产者 ③Consumer 消息消费者 ④Topic主题 ⑤Queue队列 ⑥Message 消息体 - 消息中间件模式
①点对点
消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。消息被消费以后,queue中不再存储,所以消息消费者不可能消费到已经被消费的消息。
② 发布/订阅
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。 - 使用消息中间件的优势
①解耦
②异步 提高系统响应时间 响应时间要求不高的可以放在消息队列里,让消费者去处理
③削峰 并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常
面试题:
-
RabbitMQ怎么处理消息丢失情况?
①生产者丢失
transaction(事务):开启事务 发送失败会回滚 ,吞吐量下降
confirm(返回值):rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),发送失败,会发送一个Nack消息给你
②服务器丢失
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
③消费者丢失
启用手动确认模式可以解决这个问题 -
MetaQ怎么处理消息丢失情况?
①生产者丢失
消息生产者发送消息后返回SendResult,如果isSuccess返回为true,表示消息已经被接收了
②服务器丢失
metaQ服务器收到后在做必要的校验和检查之后的第一件事就是写入磁盘,写入成功后才回复生产者
持久化磁盘可配置项,一千条或者每隔10秒强制写一次磁盘,断电最多10秒或者1000条消息丢失
MetaQ服务器集群
③消费者丢失
a,消费成功之后才会消费下一条,失败重试,五次之后依然失败的消息存在本地,然后由后台线程继续尝试
b,主线程继续消费后续消息,因此只有在MessageListener确认成功消费一条消息后,才会消费下一条消息
c,offset的存储,也就是拉取数据的偏移量 -
RabbitMQ怎么保证消息重复消费,或者重复投递?
a,重复投递: MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;
b,重复消费:要求消息体有一个bizId(业务ID全局唯一),作为去重和幂等的依据 -
MetaQ怎么保证消息重复消费,或者重复投递?
a,重复投递
生产者发送消息,发送成功,但因为网络等故障没有接收到确认消息,就会再发一条,这种由故障引起的重复,MetaQ无法避免
b,重复消费
因故障引起的重复消费,也没办法,最好就是加一个全局的业务ID -
怎么保证消息传递的顺序性?
RabbitMQ保证消息的顺序性: 拆分成多个Queue,保证一个生产者对一个消费者
MetaQ: 正常情况下,谁先进入队列谁先被消费,前提是消息发往同一机器同一分区 -
大量消息在 MQ 里长时间积压,该如何解决?
a,有设置过期时间的,到期会自动过期
b,内存满了,新数据无法产生
解决方案: 1:恢复Consumer的消费速度
2,扩容,消费者扩容,队列容量扩容
3,消息丢掉,高峰过后再导进去重新消费 -
有几种数据保留的策略?
交换器的持久化(交换器元数据丢失),队列的持久化, 消息的持久化
常用的持久化方式:
持久化到DB 就是普通的数据库
持久化到KV存储,如levelDB,伯克利DB,redis
持久化到文件 文件系统中
存储效率来说,文件系统 > 分布式 KV 存储 > 关系型数据库 DB -
MQ服务器高可用如何配置 RabbitMQ 的集群
有三种模式:单机模式、普通集群模式、镜像集群模式。
单机模式,就是 Demo 级别的,一般就是你本地启动了玩玩儿的?,没人生产用单机模式
普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的 queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。镜像集群模式:这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息需要同步到所有机器上,导致网络带宽压力和消耗很重!RabbitMQ 一个 queue 的数据都是放在一个节点里的,镜像集群下,也是每个节点都放这个 queue 的完整数据。