写点什么

消息队列面试题及答案,大 V 推荐

用户头像
极客good
关注
发布于: 刚刚

优点在于你任何一个实例宕机了,没事儿,别的实例都可以用。缺点在于性能开销太大和扩展性很低,同步所有实例,这会导致网络带宽和压力很重,而且扩展性很低,每增加一个实例都会去包含已有的 queue 的所有数据,并没有办法线性扩展 queue。


开启镜像集群模式可以去 RabbitMQ 的管理控制台去增加一个策略,指定要求数据同步到所有节点的,也可以要求就同步到指定数量的节点,然后你再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。


(二)Kafka


Kafka 天生就是一个分布式的消息队列,它可以由多个 broker 组成,每个 broker 是一个节点;你创建一个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。


kafka 0.8 以前,是没有 HA 机制的,就是任何一个 broker 宕机了,那个 broker 上的 partition 就废了,没法写也没法读,没有什么高可用性可言。


kafka 0.8 以后,提供了 HA 机制,就是 replica 副本机制。kafka 会均匀的将一个 partition 的所有 replica 分布在不同的机器上,来提高容错性。每个 partition 的数据都会同步到吉他机器上,形成自己的多个 replica 副本。然后所有 replica 会选举一个 leader 出来,那么生产和消费都去 leader,其他 replica 就是 follower,leader 会同步数据给 follower。当 leader 挂了会自动去找 replica,然后会再选举一个 leader 出来,这样就具有高可用性了。


写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)


消费的时候,只会从 leader 去读,但是只有一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。

4、如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

其实消息重复消费的主要原因在于回馈机制(RabbitMQ 是 ack,Kafka 是 offset),在某些场景中我们采用的回馈机制不同,原因也不同,例如消费者消费完消息后回复 ack, 但是刚消费完还没来得及提交系统就重启了,这时候上来就 pull 消息的时候由于没有提交 ack 或者 offset,消费的还是上条消息。


那么如何怎么来保证消息消费的幂等性呢?实际上我们只要保证多条相同的数据过来的时候只处理一条或者说多条处理和处理一条造成的结果相同即可,但是具体怎么做要根据业务需求来定,例如入库消息,先查一下消息是否已经入库啊或者说搞个唯一约束啊什么的,还有一些是天生保证幂等性就根本不用去管,例如 redis 就是天然幂等性。


还有一个问题,消费者消费消息的时候在某些场景下要放过消费不了的消息,遇到消费不了的消息通过日志记录一下或者搞个什么措施以后再来处理,但是一定要放过消息,因为在某些场景下例如 spring-rabbitmq 的默认回馈策略是出现异常就没有提交 ack,导致了一直在重发那条消费异常的消息,而且一直还消费不了,这就尴尬了,后果你会懂的。

5、如何保证消息的可靠性传输?或者说,如何处理消息丢失的问题?

参考:[https://www.jianshu.com/p/06e7e3b34dd6](


)

6、如何保证消息的顺序性?

因为在某些情况下我们扔进 MQ 中的消息是要严格保证顺序的,尤其涉及到订单什么的业务需求,消费的时候也是要严格保证顺序,不然会出大问题的。


先看看顺序会错乱的两个场景:


  • rabbitmq:一个 queue,多个 consumer,这不明显乱了

  • kafka:一个 topic,一个 partition,一个 consumer,内部多线程,这不也明显乱了

7、如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时怎么解决?

(一)、大量消息在 mq 里积压了几个小时了还没解决


几千万条数据在 MQ 里积压了七八个小时,从下午 4 点多,积压到了晚上很晚,10 点多,11 点多


这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复 consumer 的问题,让他恢复消费速度,然后傻傻的等待几个小时消费完毕。这个肯定不能在面试的时候说吧。


一个消费者一秒是 1000 条,一秒 3 个消费者是 3000 条,一分钟是 18 万条,1000 多万条,所以如果你积压了几百万到上千万的数据,即使消费者恢复了,也需要大概 1 小时的时间才能恢复过来。


一般这个时候,只能操作临时紧急扩容了,具体操作步骤和思路如下:


  1. 先修复 consumer 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉。

  2. 新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍或者 20 倍的 queue 数量。

  3. 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue。

  4. 接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。

  5. 这种做法相当于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。

  6. 等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的 consumer 机器来消费消息。


(二)、消息队列过期失效问题


假设你用的是 rabbitmq,rabbitmq 是可以设置过期时间的,就是 TTL,如果消息在 queue 中积压超过一定的时间就会被 rabbitmq 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。


这个情况下,就不是说要增加 consumer 消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上 12 点以后,用户都睡觉了。


这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。


假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。


(三)、消息队列满了怎么搞?


如果走的方式是消息积压在 mq 里,那么如果你很长时间都没处理掉,此时导致 mq 都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


后走第二个方案,到了晚上再补数据吧。

9、RabbitMQ 有哪些重要的角色?

10、RabbitMQ 有哪些重要的组件?

11、RabbitMQ 有几种广播类型?

三种广播模式:


  1. fanout: 所有 bind 到此 exchange 的 queue 都可以接收消息(纯广播,绑定到 RabbitMQ 的接受者都能收到消息);

  2. direct: 通过 routingKey 和 exchange 决定的那个唯一的 queue 可以接收消息;

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
消息队列面试题及答案,大V推荐