kafka常见面试点梳理

101 阅读11分钟

kafka文件存储机制

  • Kafka文件存储机制

Topic是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的就是Producer生产的数

据。Producer生产的数据会被不断追加到该log文件末端,为防止log文件过大导致数据定位效率低下,Kafka采取了分片索引机制,

将每个partition分为多个segment(每个1G)。每个segment包括:“.index”文件、“.log”文件和.timeindex等文件。这些文件位于一个文件夹下,该

文件夹的命名规则为:topic名称+分区序号,例如:first-0。

1、一个topic分为多个partition,一个partition分为多个segment,一个segment包含:.log 日志文件、.index 偏移量索引文件、.timeindex 时间戳索引文件

.timeindex 时间戳索引文件,每个segment文件大小是1个G

说明: index和log文件以当前segment的第一条消息的offset命名。

image.png

  • index与log文件的详解

如何在log文件中定位找到offset=600的记录呢?

1、根据目标的offset定位到segment文件,因为segment文件的命名是以第一条消息的offset命名

2、找到小于等于目标的offset(也就是绝对offset<600的index记录)的索引项

3、定位到log文件记录位置

4、向下遍历找到目标的record,然后返回

注意:

1、index为稀疏所以,大约每往log文件写入4KB数据,会往index文件写入一条索引,参数log.index.interval.bytes默认4kb

2、index文件中保存的offset为相对offset,这样能确保offset的值所占用空间不会过大,因此能将offset的值控制在固定的大小

整体流程图

image.png

kafka高效读写数据

1、Kafka 本身是分布式集群,可以采用分区技术,并行度高

2、读数据采用稀疏索引,可以快速定位要消费的数据**

3、顺序写磁盘,顺序写能到 600M/s

4、页缓存** + 零拷贝技术

kafka文件清理策略

Kafka 中默认的日志保存时间为 7 天,可以通过调整如下参数修改保存时间。

⚫ log.retention.hours,最低优先级小时,默认 7 天。

⚫ log.retention.minutes,分钟。

⚫ log.retention.ms,最高优先级毫秒。

⚫ log.retention.check.interval.ms,负责设置检查周期,默认 5 分钟。

那么日志一旦超过了设置的时间,怎么处理呢?

Kafka 中提供的日志清理策略有 delete 和 compact 两种。

1)delete 日志删除:将过期数据删除

⚫ log.cleanup.policy = delete 所有数据启用删除策略

(1)基于时间:默认打开。以 segment 中所有记录中的最大时间戳作为该文件时间戳。

(2)基于大小:默认关闭。超过设置的所有日志总大小,删除最早的 segment。

log.retention.bytes,默认等于-1,表示无穷大。

思考: 如果一个 segment 中有一部分数据过期,一部分没有过期,怎么处理?

2)compact 日志压缩

compact日志压缩:对于相同key的不同value值,只保留最后一个版本

Kafka消费方式

pull (拉)模 式:

consumer采用从broker中主动拉取数据。 pull模式不足之处是,如 果Kafka没有数据,消费者可能会陷入循环中,一直返回空数据。

Kafka 默认采用这种方式。

push (推)模式:

Kafka没有采用这种方式,因为由broker决定消息发送速率,很难适应所有消费者的消费速率。例如推送的速度是50m/s,

Consumer1、Consumer2就来不及处理消息。

Kafka消费者组初始化流程

1、coordinator:辅助实现消费者组的初始化和分区的分配。每个broker都有一个coordinator

消费者组要选择哪个coordinator作为他辅助呢?

coordinator节点选择 = groupid的hashcode值 % 50( __consumer_offsets的分区数量)

例如: groupid的hashcode值 = 1,1% 50 = 1,那么__consumer_offsets 主题的1号分区,在哪个broker上,就选择这个节点的coordinator

作为这个消费者组的老大。消费者组下的所有的消费者提交offset的时候就往这个分区去提交offset。

筛选出coordinator之后

1)每个consumer都发送JoinGroup请求到coordinator中,首要加入到这个group中

2)对应的coordinator会随机通过消费者id,来选出一个leade作为老大

3)对应的coordinator收集到各个consumer之后,把要消费的topic情况发送给leader 消费者

4)leader会负责制定消费方案,制定各个消费者消费哪个分区(分区分配策略 rang、roundRobin、sticky、cooperativeSticky)

5)leader把制定后的消费方案发给对应的coordinator

6)对应的coordinator就把消费方案下发给各个consumer

7)每个消费者都会和coordinator保持心跳(默认3s),一旦超时(session.timeout.ms=45s),该消费者会被移除,并触发再平衡;或者消费者处理消息的时间过长(max.poll.interval.ms5分钟),也会触发再平衡

image.png

kafka消费者分区的分配以及再平衡

1、一个consumer group中有多个consumer组成,一个 topic有多个partition组成,现在的问题是,到底由哪个consumer来消费哪个 partition的数据(请阅读kafka消费者初始化过程)。

2、Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky。

可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用

多个分区分配策略。

1)每个consumer都发送JoinGroup请求到coordinator中,首要加入到这个group中

2)对应的coordinator会随机通过消费者id,来选出一个leade作为老大

3)对应的coordinator收集到各个consumer之后,把要消费的topic情况发送给leader 消费者

4)leader会负责制定消费方案,制定各个消费者消费哪个分区(分区分配策略 rang、roundRobin、sticky、cooperativeSticky)

5)leader把制定后的消费方案发给对应的coordinator

6)对应的coordinator就把消费方案下发给各个consumer

7)每个消费者都会和coordinator保持心跳(默认3s),一旦超时(session.timeout.ms=45s),该消费者会被移除,并触发再平衡;或者消费者处理消息的时间过长(max.poll.interval.ms5分钟),也会触发再平衡

参数名称描述
heartbeat.interval.msKafka 消费者和 coordinator 之间的心跳时间,默认 3s。 该条目的值必须小于 session.timeout.ms,也不应该高于 session.timeout.ms 的 1/3。
session.timeout.msKafka 消费者和 coordinator 之间连接超时时间,默认 45s。超 过该值,该消费者被移除,消费者组执行再平衡。session.timeout.ms 的 1/3。
max.poll.interval.ms消费者处理消息的最大时长,默认是 5 分钟。超过该值,该 消费者被移除,消费者组执行再平衡。
partition.assignment.strategy消 费 者 分 区 分 配 策 略 , 默 认 策 略 是 Range + CooperativeSticky。Kafka 可以同时使用多个分区分配策略。 可 以 选 择 的 策 略 包 括 : Range 、 RoundRobin 、 Sticky 、CooperativeSticky

Range 以及再平衡

  • Range 分区策略原理

Range 是对每个 topic 而言的。

首先对同一个 topic 里面的分区按照序号进行排序,并

对消费者按照字母顺序进行排序。

假如现在有 7 个分区,3 个消费者,排序后的分区将会

是0,1,2,3,4,5,6;消费者排序完之后将会是C0,C1,C2。

例如,7/3 = 2 余 1 ,除不尽,那么 消费者 C0 便会多

消费 1 个分区。 8/3=2余2,除不尽,那么C0和C1分别多

消费一个。

通过 partitions数/consumer数 来决定每个消费者应该

消费几个分区。如果除不尽,那么前面几个消费者将会多

消费 1 个分区。

分区分配策略之Range

注意:如果只是针对 1 个 topic 而言,C0消费者多消费1

个分区影响不是很大。但是如果有 N 多个 topic,那么针对每

个 topic,消费者 C0都将多消费 1 个分区,topic越多,C0消

费的分区会比其他消费者明显多消费 N 个分区。

  • Range 分区分配再平衡案例

(1)停止掉 0 号消费者,快速重新发送消息观看结果(45s 以内,越快越好)。

1 号消费者:消费到 3、4 号分区数据。

2 号消费者:消费到 5、6 号分区数据。

0 号消费者的任务会整体被分配到 1 号消费者或者 2 号消费者。

说明:0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需

要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行。

(2)再次重新发送消息观看结果(45s 以后)。

1 号消费者:消费到 0、1、2、3 号分区数据。

2 号消费者:消费到 4、5、6 号分区数据。

说明:消费者 0 已经被踢出消费者组,所以重新按照 range 方式分配。

RoundRobin 以及再平衡

  • RoundRobin分区策略原理

RoundRobin 针对集群中所有Topic而言。

RoundRobin 轮询分区策略,是把所有的 partition 和所有的

consumer 都列出来,然后按照 hashcode 进行排序,最后

通过轮询算法来分配 partition 给到各个消费者。

  • RoundRobin 分区分配再平衡案例

(1)停止掉 0 号消费者,快速重新发送消息观看结果(45s 以内,越快越好)。

1 号消费者:消费到 2、5 号分区数据

2 号消费者:消费到 4、1 号分区数据

0 号消费者的任务会按照 RoundRobin 的方式,把数据轮询分成 0 、6 和 3 号分区数据,

分别由 1 号消费者或者 2 号消费者消费。

说明:0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需

要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行。

(2)再次重新发送消息观看结果(45s 以后)。

1 号消费者:消费到 0、2、4、6 号分区数据

2 号消费者:消费到 1、3、5 号分区数据

说明:消费者 0 已经被踢出消费者组,所以重新按照 RoundRobin 方式分配。

##Sticky以及再平衡

  • 粘性分区定义

粘性分区定义: 可以理解为分配的结果带有“粘性的”。即在执行一次新的分配之前,

考虑上一次分配的结果,尽量少的调整分配的变动,可以节省大量的开销。

粘性分区是 Kafka 从 0.11.x 版本开始引入这种分配策略,首先会尽量均衡的放置分区

到消费者上面,在出现同一消费者组内消费者出现问题的时候,会尽量保持原有分配的分

区不变化

  • Sticky 分区分配再平衡案

停止掉 0 号消费者,快速重新发送消息观看结果(45s 以内,越快越好)。

1 号消费者:消费到 2、5、3 号分区数据。

2 号消费者:消费到 4、6 号分区数据。

0 号消费者的任务会按照粘性规则,尽可能均衡的随机分成 0 和 1 号分区数据,分别

由 1 号消费者或者 2 号消费者消费

说明:0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需

要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行。

(2)再次重新发送消息观看结果(45s 以后)。

1 号消费者:消费到 2、3、5 号分区数据。

2 号消费者:消费到 0、1、4、6 号分区数据。

说明:消费者 0 已经被踢出消费者组,所以重新按照粘性方式分配。

kafka—数据积压(消费者如何提高吞吐量)

1)如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数 = 分区数。(两者缺一不可)

2)如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间 < 生产速度),使处理的数据小于生产的数据,也会造成数据积压。

参数名称描述
fetch.max.bytes默认 Default: 52428800(50 m)。消费者获取服务器端一批消息最大的字节数。如果服务器端一批次的数据大于该值(50m)仍然可以拉取回来这批数据,因此,这不是一个绝对最大值。一批次的大小受 message.max.bytes (broker config)or max.message.bytes (topic config)影响。
max.poll.records一次 poll 拉取数据返回消息的最大条数,默认是 500 条