面试题剖析:如何保证 “消息队列” 的高可用?

554 阅读13分钟

01 面试官心理分析

如果有人问到你MQ的知识,高可用是必问的。因为 MQ 会导致系统可用性降低,所以只要你用了MQ,接下来问的一些要点肯定就是围绕着MQ的那些缺点怎么来解决了。

要是你傻乎乎的就干用了一个MQ,各种问题从来没考虑过,那你就杯具了,面试官对你的感觉就是,只会简单使用一些技术,没任何思考,马上对你的印象就不太好了。这样的同学招进来要是做个20k薪资以内的普通小弟还凑合,要是做薪资20k+的高工,那就惨了,让你设计个系统,里面肯定一堆坑,出了事故公司受损失,团队一起背锅。

02 面试题剖析:如何保证 “消息队列” 的高可用?

这个问题这么问是很好的,因为不能问你Kafka高可用性怎么保证?ActiveMQ 高可用性怎么保证?一个面试官要是这么问就显得很没水平,人家可能用的就是RabbitMQ,没用过Kafka,你上来问人家Kafka干什么?这不是摆明了刁难人么...

所以有水平的面试官,问的是MQ的高可用性怎么保证?这样就是你用过哪个MQ,你就说说你对哪个MQ的高可用性的理解。

题目来源:《Java高级程序员面试指南--消息队列篇》,从“面试官心理分析”到“面试题剖析”,一步一步深入解析!如需参考这份面试指南→请看原件

2.1 RabbitMQ的高可用性

RabbitMQ是比较有代表性的,因为是基于主从(非分布式〉做高可用性的,我们就以RabbitMQ为例子讲解第一种 MQ的高可用性怎么实现。

RabbitMQ有三种模式:单机模式、普通集群模式、镜像集群模式。

单机模式

单机模式,就是 Demo级别的,一般就是你本地启动了玩玩儿的。

普通集群模式(无高可用性)

普通集群模式,意思就是在多台机器上启动多个 RabbitMQ实例,每个机器启动一个。你创建的queue,只会放在一个RabbitMQ实例上,但是每个实例都同步queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到queue 所在实例)。你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。

这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通的集群。因为这导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个queue所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。

而且如果那个放 queue 的实例宕机了,会导致接下来其他实例就无法从那个实例拉取,如果你开启了消息持久化,让 RabbitMQ落地存储消息的话,消息不一定会丢,得等这个实例恢复了,然后才可以继续从这个queue拉取数据。

所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个queue的读写操作。

镜像集群模式(高可用性)

这种模式,才是所谓的RabbitNQ的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论是元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个RabbitMQ节点都有这个queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的queue 上。

那么如何开启这个镜像集群模式呢﹖其实很简单,RabbitMQ有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。

这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个queue 的完整数据,别的 consumer都可以到其它节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息需要同步到所有机器上,导致网络带宽压力和消耗很重!第二,这么玩儿,不是分布式的,就没有扩展性可言了,如果某个queue 负载很重,你加机器,新增的机器也包含了这个queue 的所有数据,并没有办法线性扩展你的 queue。你想,如果这个queue 的数据量很大,大到这个机器上的容量无法容纳了,此时该怎么办呢?

2.2 Kafka的高可用性

Kafka一个最基本的架构认识:由多个broker组成,每个 broker 是一个节点;你创建一个topic,这个topic可以划分为多个 partition,每个partition可以存在于不同的 broker 上,每个partition 就放一部分数据。

这就是天然的分布式消息队列,就是说一个topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。

实际上 RabbmitMQ之类的,并不是分布式消息队列,它就是传统的消息队列,只不过提供了一些集群、HA(High Availability,高可用性)的机制而已,因为无论怎么玩儿,RabbitMQ一个queue 的数据都是放在一个节点里的,镜像集群下,也是每个节点都放这个queue 的完整数据。

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

比如说,我们假设创建了一个topic,指定其 partition数量是3个,分别在三台机器上。但是,如果第二台机器宕机了,会导致这个topic 的 1/3的数据就丢了,因此这个是做不到高可用的。

Kafka 0.8 以后,提供了HA 机制,就是 replica(复制品)副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个replica副本。所有 replica 会选举一个leader出来,那么生产和消费都跟这个leader打交道,然后其他replica 就是 follower。写的时候,leader会负责把数据同步到所有 follower 上去,读的时候就直接读leader 上的数据即可。只能读写leader?很简单,要是你可以随意读写每个follower,那么就要care数据一致性的问题,系统复杂度太高,很容易出问题。Kafka 均匀地将一个partition 的所有 replica 分布在不同的机器上,这样才可以提高容错性。

这么搞,就有所谓的高可用性了,因为如果某个broker宕机了,没事儿,那个broker上面的 partition在其他机器上都有副本的。如果这个宕机的 broker 上面有某个 partition 的 leader,那么此时会从follower中重新选举一个新的 leader出来,大家继续读写那个新的 leader即可。这就有所谓的高可用性了。

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

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

看到这里,相信你大致明白了Kafka是如何保证高可用机制的了,对吧?不至于一无所知,现场还能给面试官画画图。要是遇上面试官确实是Kafka高手,深挖了问,那你只能说不好意思,太深入的你没研究过。

03 此外关于kafka面试

整理了44道面试官最爱问的kafka面试题,从基础-进阶-高级,分类整理,先看题目...

这里给出了全部的题目,关于答案解析,内容偏多(我将其整理成31页的PDF文档),篇幅有限,只截图展现部分答案解析,如需参考完整的kafka44问解析文档原件→【请看答案】

kafka基础面试题(17道)

  1. Kafka的用途有哪些?使用场景如何?

  2. Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么

  3. Kafka中的HW、LEO、LSO、LW等分别代表什么?

  4. Kafka中是怎么体现消息顺序性的?

  5. Kafka中的分区器、序列化器、拦截器是否了解?它们之间的处理顺序是什么?

  6. Kafka生产者客户端的整体结构是什么样子的?

  7. Kafka生产者客户端中使用了几个线程来处理?分别是什么?

  8. Kafka的旧版Scala的消费者客户端的设计有什么缺陷?

  9. “消费组中的消费者个数如果超过topic的分区,那么就会有消费者消费不到数据”这句话是否正确?如果正确,那么有没有什么hack的手段?

  10. 有哪些情形会造成重复消费?

  11. 哪些情景下会造成消息漏消费?

  12. KafkaConsumer是非线程安全的,那么怎么样实现多线程消费?

  13. 简述消费者与消费组之间的关系

  14. 当你使用kafka-topics.sh创建(删除)了一个topic之后,Kafka背后会执行什么逻辑?

  15. topic的分区数可不可以增加?如果可以怎么增加?如果不可以,那又是为什么?

  16. topic的分区数可不可以减少?如果可以怎么减少?如果不可以,那又是为什么?

  17. 创建topic时如何选择合适的分区数?

kafka进阶面试题(15道)

  1. Kafka目前有哪些内部topic,它们都有什么特征?各自的作用又是什么?

  2. 优先副本是什么?它有什么特殊的作用?

  3. Kafka有哪几处地方有分区分配的概念?简述大致的过程及原理

  4. 简述Kafka的日志目录结构

  5. Kafka中有哪些索引文件?

  6. 如果我指定了一个offset,Kafka怎么查找到对应的消息?

  7. 如果我指定了一个timestamp,Kafka怎么查找到对应的消息?

  8. 聊一聊你对Kafka的Log Retention的理解

  9. 聊一聊你对Kafka的Log Compaction的理解

  10. 聊一聊你对Kafka底层存储的理解

  11. 聊一聊Kafka的延时操作的原理

  12. 聊一聊Kafka控制器的作用

  13. Kafka的旧版Scala的消费者客户端的设计有什么缺陷?

  14. 消费再均衡的原理是什么?(提示:消费者协调器和消费组协调器)

  15. Kafka中的幂等是怎么实现的?

kafka高级面试题(12道)

  1. Kafka中的事务是怎么实现的?

  2. 失效副本是指什么?有哪些应对措施?

  3. 多副本下,各个副本中的HW和LEO的演变过程

  4. Kafka在可靠性方面做了哪些改进?(HW, LeaderEpoch)

  5. 为什么Kafka不支持读写分离?

  6. Kafka中的延迟队列怎么实现

  7. Kafka中怎么实现死信队列和重试队列?

  8. Kafka中怎么做消息审计?

  9. Kafka中怎么做消息轨迹?

  10. 怎么计算Lag?(注意read_uncommitted和read_committed状态下的不同)

  11. Kafka有哪些指标需要着重关注?

  12. Kafka的哪些设计让它有如此高的性能?

04 最后RabbitMQ专题

RabbitMQ面试

整理了24道RabbitMQ面试问题(附答案)

  1. RabbitMQ 中的 broker 是指什么?cluster 又是指什么?

  2. 什么是元数据?元数据分为哪些类型?包括哪些内容?与 cluster 相关的元数据有哪些?元数据是如何保存的?元数据在 cluster 中是如何分布的?

  3. RAM node 和 disk node 的区别?

  4. RabbitMQ 上的一个 queue 中存放的 message 是否有数量限制?

  5. RabbitMQ 概念里的 channel、exchange 和 queue 这些东东是逻辑概念,还是对应着进程实体?这些东东分别起什么作用?

  6. vhost 是什么?起什么作用?

  7. 在单 node 系统和多 node 构成的 cluster 系统中声明 queue、exchange ,以及进行 binding 会有什么不同?

  8. 8. 客户端连接到 cluster 中的任意 node 上是否都能正常工作?

  9. 若 cluster 中拥有某个 queue 的 owner node 失效了,且该 queue 被声明具有durable 属性,是否能够成功从其他 node 上重新声明该 queue ?

  10. cluster 中 node 的失效会对 consumer 产生什么影响?若是在 cluster 中创建了mirrored queue ,这时 node 失效会对 consumer 产生什么影响?

  11. 能够在地理上分开的不同数据中心使用 RabbitMQ cluster 么?

  12. 为什么 heavy RPC 的使用场景下不建议采用 disk node ?

  13. 向不存在的 exchange 发 publish 消息会发生什么?向不存在的 queue 执行consume 动作会发生什么?

  14. routing_key 和 binding_key 的最大长度是多少?

  15. RabbitMQ 允许发送的 message 最大可达多大?

  16. 什么情况下 producer 不主动创建 queue 是安全的?

  17. “dead letter”queue 的用途?

  18. 为什么说保证 message 被可靠持久化的条件是 queue 和 exchange 具有durable 属性,同时 message 具有 persistent 属性才行?

  19. 什么情况下会出现 blackholed 问题?

  20. 如何防止出现 blackholed 问题?

  21. Consumer Cancellation Notification 机制用于什么场景?

  22. Basic.Reject 的用法是什么?

  23. 为什么不应该对所有的 message 都使用持久化机制?

  24. RabbitMQ 中的 cluster、mirrored queue,以及 warrens 机制分别用于解决什么问题?存在哪些问题?

RabbitMQ架构大纲(学习路线图)

这是手绘版的(xmind文件),原件无法上传,这里用的图片...

但无论是面试文档pdf还是这路线图xmind,若你需要参考学习→【请看原件