消息队列面试题

为什么使用MQ

 

解耦,异步,削峰

MQ优缺点

系统可用性降低

系统复杂度提高

一致性问题

KafkaActiveMQRabbitMQRocketMQ 都有什么区别?

直接看功能支持那一栏

小公司用RabbitMq延时性低,非分布式的,大公司用rokectmq吞吐量高,分布式的

kafka分布式的,功能较简单,大数据领域实时计算以及日志采集被大规模使用

RabbitMQ如何保证高可用的?

RabbitMQ基于主从(非分布式)做高可用性的,

RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式
单机模式:
没人生产用单机模式
普通集群模式:
缺点:1.可能会在RabbitMQ集群内部产生大量的数据传输
           2.可用性几乎没有什么保障,如果queue所在的节点宕机了,就导致queue的数据丢失了,你就没办法消费了
创建的queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。你消费的时候,实际上如果连接到了queue不在的实例,那么那个实例会从 queue 所在实例上拉取数据过来
镜像集群模式:
优点:才是所谓的 RabbitMQ 的高可用模式,你任何一个机器宕机了,没事儿,其它机器节点还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据
坏处:不是分布式的,如果这个queue的数据量很大,导致网络带宽压力和消耗很重
创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上
RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点

RabbitMQ,Kafka如何保证消息不重复(面试题)

比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了, update 一下好吧。
比如你是做redis的set的操作, 天然幂等性。
如果上面两种情况还不行,准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

RabbitMQ如何保证消息不丢失(面试题)

数据的丢失问题,可能出现在生产者、MQ、消费者中

生产者丢失:生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,因为网络问题啥的,都有可能。

就是生产者发送数据之前开启 RabbitMQ 事务channel.txSelect,然后发送消息,如果消息没有成功被 RabbitMQ 接收到,那么生产者会收到异常报错,此时就可以回滚事务channel.txRollback,然后重试发送消息;如果收到了消息,那么可以提交事务channel.txCommit。吞吐量会下来,因为太耗性能。同步的

可以开启confirm模式,在生产者那里设置开启confirm模式之后,你每次写的消息都会分配一个唯一的 id,然后如果写入了 RabbitMQ 中,RabbitMQ 会给你回传一个ack消息,告诉你说这个消息 ok 了。如果 RabbitMQ 没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,你可以重试,异步的

MQ 中丢失:就是 RabbitMQ 自己弄丢了数据,这个你必须开启 RabbitMQ 的持久化,就是消息写入之 后会持久化到磁盘,哪怕是 RabbitMQ 自己挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢。
设置持久化有两个步骤:
第一个是将queue的持久化标识durable设置为true,则代表是一个持久的队列 这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是不会持久化 queue 里的数据。
第二个是发送消息的时候将消息的 deliveryMode 设置为 2 ,就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。必须要同时设置这两个持久化才行,RabbitMQ 哪怕是挂了,再次重启,也会从磁盘上重启恢复 queue,恢复这个 queue 里的数据。
持久化可以跟生产者那边的 confifirm 机制配合起来,只有消息被持久化到磁盘之后,才会通知生产者ack 了,所以哪怕是在持久化到磁盘之前, RabbitMQ 挂了,数据丢了,生产者收不到ack ,你也是可以自己重发的。注意,哪怕是你给 RabbitMQ 开启了持久化机制,也有一种可能,就是这个消息写到了 RabbitMQ 中,但是还没来得及持久化到磁盘上,结果不巧,此时 RabbitMQ 挂了,就会导致内存里的一点点数据丢失。

消费端丢失:你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,
RabbitMQ 认为你都消费了,这数据就丢了

启用手动确认ack模式可以解决这个问题

简单来说,就是你关闭 RabbitMQ 的自动ack,可以通过一个 api 来调用就行,然后每次你自己代码里确保处理完的时候,再在程序里ack一把,

手动确认模式,如果消费者来不及处理就死掉时,没有响应ack时会重复发送一条信息给其他消费者;如果监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛异常;如果对异常进行了捕获,但是没有在finally里ack,也会一直重复发送消息(重试机制)。

如何保证消息的顺序性

RabbitMQ:同一个queue里的消息一定是顺序消息的

一个 queue,多个 consumer保证一个 queue,一个 consumer,然后这个消费者内部用内存队列做排队,保证顺序性

或者拆分成多个queue,生产者保证顺序性

消息积压如何处理

临时紧急扩容:
然后将现有 cnosumer 都停掉
新建一个 topic partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue
等快速消费完积压数据之后,重新用原先的 consumer 机器来消费消息。

MQ中消息失效如何处理

假设你用的是 RabbitMQ RabbtiMQ 是可以设置过期时间的,也就是 TTL 。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。
就是批量重导,就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如晚上12 点以后,用户都睡觉了。这个时候我们就开始写程序
将丢失的那批数据,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。
假设 1 万个订单积压在 mq 里面,没有处理,其中 1000个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq

mq消息队列块满了如何处理

临时写一个consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入 queue。
然后走第二个方案,将丢失的那批数据,一点一点的查出来,然后重新灌入 mq 里面去。

        

Kafka如何保证高可用的?

后面有问到再补充ba

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值