You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
23 KiB
Markdown

2 years ago
# 特别放送(四)| 20道经典的Kafka面试题详解
你好我是胡夕。这一期的“特别放送”我想跟你分享一些常见的Kafka面试题。
无论是作为面试官还是应聘者我都接触过很多Kafka面试题。有的题目侧重于基础的概念考核有的关注实际场景下的解决方案有的属于“炫技式”有的可算是深入思考后的“灵魂拷问”。“炫技”类的问题属于冷门的Kafka组件知识考核而“灵魂拷问”类的问题大多是对Kafka设计原理的深入思考有很高的技术难度。
每类题目的应对方法其实不太一样。今天我就按照这4种类别具体讲解20道面试题。不过我不打算只给出答案我会把面试题的考核初衷也一并写出来。同时我还会给你分享一些面试小技巧希望能够帮你更顺利地获取心仪的offer。
那么,话不多说,我们现在开始吧。
## 基础题目
### 1.Apache Kafka是什么
这是一道很常见的题目,看似很无聊,其实考核的知识点很多。
首先它考验的是你对Kafka的定位认知是否准确。Apache Kafka一路发展到现在已经由最初的分布式提交日志系统逐渐演变成了实时流处理框架。因此这道题你最好这么回答**Apach Kafka是一款分布式流处理框架用于实时构建流处理应用。它有一个核心的功能广为人知即作为企业级的消息引擎被广泛使用。**
其实这里暗含了一个小技巧。Kafka被定位为实时流处理框架在国内的接受度还不是很高因此在回答这道题的时候你一定要先明确它的流处理框架地位这样能给面试官留下一个很专业的印象。
### 2.什么是消费者组?
从某种程度上说这可是个“送命题”。消费者组是Kafka独有的概念如果面试官问这个就说明他对此是有一定了解的。我先给出标准答案**关于它的定义官网上的介绍言简意赅即消费者组是Kafka提供的可扩展且具有容错性的消费者机制。**切记,一定要加上前面那句,以显示你对官网很熟悉。
另外,你最好再解释下消费者组的原理:**在Kafka中消费者组是一个由多个消费者实例构成的组。多个实例共同订阅若干个主题实现共同消费。同一个组下的每个实例都配置有相同的组ID被分配不同的订阅分区。当某个实例挂掉的时候其他实例会自动地承担起它负责消费的分区。**
此时,又有一个小技巧给到你:消费者组的题目,能够帮你在某种程度上掌控下面的面试方向。
* 如果你擅长**位移值原理**,就不妨再提一下消费者组的位移提交机制;
* 如果你擅长Kafka **Broker**可以提一下消费者组与Broker之间的交互
* 如果你擅长与消费者组完全不相关的**Producer**那么就可以这么说“消费者组要消费的数据完全来自于Producer端生产的消息我对Producer还是比较熟悉的。”
使用这个策略的话,面试官可能会被你的话术所影响,偏离他之前想问的知识路径。当然了,如果你什么都不擅长,那就继续往下看题目吧。
### 3.在Kafka中ZooKeeper的作用是什么
这是一道能够帮助你脱颖而出的题目。碰到这个题目,请在心中暗笑三声。
先说标准答案:**目前Kafka使用ZooKeeper存放集群元数据、成员管理、Controller选举以及其他一些管理类任务。之后等KIP-500提案完成后Kafka将完全不再依赖于ZooKeeper。**
记住,**一定要突出“目前”**以彰显你非常了解社区的演进计划。“存放元数据”是指主题分区的所有数据都保存在ZooKeeper中且以它保存的数据为权威其他“人”都要与它保持对齐。“成员管理”是指Broker节点的注册、注销以及属性变更等等。“Controller选举”是指选举集群Controller而其他管理类任务包括但不限于主题删除、参数配置等。
不过抛出KIP-500也可能是个双刃剑。碰到非常资深的面试官他可能会进一步追问你KIP-500是做的。一言以蔽之**KIP-500思想是使用社区自研的基于Raft的共识算法替代ZooKeeper实现Controller自选举**。你可能会担心,如果他继续追问的话,该怎么办呢?别怕,在下一期“特别发送”,我会专门讨论这件事。
### 4.解释下Kafka中位移offset的作用
这也是一道常见的面试题。位移概念本身并不复杂,你可以这么回答:**在Kafka中每个主题分区下的每条消息都被赋予了一个唯一的ID数值用于标识它在分区中的位置。这个ID数值就被称为位移或者叫偏移量。一旦消息被写入到分区日志它的位移值将不能被修改。**
答完这些之后你还可以把整个面试方向转移到你希望的地方。常见方法有以下3种
* 如果你深谙Broker底层日志写入的逻辑可以强调下消息在日志中的存放格式
* 如果你明白位移值一旦被确定不能修改可以强调下“Log Cleaner组件都不能影响位移值”这件事情
* 如果你对消费者的概念还算熟悉,可以再详细说说位移值和消费者位移值之间的区别。
### 5.阐述下Kafka中的领导者副本Leader Replica和追随者副本Follower Replica的区别
这道题表面上是考核你对Leader和Follower区别的理解但很容易引申到Kafka的同步机制上。因此我建议你主动出击一次性地把隐含的考点也答出来也许能够暂时把面试官“唬住”并体现你的专业性。
你可以这么回答:**Kafka副本当前分为领导者副本和追随者副本。只有Leader副本才能对外提供读写服务响应Clients端的请求。Follower副本只是采用拉PULL的方式被动地同步Leader副本中的数据并且在Leader副本所在的Broker宕机后随时准备应聘Leader副本。**
通常来说回答到这个程度其实才只说了60%,因此,我建议你再回答两个额外的加分项。
* **强调Follower副本也能对外提供读服务**。自Kafka 2.4版本开始社区通过引入新的Broker端参数允许Follower副本有限度地提供读服务。
* **强调Leader和Follower的消息序列在实际场景中不一致**。很多原因都可能造成Leader和Follower保存的消息序列不一致比如程序Bug、网络问题等。这是很严重的错误必须要完全规避。你可以补充下之前确保一致性的主要手段是高水位机制但高水位值无法保证Leader连续变更场景下的数据一致性因此社区引入了Leader Epoch机制来修复高水位值的弊端。关于“Leader Epoch机制”国内的资料不是很多它的普及度远不如高水位不妨大胆地把这个概念秀出来力求惊艳一把。上一季专栏的[第27节课](https://time.geekbang.org/column/article/112118)讲的就是Leader Epoch机制的原理推荐你赶紧去学习下。
## 实操题目
### 6.如何设置Kafka能接收的最大消息的大小
这道题除了要回答消费者端的参数设置之外一定要加上Broker端的设置这样才算完整。毕竟如果Producer都不能向Broker端发送数据很大的消息又何来消费一说呢因此你需要同时设置Broker端参数和Consumer端参数。
* Broker端参数message.max.bytes、max.message.bytes主题级别和replica.fetch.max.bytes。
* Consumer端参数fetch.message.max.bytes。
Broker端的最后一个参数比较容易遗漏。我们必须调整Follower副本能够接收的最大消息的大小否则副本同步就会失败。因此把这个答出来的话就是一个加分项。
### 7.监控Kafka的框架都有哪些
其实目前业界并没有公认的解决方案各家都有各自的监控之道。所以面试官其实是在考察你对监控框架的了解广度或者说你是否知道很多能监控Kafka的框架或方法。下面这些就是Kafka发展历程上比较有名气的监控系统。
* **Kafka Manager**应该算是最有名的专属Kafka监控框架了是独立的监控系统。
* **Kafka Monitor**LinkedIn开源的免费框架支持对集群进行系统测试并实时监控测试结果。
* **CruiseControl**也是LinkedIn公司开源的监控框架用于实时监测资源使用率以及提供常用运维操作等。无UI界面只提供REST API。
* **JMX监控**由于Kafka提供的监控指标都是基于JMX的因此市面上任何能够集成JMX的框架都可以使用比如Zabbix和Prometheus。
* **已有大数据平台自己的监控体系**像Cloudera提供的CDH这类大数据平台天然就提供Kafka监控方案。
* **JMXTool**社区提供的命令行工具能够实时监控JMX指标。答上这一条属于绝对的加分项因为知道的人很少而且会给人一种你对Kafka工具非常熟悉的感觉。如果你暂时不了解它的用法可以在命令行以无参数方式执行一下`kafka-run-class.sh kafka.tools.JmxTool`,学习下它的用法。
### 8.Broker的Heap Size如何设置
如何设置Heap Size的问题其实和Kafka关系不大它是一类非常通用的面试题目。一旦你应对不当面试方向很有可能被引到JVM和GC上去那样的话你被问住的几率就会增大。因此我建议你简单地介绍一下Heap Size的设置方法并把重点放在Kafka Broker堆大小设置的最佳实践上。
比如,你可以这样回复:**任何Java进程JVM堆大小的设置都需要仔细地进行考量和测试。一个常见的做法是以默认的初始JVM堆大小运行程序当系统达到稳定状态后手动触发一次Full GC然后通过JVM工具查看GC后的存活对象大小。之后将堆大小设置成存活对象总大小的1.5~2倍。对于Kafka而言这个方法也是适用的。不过业界有个最佳实践那就是将Broker的Heap Size固定为6GB。经过很多公司的验证这个大小是足够且良好的**。
### 9.如何估算Kafka集群的机器数量
这道题目考查的是**机器数量和所用资源之间的关联关系**。所谓资源也就是CPU、内存、磁盘和带宽。
通常来说CPU和内存资源的充足是比较容易保证的因此你需要从磁盘空间和带宽占用两个维度去评估机器数量。
在预估磁盘的占用时你一定不要忘记计算副本同步的开销。如果一条消息占用1KB的磁盘空间那么在有3个副本的主题中你就需要3KB的总空间来保存这条消息。显式地将这些考虑因素答出来能够彰显你考虑问题的全面性是一个难得的加分项。
对于评估带宽来说常见的带宽有1Gbps和10Gbps但你要切记**这两个数字仅仅是最大值**。因此你最好和面试官确认一下给定的带宽是多少。然后明确阐述出当带宽占用接近总带宽的90%时,丢包情形就会发生。这样能显示出你的网络基本功。
### 10.Leader总是-1怎么破
在生产环境中你一定碰到过“某个主题分区不能工作了”的情形。使用命令行查看状态的话会发现Leader是-1于是你使用各种命令都无济于事最后只能用“重启大法”。
但是,有没有什么办法,可以不重启集群,就能解决此事呢?这就是此题的由来。
我直接给答案:**删除ZooKeeper节点/controller触发Controller重选举。Controller重选举能够为所有主题分区重刷分区状态可以有效解决因不一致导致的Leader不可用问题**。我几乎可以断定,当面试官问出此题时,要么就是他真的不知道怎么解决在向你寻求答案,要么他就是在等你说出这个答案。所以,**千万别一上来就说“来个重启”之类的话**。
## 炫技式题目
### 11.LEO、LSO、AR、ISR、HW都表示什么含义
在我看来,这纯属无聊的炫技。试问我不知道又能怎样呢?!不过既然问到了,我们就统一说一说。
* **LEO**Log End Offset。日志末端位移值或末端偏移量表示日志下一条待插入消息的位移值。举个例子如果日志有10条消息位移值从0开始那么第10条消息的位移值就是9。此时LEO = 10。
* **LSO**Log Stable Offset。这是Kafka事务的概念。如果你没有使用到事务那么这个值不存在其实也不是不存在只是设置成一个无意义的值。该值控制了事务型消费者能够看到的消息范围。它经常与Log Start Offset即日志起始位移值相混淆因为有些人将后者缩写成LSO这是不对的。在Kafka中LSO就是指代Log Stable Offset。
* **AR**Assigned Replicas。AR是主题被创建后分区创建时被分配的副本集合副本个数由副本因子决定。
* **ISR**In-Sync Replicas。Kafka中特别重要的概念指代的是AR中那些与Leader保持同步的副本集合。在AR中的副本可能不在ISR中但Leader副本天然就包含在ISR中。关于ISR还有一个常见的面试题目是**如何判断副本是否应该属于ISR**。目前的判断依据是:**Follower副本的LEO落后Leader LEO的时间是否超过了Broker端参数replica.lag.time.max.ms值**。如果超过了副本就会被从ISR中移除。
* **HW**高水位值High watermark。这是控制消费者可读取消息范围的重要字段。一个普通消费者只能“看到”Leader副本上介于Log Start Offset和HW不含之间的所有消息。水位以上的消息是对消费者不可见的。关于HW问法有很多我能想到的最高级的问法就是让你完整地梳理下Follower副本拉取Leader副本、执行同步机制的详细步骤。这就是我们的第20道题的题目一会儿我会给出答案和解析。
### 12.Kafka能手动删除消息吗
其实Kafka不需要用户手动删除消息。它本身提供了留存策略能够自动删除过期消息。当然它是支持手动删除消息的。因此你最好从这两个维度去回答。
* 对于设置了Key且参数cleanup.policy=compact的主题而言我们可以构造一条<Keynull>的消息发送给Broker依靠Log Cleaner组件提供的功能删除掉该Key的消息。
* 对于普通主题而言我们可以使用kafka-delete-records命令或编写程序调用Admin.deleteRecords方法来删除消息。这两种方法殊途同归底层都是调用Admin的deleteRecords方法通过将分区Log Start Offset值抬高的方式间接删除消息。
### 13.\_\_consumer\_offsets是做什么用的
这是一个内部主题公开的官网资料很少涉及到。因此我认为此题属于面试官炫技一类的题目。你要小心这里的考点该主题有3个重要的知识点你一定要全部答出来才会显得对这块知识非常熟悉。
* 它是一个内部主题无需手动干预由Kafka自行管理。当然我们可以创建该主题。
* 它的主要作用是负责注册消费者以及保存位移值。可能你对保存位移值的功能很熟悉,但其实**该主题也是保存消费者元数据的地方。千万记得把这一点也回答上**。另外,这里的消费者泛指消费者组和独立消费者,而不仅仅是消费者组。
* Kafka的GroupCoordinator组件提供对该主题完整的管理功能包括该主题的创建、写入、读取和Leader维护等。
### 14.分区Leader选举策略有几种
分区的Leader副本选举对用户是完全透明的它是由Controller独立完成的。你需要回答的是在哪些场景下需要执行分区Leader选举。每一种场景对应于一种选举策略。当前Kafka有4种分区Leader选举策略。
* **OfflinePartition Leader选举**每当有分区上线时就需要执行Leader选举。所谓的分区上线可能是创建了新分区也可能是之前的下线分区重新上线。这是最常见的分区Leader选举场景。
* **ReassignPartition Leader选举**当你手动运行kafka-reassign-partitions命令或者是调用Admin的alterPartitionReassignments方法执行分区副本重分配时可能触发此类选举。假设原来的AR是\[123\]Leader是1当执行副本重分配后副本集合AR被设置成\[456\]显然Leader必须要变更此时会发生Reassign Partition Leader选举。
* **PreferredReplicaPartition Leader选举**当你手动运行kafka-preferred-replica-election命令或自动触发了Preferred Leader选举时该类策略被激活。所谓的Preferred Leader指的是AR中的第一个副本。比如AR是\[321\]那么Preferred Leader就是3。
* **ControlledShutdownPartition Leader选举**当Broker正常关闭时该Broker上的所有Leader副本都会下线因此需要为受影响的分区执行相应的Leader选举。
这4类选举策略的大致思想是类似的即从AR中挑选首个在ISR中的副本作为新Leader。当然个别策略有些微小差异。不过回答到这种程度应该足以应付面试官了。毕竟微小差别对选举Leader这件事的影响很小。
### 15.Kafka的哪些场景中使用了零拷贝Zero Copy
Zero Copy是特别容易被问到的高阶题目。在Kafka中体现Zero Copy使用场景的地方有两处**基于mmap的索引**和**日志文件读写所用的TransportLayer**。
先说第一个。索引都是基于MappedByteBuffer的也就是让用户态和内核态共享内核态的数据缓冲区此时数据不需要复制到用户态空间。不过mmap虽然避免了不必要的拷贝但不一定就能保证很高的性能。在不同的操作系统下mmap的创建和销毁成本可能是不一样的。很高的创建和销毁开销会抵消Zero Copy带来的性能优势。由于这种不确定性在Kafka中只有索引应用了mmap最核心的日志并未使用mmap机制。
再说第二个。TransportLayer是Kafka传输层的接口。它的某个实现类使用了FileChannel的transferTo方法。该方法底层使用sendfile实现了Zero Copy。对Kafka而言如果I/O通道使用普通的PLAINTEXT那么Kafka就可以利用Zero Copy特性直接将页缓存中的数据发送到网卡的Buffer中避免中间的多次拷贝。相反如果I/O通道启用了SSL那么Kafka便无法利用Zero Copy特性了。
## 深度思考题
### 16.Kafka为什么不支持读写分离
这道题目考察的是你对Leader/Follower模型的思考。
Leader/Follower模型并没有规定Follower副本不可以对外提供读服务。很多框架都是允许这么做的只是Kafka最初为了避免不一致性的问题而采用了让Leader统一提供服务的方式。
不过,在开始回答这道题时,你可以率先亮出观点:**自Kafka 2.4之后Kafka提供了有限度的读写分离也就是说Follower副本能够对外提供读服务。**
说完这些之后,你可以再给出之前的版本不支持读写分离的理由。
* **场景不适用**。读写分离适用于那种读负载很大而写操作相对不频繁的场景可Kafka不属于这样的场景。
* **同步机制**。Kafka采用PULL方式实现Follower的同步因此Follower与Leader存在不一致性窗口。如果允许读Follower副本就势必要处理消息滞后Lagging的问题。
### 17.如何调优Kafka
回答任何调优问题的第一步,就是**确定优化目标,并且定量给出目标**这点特别重要。对于Kafka而言常见的优化目标是吞吐量、延时、持久性和可用性。每一个方向的优化思路都是不同的甚至是相反的。
确定了目标之后还要明确优化的维度。有些调优属于通用的优化思路比如对操作系统、JVM等的优化有些则是有针对性的比如要优化Kafka的TPS。我们需要从3个方向去考虑。
* **Producer端**增加batch.size、linger.ms启用压缩关闭重试等。
* **Broker端**增加num.replica.fetchers提升Follower同步TPS避免Broker Full GC等。
* **Consumer**增加fetch.min.bytes等
### 18.Controller发生网络分区Network PartitioningKafka会怎么样
这道题目能够诱发我们对分布式系统设计、CAP理论、一致性等多方面的思考。不过针对故障定位和分析的这类问题我建议你首先言明“实用至上”的观点即不论怎么进行理论分析永远都要以实际结果为准。一旦发生Controller网络分区那么第一要务就是查看集群是否出现“脑裂”即同时出现两个甚至是多个Controller组件。这可以根据Broker端监控指标ActiveControllerCount来判断。
现在我们分析下一旦出现这种情况Kafka会怎么样。
由于Controller会给Broker发送3类请求即LeaderAndIsrRequest、StopReplicaRequest和UpdateMetadataRequest因此一旦出现网络分区这些请求将不能顺利到达Broker端。这将影响主题的创建、修改、删除操作的信息同步表现为集群仿佛僵住了一样无法感知到后面的所有操作。因此网络分区通常都是非常严重的问题要赶快修复。
### 19.Java Consumer为什么采用单线程来获取消息
在回答之前,如果先把这句话说出来,一定会加分:**Java Consumer是双线程的设计。一个线程是用户主线程负责获取消息另一个线程是心跳线程负责向Kafka汇报消费者存活情况。将心跳单独放入专属的线程能够有效地规避因消息处理速度慢而被视为下线的“假死”情况。**
单线程获取消息的设计能够避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操作算子。因为很多实时流处理操作算子都不能是阻塞式的。另外一个可能的好处是,可以简化代码的开发。多线程交互的代码是非常容易出错的。
### 20.简述Follower副本消息同步的完整流程
首先Follower发送FETCH请求给Leader。接着Leader会读取底层日志文件中的消息数据再更新它内存中的Follower副本的LEO值更新为FETCH请求中的fetchOffset值。最后尝试更新分区高水位值。Follower接收到FETCH响应之后会把消息写入到底层日志接着更新LEO和HW值。
Leader和Follower的HW值更新时机是不同的Follower的HW更新永远落后于Leader的HW。这种时间上的错配是造成各种不一致的原因。
好了,今天的面试题分享就先到这里啦。你有遇到过什么经典的面试题吗?或者是有什么好的面试经验吗?
欢迎你在留言区分享。如果你觉得今天的内容对你有所帮助,也欢迎分享给你的朋友。