你好,我是胡夕。这一期的“特别放送”,我想跟你分享一些常见的Kafka面试题。
无论是作为面试官,还是应聘者,我都接触过很多Kafka面试题。有的题目侧重于基础的概念考核,有的关注实际场景下的解决方案,有的属于“炫技式”,有的可算是深入思考后的“灵魂拷问”。“炫技”类的问题属于冷门的Kafka组件知识考核,而“灵魂拷问”类的问题大多是对Kafka设计原理的深入思考,有很高的技术难度。
每类题目的应对方法其实不太一样。今天,我就按照这4种类别,具体讲解20道面试题。不过,我不打算只给出答案,我会把面试题的考核初衷也一并写出来。同时,我还会给你分享一些面试小技巧,希望能够帮你更顺利地获取心仪的offer。
那么,话不多说,我们现在开始吧。
这是一道很常见的题目,看似很无聊,其实考核的知识点很多。
首先,它考验的是,你对Kafka的定位认知是否准确。Apache Kafka一路发展到现在,已经由最初的分布式提交日志系统逐渐演变成了实时流处理框架。因此,这道题你最好这么回答:Apach Kafka是一款分布式流处理框架,用于实时构建流处理应用。它有一个核心的功能广为人知,即作为企业级的消息引擎被广泛使用。
其实,这里暗含了一个小技巧。Kafka被定位为实时流处理框架,在国内的接受度还不是很高,因此,在回答这道题的时候,你一定要先明确它的流处理框架地位,这样能给面试官留下一个很专业的印象。
从某种程度上说,这可是个“送命题”。消费者组是Kafka独有的概念,如果面试官问这个,就说明他对此是有一定了解的。我先给出标准答案:关于它的定义,官网上的介绍言简意赅,即消费者组是Kafka提供的可扩展且具有容错性的消费者机制。切记,一定要加上前面那句,以显示你对官网很熟悉。
另外,你最好再解释下消费者组的原理:在Kafka中,消费者组是一个由多个消费者实例构成的组。多个实例共同订阅若干个主题,实现共同消费。同一个组下的每个实例都配置有相同的组ID,被分配不同的订阅分区。当某个实例挂掉的时候,其他实例会自动地承担起它负责消费的分区。
此时,又有一个小技巧给到你:消费者组的题目,能够帮你在某种程度上掌控下面的面试方向。
使用这个策略的话,面试官可能会被你的话术所影响,偏离他之前想问的知识路径。当然了,如果你什么都不擅长,那就继续往下看题目吧。
这是一道能够帮助你脱颖而出的题目。碰到这个题目,请在心中暗笑三声。
先说标准答案:目前,Kafka使用ZooKeeper存放集群元数据、成员管理、Controller选举,以及其他一些管理类任务。之后,等KIP-500提案完成后,Kafka将完全不再依赖于ZooKeeper。
记住,一定要突出“目前”,以彰显你非常了解社区的演进计划。“存放元数据”是指主题分区的所有数据都保存在ZooKeeper中,且以它保存的数据为权威,其他“人”都要与它保持对齐。“成员管理”是指Broker节点的注册、注销以及属性变更,等等。“Controller选举”是指选举集群Controller,而其他管理类任务包括但不限于主题删除、参数配置等。
不过,抛出KIP-500也可能是个双刃剑。碰到非常资深的面试官,他可能会进一步追问你KIP-500是做的。一言以蔽之:KIP-500思想,是使用社区自研的基于Raft的共识算法,替代ZooKeeper,实现Controller自选举。你可能会担心,如果他继续追问的话,该怎么办呢?别怕,在下一期“特别发送”,我会专门讨论这件事。
这也是一道常见的面试题。位移概念本身并不复杂,你可以这么回答:在Kafka中,每个主题分区下的每条消息都被赋予了一个唯一的ID数值,用于标识它在分区中的位置。这个ID数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能被修改。
答完这些之后,你还可以把整个面试方向转移到你希望的地方。常见方法有以下3种:
这道题表面上是考核你对Leader和Follower区别的理解,但很容易引申到Kafka的同步机制上。因此,我建议你主动出击,一次性地把隐含的考点也答出来,也许能够暂时把面试官“唬住”,并体现你的专业性。
你可以这么回答:Kafka副本当前分为领导者副本和追随者副本。只有Leader副本才能对外提供读写服务,响应Clients端的请求。Follower副本只是采用拉(PULL)的方式,被动地同步Leader副本中的数据,并且在Leader副本所在的Broker宕机后,随时准备应聘Leader副本。
通常来说,回答到这个程度,其实才只说了60%,因此,我建议你再回答两个额外的加分项。
这道题除了要回答消费者端的参数设置之外,一定要加上Broker端的设置,这样才算完整。毕竟,如果Producer都不能向Broker端发送数据很大的消息,又何来消费一说呢?因此,你需要同时设置Broker端参数和Consumer端参数。
Broker端的最后一个参数比较容易遗漏。我们必须调整Follower副本能够接收的最大消息的大小,否则,副本同步就会失败。因此,把这个答出来的话,就是一个加分项。
其实,目前业界并没有公认的解决方案,各家都有各自的监控之道。所以,面试官其实是在考察你对监控框架的了解广度,或者说,你是否知道很多能监控Kafka的框架或方法。下面这些就是Kafka发展历程上比较有名气的监控系统。
kafka-run-class.sh kafka.tools.JmxTool
,学习下它的用法。如何设置Heap Size的问题,其实和Kafka关系不大,它是一类非常通用的面试题目。一旦你应对不当,面试方向很有可能被引到JVM和GC上去,那样的话,你被问住的几率就会增大。因此,我建议你简单地介绍一下Heap Size的设置方法,并把重点放在Kafka Broker堆大小设置的最佳实践上。
比如,你可以这样回复:任何Java进程JVM堆大小的设置都需要仔细地进行考量和测试。一个常见的做法是,以默认的初始JVM堆大小运行程序,当系统达到稳定状态后,手动触发一次Full GC,然后通过JVM工具查看GC后的存活对象大小。之后,将堆大小设置成存活对象总大小的1.5~2倍。对于Kafka而言,这个方法也是适用的。不过,业界有个最佳实践,那就是将Broker的Heap Size固定为6GB。经过很多公司的验证,这个大小是足够且良好的。
这道题目考查的是机器数量和所用资源之间的关联关系。所谓资源,也就是CPU、内存、磁盘和带宽。
通常来说,CPU和内存资源的充足是比较容易保证的,因此,你需要从磁盘空间和带宽占用两个维度去评估机器数量。
在预估磁盘的占用时,你一定不要忘记计算副本同步的开销。如果一条消息占用1KB的磁盘空间,那么,在有3个副本的主题中,你就需要3KB的总空间来保存这条消息。显式地将这些考虑因素答出来,能够彰显你考虑问题的全面性,是一个难得的加分项。
对于评估带宽来说,常见的带宽有1Gbps和10Gbps,但你要切记,这两个数字仅仅是最大值。因此,你最好和面试官确认一下给定的带宽是多少。然后,明确阐述出当带宽占用接近总带宽的90%时,丢包情形就会发生。这样能显示出你的网络基本功。
在生产环境中,你一定碰到过“某个主题分区不能工作了”的情形。使用命令行查看状态的话,会发现Leader是-1,于是,你使用各种命令都无济于事,最后只能用“重启大法”。
但是,有没有什么办法,可以不重启集群,就能解决此事呢?这就是此题的由来。
我直接给答案:删除ZooKeeper节点/controller,触发Controller重选举。Controller重选举能够为所有主题分区重刷分区状态,可以有效解决因不一致导致的Leader不可用问题。我几乎可以断定,当面试官问出此题时,要么就是他真的不知道怎么解决在向你寻求答案,要么他就是在等你说出这个答案。所以,千万别一上来就说“来个重启”之类的话。
在我看来,这纯属无聊的炫技。试问我不知道又能怎样呢?!不过既然问到了,我们就统一说一说。
其实,Kafka不需要用户手动删除消息。它本身提供了留存策略,能够自动删除过期消息。当然,它是支持手动删除消息的。因此,你最好从这两个维度去回答。
这是一个内部主题,公开的官网资料很少涉及到。因此,我认为,此题属于面试官炫技一类的题目。你要小心这里的考点:该主题有3个重要的知识点,你一定要全部答出来,才会显得对这块知识非常熟悉。
分区的Leader副本选举对用户是完全透明的,它是由Controller独立完成的。你需要回答的是,在哪些场景下,需要执行分区Leader选举。每一种场景对应于一种选举策略。当前,Kafka有4种分区Leader选举策略。
这4类选举策略的大致思想是类似的,即从AR中挑选首个在ISR中的副本,作为新Leader。当然,个别策略有些微小差异。不过,回答到这种程度,应该足以应付面试官了。毕竟,微小差别对选举Leader这件事的影响很小。
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特性了。
这道题目考察的是你对Leader/Follower模型的思考。
Leader/Follower模型并没有规定Follower副本不可以对外提供读服务。很多框架都是允许这么做的,只是Kafka最初为了避免不一致性的问题,而采用了让Leader统一提供服务的方式。
不过,在开始回答这道题时,你可以率先亮出观点:自Kafka 2.4之后,Kafka提供了有限度的读写分离,也就是说,Follower副本能够对外提供读服务。
说完这些之后,你可以再给出之前的版本不支持读写分离的理由。
回答任何调优问题的第一步,就是确定优化目标,并且定量给出目标!这点特别重要。对于Kafka而言,常见的优化目标是吞吐量、延时、持久性和可用性。每一个方向的优化思路都是不同的,甚至是相反的。
确定了目标之后,还要明确优化的维度。有些调优属于通用的优化思路,比如对操作系统、JVM等的优化;有些则是有针对性的,比如要优化Kafka的TPS。我们需要从3个方向去考虑。
这道题目能够诱发我们对分布式系统设计、CAP理论、一致性等多方面的思考。不过,针对故障定位和分析的这类问题,我建议你首先言明“实用至上”的观点,即不论怎么进行理论分析,永远都要以实际结果为准。一旦发生Controller网络分区,那么,第一要务就是查看集群是否出现“脑裂”,即同时出现两个甚至是多个Controller组件。这可以根据Broker端监控指标ActiveControllerCount来判断。
现在,我们分析下,一旦出现这种情况,Kafka会怎么样。
由于Controller会给Broker发送3类请求,即LeaderAndIsrRequest、StopReplicaRequest和UpdateMetadataRequest,因此,一旦出现网络分区,这些请求将不能顺利到达Broker端。这将影响主题的创建、修改、删除操作的信息同步,表现为集群仿佛僵住了一样,无法感知到后面的所有操作。因此,网络分区通常都是非常严重的问题,要赶快修复。
在回答之前,如果先把这句话说出来,一定会加分:Java Consumer是双线程的设计。一个线程是用户主线程,负责获取消息;另一个线程是心跳线程,负责向Kafka汇报消费者存活情况。将心跳单独放入专属的线程,能够有效地规避因消息处理速度慢而被视为下线的“假死”情况。
单线程获取消息的设计能够避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操作算子。因为很多实时流处理操作算子都不能是阻塞式的。另外一个可能的好处是,可以简化代码的开发。多线程交互的代码是非常容易出错的。
首先,Follower发送FETCH请求给Leader。接着,Leader会读取底层日志文件中的消息数据,再更新它内存中的Follower副本的LEO值,更新为FETCH请求中的fetchOffset值。最后,尝试更新分区高水位值。Follower接收到FETCH响应之后,会把消息写入到底层日志,接着更新LEO和HW值。
Leader和Follower的HW值更新时机是不同的,Follower的HW更新永远落后于Leader的HW。这种时间上的错配是造成各种不一致的原因。
好了,今天的面试题分享就先到这里啦。你有遇到过什么经典的面试题吗?或者是有什么好的面试经验吗?
欢迎你在留言区分享。如果你觉得今天的内容对你有所帮助,也欢迎分享给你的朋友。
评论