kafka常见面试题
1.Kafka 中的 ISR(InSyncRepli)、OSR(OutSyncRepli)、AR(AllRepli)代表什么?
1、AR = ISR+OSR
ISR:
kafka 使用多副本来保证消息不丢失,多副本就涉及到kafka的复制机制,在一个超大规模的集群中,时不时地这个点磁盘坏了,那个点cpu负载高了,出现各种各样的问题,多个副本之间的复制,如果想完全自动化容错,就要做一些考量和取舍了。我们举个例子说明下运维中面对的复杂性,我们都知道 kafka 有个 ISR集合,我先说明下这个概念:
kafka不是完全同步,也不是完全异步,是一种ISR机制:
1. leader会维护一个与其基本保持同步的Replica列表,该列表称为ISR(in-sync Replica),每个Partition都会有一个ISR,而且是由leader动态维护
2. 如果一个follower比一个leader落后太多,或者超过一定时间未发起数据复制请求,则leader将其重ISR中移除
3. 当ISR中所有Replica都向Leader发送ACK时,leader才commit,这时候producer才能认为一个请求中的消息都commit了。
kafka中的副本机制是以分区粒度进行复制的,我们在kafka中创建 topic的时候,都可以设置一个复制因子,这个复制因子决定着分区副本的个数,如果leader 挂掉了,kafka 会把分区主节点failover到其他副本节点,这样就能保证这个分区的消息是可用的。leader节点负责接收producer 打过来的消息,其他副本节点(follower)从主节点上拷贝消息。
存在的问题:
从上面的情况来看,两个参数看似已经足够了,如果一个副本超过 replica.lag.time.max.ms 还没有发送fetch同步请求, 可以认为这个副本节点卡住了,然后踢出去,但是还有一种比较特殊的情况没有考虑到,我们上文中设置 replica.lag.max.messages 为4,之所以设置为 4, 是我们已经知道 producer 每次请求打过来的消息数都在 4 以下,如果我们的参数是作用于多个 topic 的情况,那么这个 producer 最大打过来的消息数目就不好估计了,或者说在经常出现流量抖动的情况下,就会出现一个什么情况呢,我们还是使用例子说明:
如果我们的 topic — foo 的 producer 因为流量抖动打过来一个 包含 4条消息的请求,我们设置的 replica.lag.max.messages 还是为4, 这个时候,所有的 follower 都会因为超出落后条数被踢出 ISR集合。
然后,因为 follower 是正常的,所以下一次 fetch 请求就会又追上 leader, 这时候就会再次加入 ISR 集合,如果经常性的抖动,就会不断的移入移出ISR集合,会造成令人头疼的 告警轰炸。
kafka 给出的方案是这样的,对 replica.lag.time.max.ms 这个配置的含义做了增强,和之前一样,如果 follower 卡住超过这个时间不发送fetch请求, 会被踢出ISR集合,新的增强逻辑是,在 follower 落后 leader 超过 eplica.lag.max.messages 条消息的时候,不会立马踢出ISR 集合,而是持续落后超过 replica.lag.time.max.ms 时间,才会被踢出
2.Kafka 中的 HW、LEO 等分别代表什么?
- LEO:即日志末端位移(log end offset),记录了该副本底层日志(log)中下一条消息的位移值。注意是下一条消息!也就是说,如果LEO=10,那么表示该副本保存了10条消息,位移值范围是[0, 9]。
- High Watermark(高水位线)以下简称HW,表示消息被leader和ISR内的follower都确认commit写入本地log,所以在HW位置以下的消息都可以被消费(不会丢失)。
Kafka复制协议有两个阶段,第一阶段,follower从leader获取到消息;第二阶段,在下一轮的RPC中向leader发送fetch request确认收到消息。假设其他的follower也都确认了,那么leader会更新HW,并在接下来的RPC中响应给follower。
同时,在重启一个follower时,这个follower可能会把日志截断到HW处(意味着此follower将会删除一些消息),然后从leader获取消息。
正式有与Kafka的复制协议分两个阶段,导致使用高水位会出现数据丢失和数据不一致的问题,下面我们分别讲一下这两种问题:
①数据丢失【Scenario 1: High Watermark Truncation followed by Immediate Leader Election】
假设有A、B两个Broker,初始时B为leader,A从B中取到消息m2,所以A中有消息m2了,但是由于在下一轮RPC中,A才会更新自己的HW,所以此时A的HW没变。如果这时候A重启了,他截取自己的日志到HW并发送一个fetch request到B。不幸的是,B这时宕机了,A成了新的leader,那么此时消息m2就会永久的丢失了。
②数据不一致:【Scenario 2: Replica Divergence on Restart after Multiple Hard Failures】
假设我们有两个Broker,初始时A是leader,B是follower。A接收到m2消息,但B还没来得及复制时,断电了。过了一会,B重启了,成为了leader,接收了m3消息,HW+1。然后A重启了,截断日志到高水位,但是此时的消息却出现了不一致。
在0.11版本使用leader epoch解决这两个问题。
3.Kafka 中是怎么体现消息顺序性的?
1、Kafka只能保证分区内消息顺序有序,无法保证全局有序。
- 生产者:通过分区的leader副本负责数据顺序写入,来保证消息顺序性。
- 消费者:同一个分区内的消息只能被一个group里的一个消费者消费,保证分区内消费有序。
2、如何做到并发且全局有序?
整体思路】想办法让需要保证顺序的数据发送到同一个分区中,并增加生产者/消费者的并发度
topic设置一个分区,发送端和消费端开启多线程生产和消费:简单但有热点瓶颈问题。
topic设置多个分区,自定义发送端的分区策略,数据发送不同分区,消费时按发送分区的顺序消费,发送和消费端都启动多线程来提高并发度
- 自义分区器,使得消息按分区号大小顺序依次发送相同数量大小的数据
- 发送端和消费端启动多个消费线程进行生产和消费
- 线程之间按分区号大小顺序消费数据
- 【弊端】消费性能极大下降,无法真正并发
4.Kafka 中的分区器、序列化器、拦截器是否了解?它们之间的处理顺序是什么?
序列化器:键序列化器和值序列化器,将键和值都转为二进制流 还有反序列化器 将二进制流转为指定类型数据
拦截器:两个方法 doSend()方法会在序列化之前完成 ,onAcknowledgement()方法在消息确认或失败时回调。 可以添加多个拦截器按顺序执行。
5.Kafka 生产者客户端的整体结构是什么样子的?使用了几个线程来处理?分别是什么?
Kafka 的 Producer 发送消息采用的是异步发送的方式。在消息发送的过程中,涉及到了 两个线程——main 线程和 Sender 线程,以及一个线程共享变量——RecordAccumulator。 main 线程将消息发送给 RecordAccumulator,Sender 线程不断从 RecordAccumulator 中拉取 消息(已经分好区)发送到 Kafka broker。
https://www.cnblogs.com/wsw-seu/p/13458506.html
6.“消费组中的消费者个数如果超过 topic 的分区,那么就会有消费者消费不到数据”这句 话是否正确?
正确,生产环境中这样做浪费资源。
7.消费者提交消费位移时提交的是当前消费到的最新消息的 offset 还是 offset+1?
offset+1
下面这个例子,zk中,bbb主题,2个分区。还没消费就会存一个0 offset。
8.有哪些情形会造成重复消费?
消费者 先处理消息,后提交offset(可能失败)
9.那些情景会造成消息漏消费?
消费者 先提交offset,再处理消息(可能失败)
10.当你使用 kafka-topics.sh 创建(删除)了一个 topic 之后,Kafka 背后会执行什么逻辑?
1)会在 zookeeper 中的/brokers/topics 节点下创建一个新的 topic 节点,如:
/brokers/topics/first
2)触发 Controller 的监听程序
3)kafka Controller 负责 topic 的创建工作,并更新 metadata cache
11.topic 的分区数可不可以增加?如果可以怎么增加?如果不可以,那又是为什么?
可以增
当一个主题被创建之后,依然允许我们对其做一定的修改,比如修改分区个数、修改配置等,这个修改的功能就是由kafka-topics.sh脚本中的alter指令所提供。我们首先来看如何增加主题的分区数。
以前面的主题topic-config为例,当前分区数为1,修改为3,示例如下:
注意上面提示的告警信息:当主题中的消息包含有key时(即key不为null),根据key来计算分区的行为就会有所影响。当topic-config的分区数为1时,不管消息的key为何值,消息都会发往这一个分区中;当分区数增加到3时,那么就会根据消息的key来计算分区号,原本发往分区0的消息现在有可能会发往分区1或者分区2中。如此还会影响既定消息的顺序,所以在增加分区数时一定要三思而后行。对于基于key计算的主题而言,建议在一开始就设置好分区数量,避免以后对其进行调整。
12.topic 的分区数可不可以减少?如果可以怎么减少?如果不可以,那又是为什么?
目前Kafka只支持增加分区数而不支持减少分区数。比如我们将主题topic-config的分区数修改为1,就会报出InvalidPartitionException的异常。
比如删除掉的分区中的消息该作何处理?如果随着分区一起消失则消息的可靠性得不到保障;如果需要保留则又需要考虑如何保留。直接存储到现有分区的尾部,消息的时间戳就不会递增,如此对于Spark、Flink这类需要消息时间戳(事件时间)的组件将会受到影响;如果分散插入到现有的分区中,那么在消息量很大的时候,内部的数据复制会占用很大的资源,而且在复制期间,此主题的可用性又如何得到保障?与
此同时,顺序性问题、事务性问题、以及分区和副本的状态机切换问题都是不得不面对的。反观这个功能的收益点却是很低,如果真的需要实现此类的功能,完全可以重新创建一个分区数较小的主题,然后将现有主题中的消息按照既定的逻辑复制过去即可。
虽然分区数不可以减少,但是分区对应的副本数是可以减少的,这个其实很好理解,你关闭一个副本时就相当于副本数减少了。
13.Kafka 有内部的 topic 吗?如果有是什么?有什么所用?
kafka在0.10.x版本后默认将消费者组的位移(offset)提交到自带的topic__consumer_offsets
里面,当有消费者第一次消费kafka数据时就会自动创建,它的副本数不受集群配置的topic副本数限制,分区数默认50(可以配置),默认压缩策略为compact
14.Kafka 分区分配的概念?
当遇到“分区分配”这个字眼的时候,一定要记住有三处地方,分别是生产者发送消息、消费者消费消息、创建主题
1、生产者的分区分配
对于用户而言,当调用send方法发送消息之后,消息就自然而然的发送到了broker中。其实在这一过程中,有可能还要经过拦截器、序列化器和分区器(Partitioner)的一系列作用之后才能被真正地发往broker。
2、消费者的分区分配
在Kafka的默认规则中,每一个分区只能被同一个消费组中的一个消费者消费。消费者的分区分配是指为消费组中的消费者分配所订阅主题中的分区。
Kafka自身提供了三种策略,分别为RangeAssignor、RoundRobinAssignor以及StickyAssignor,其中RangeAssignor为默认的分区分配策略3、broker端的分区分配
生产者的分区分配是指为每条消息指定其所要发往的分区,消费者中的分区分配是指为消费者指定其可以消费消息的分区,而这里的分区分配是指为集群制定创建主题时的分区副本分配方案,即在哪个broker中创建哪些分区的副本。分区分配是否均衡会影响到Kafka整体的负载均衡,具体还会牵涉到优先副本等概念。
15.简述 Kafka 的日志目录结构?
见深入理解kafka核心设计与实践原理第5章日志存储
16.如果我指定了一个 offset,Kafka Controller 怎么查找到对应的消息?
同上
17.聊一聊 Kafka Controller 的作用?
Controller 作为 Kafka Server 端一个重要的组件,它的角色类似于其他分布式系统 Master 的角色,跟其他系统不一样的是,Kafka 集群的任何一台 Broker 都可以作为 Controller,但是在一个集群中同时只会有一个 Controller 是 alive 状态。Controller 在集群中负责的事务很多,比如:集群 meta 信息的一致性保证、Partition leader 的选举、broker 上下线等都是由 Controller 来具体负责。
Controller 是运行在 Broker 上的,任何一台 Broker 都可以作为 Controller,但是一个集群同时只能存在一个 Controller,也就意味着 Controller 与数据节点是在一起的,Controller 做的主要事情如下:
- Broker 的上线、下线处理;
- 新创建的 topic 或已有 topic 的分区扩容,处理分区副本的分配、leader 选举;
- 管理所有副本的状态机和分区的状态机,处理状态机的变化事件;
- topic 删除、副本迁移、leader 切换等处理。
18.Kafka 中有那些地方需要选举?这些地方的选举策略又有哪些?
Kafka中的选举大致可以分为三大类:控制器的选举、分区leader的选举以及消费者相关的选举。
1、控制器的选举
在Kafka集群中会有一个或多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态等工作。比如当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。再比如当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。
Kafka Controller的选举是依赖Zookeeper来实现的,在Kafka集群中哪个broker能够成功创建/controller这个临时(EPHEMERAL)节点他就可以成为Kafka Controller。
2、分区leader的选举
分区leader副本的选举由Kafka Controller 负责具体实施。当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要执行leader的选举动作。
基本思路是按照AR集合中副本的顺序查找第一个存活的副本,并且这个副本在ISR集合中。一个分区的AR集合在分配的时候就被指定,并且只要不发生重分配的情况,集合内部副本的顺序是保持不变的,而分区的ISR集合中副本的顺序可能会改变。注意这里是根据AR的顺序而不是ISR的顺序进行选举的。
还有一些情况也会发生分区leader的选举,比如当分区进行重分配(reassign)的时候也需要执行leader的选举动作。这个思路比较简单:从重分配的AR列表中找到第一个存活的副本,且这个副本在目前的ISR列表中。
再比如当发生优先副本(preferred replica partition leader election)的选举时,直接将优先副本设置为leader即可,AR集合中的第一个副本即为优先副本。
3、消费者相关的选举
组协调器GroupCoordinator需要为消费组内的消费者选举出一个消费组的leader,这个选举的算法也很简单,分两种情况分析。如果消费组内还没有leader,那么第一个加入消费组的消费者即为消费组的leader。如果某一时刻leader消费者由于某些原因退出了消费组,那么会重新选举一个新的leader。
19.失效副本是指什么?有那些应对措施?
正常情况下,分区的所有副本都处于 ISR 集合中,但是难免会有异常情况发生,从而某些副本被剥离出 ISR 集合中。在 ISR 集合之外,也就是处于同步失效或功能失效(比如副本处于非存活状态)的副本统称为失效副本,失效副本对应的分区也就称为同步失效分区,即 under-replicated 分区。
可以参考 https://www.cnblogs.com/luozhiyun/p/12079527.html
20.Kafka 的哪些设计让它有如此高的性能?