KAFKA面试题

1,081 阅读10分钟

1. 生产者如何提高吞吐量

batch.size:批次大小,默认16k
linger.ms:等待时间,修改为5-100ms
compression.type:压缩snappy
RecordAccumulator:缓冲区大小,修改为64m

2. Kafka的生产和消费数据为什么会快,请说说原因

  1. 一个topic创建多个partition,一个生产者在发送消息的时候可以进一步提高吞吐量

  2. sender线程是把一批消息发送到pageCache中,

  3. 消息是被存储在RecordAccumulator 的recordBatch中,有压缩过程

  4. 把pagechache上面的数据定时刷到segment的log日志, 顺序写 segment的log日志, 也保留一些最新的数据,当消费者要消费的数据在pagecache上,就直接消费了,不需要读磁盘了,但也不能把要消费的数据都保存在pageCache上,因为物理机内存有限

  5. 用户发起消费,发起sendfile()系统调用,从用户态切换到内核态,要消费的数据是否在pageCache中存在,如果存在就利用CPU拷贝把数据在pageCache中的内存地址、地址偏移量、等描述信息拷贝到socket缓冲区, socket缓冲区会根据这些描述信息利用DMA gather copy把数据copy到网卡设备,sendfile系统调用返回,内核态切换到用户态

image.png

image.png

3. Kafka生产消息为什么快之PageCache

消息会被打包到一个recordbatch中,一个recordbatch的大小16KB,一个recordbatch被使用完,会申请一个新的recordbatch,一个recordbatch被写满会触发sender线程发送数据 的操作,会把数据发送到pageCache中,发送的最小单位是一个recordbatch,收到broker的ack以后,就会清空recordbatch,脏页4KB,每5s 写入flash一次硬盘,用到了顺序写的技术

直接使用jvm进程中的缓存,内存的开销是很大的,会占用对象真实大小的几倍的大小,还要进行垃圾回收,触发STW

4. Kafka的生产者是如何把一条消息发送到Broker节点的

生产者会把消息封装成ProducerRecord,key不为空,默认key的hashcode值取模获取投递的分区,key相同的分区都会发送到同一个分区。key==null按照轮询方式选择分区

打包压缩成recordBatch再进行发送,16KB,支持某种压缩算法的,linger.ms和batch.size两个参数控制生成一个发送请求

5. Kafka 中一个 Topic 有三个 Partition,同一个消 费组中两个消费者如何消费的?

当我们向某个 Topic 发送消息的时候,在 Kafka 的 Broker 上,会通过Partition分区的机制来实现消息的物理存储。 一个 Topic可以有多个Partition,相当于把一个Topic里面的N个消息数据进行分片存储。 消费端去消费消息的时候,会从指定的 Partition 中去获取

在同一个消费组中,一个消费者可以消费多个 Partition 中的数据。但是消费者的数量 只能小于或者等于 Partition 分区数量。

这个问题涉及到Kafka里面的ConsumerGroupCoordinator ,也就是消费组协调器。 它会根据消费者订阅的 Topic 中的 partition 数量、 和消费组中的消费者实例数量来决定每个消费者消费哪些 Partition。 这个算法会在消费组中选择一个消费者实例作为 Leader, Leader 负责分配 Partition 给消费者实例,并协调消费者实例之间的 Partition 分配和 Reblance 当一个消费者实例加入或离开消费组的时候,协调器会触发 Partition 的重新分配,确保所有 Partition 都能被消费者实例均匀地消费。 Kafka 还提供了三种 Partition 分配策略,

1. "Round-robin(轮训)",它会将 Partition 均匀地分配给消费者实例
2. "Range(范围)",它会按照 Partition 的范围进行分配。
3. ”Sticky(粘滞分配),它会尽可能地将同一 Partition 分配给同一个消费者实例

6. Kafka 分区的目的?

分区对于 Kafka 集群的好处是:实现负载均衡。分区对于消费者来说,可以提高并发度,提高效率。

Kafka Producer 的执行过程

1 Producer生产消息

2 从Zookeeper找到Partition的Leader

3 推送消息

4 通过ISR列表通知给Follower

5 Follower从Leader拉取消息,并发送ack

6 Leader收到所有副本的ack,更新Offset,并向Producer发送ack,表示消息写入成功。

7. Kafka消息是采用Pull模式,还是Push模式?

Kafka遵循了一种大部分消息系统共同的传统的设计:producer将消息推送到broker,consumer从broker拉取消息。

一些消息系统比如Scribe和Apache Flume采用了push模式,将消息推送到下游的consumer。这样做有好处也有坏处:由broker决定消息推送的速率,对于不同消费速率的consumer就不太好处理了。消息系统都致力于让consumer以最大的速率最快速的消费消息,但不幸的是,push模式下,当broker推送的速率远大于consumer消费的速率时,consumer恐怕就要崩溃了。

最终Kafka还是选取了传统的pull模式。Pull模式的另外一个好处是consumer可以自主决定是否批量的从broker拉取数据。Push模式必须在不知道下游consumer消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。如果为了避免consumer崩溃而采用较低的推送速率,将可能导致一次只推送较少的消息而造成浪费。Pull模式下,consumer就可以根据自己的消费能力去决定这些策略。

Pull有个缺点是,如果broker没有可供消费的消息,将导致consumer不断在循环中轮询,直到新消息到t达。为了避免这点,Kafka有个参数可以让consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发#

8. Kafka 高效文件存储设计特点

Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。 通过索引信息可以快速定位message和确定response的最大大小。 通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。 通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小

9. 谈一谈 Kafka 的再均衡

在Kafka中,当有新消费者加入或者订阅的topic数发生变化时,会触发Rebalance(再均衡:在同一个消费者组当中,分区的所有权从一个消费者转移到另外一个消费者)机制,Rebalance顾名思义就是重新均衡消费者消费。 Rebalance的过程如下:

第一步:所有成员都向coordinator发送请求,请求入组。一旦所有成员都发送了请求,coordinator会从中选择一个consumer担任leader的角色,并把组成员信息以及订阅信息发给leader。

第二步:leader开始分配消费方案,指明具体哪个consumer负责消费哪些topic的哪些partition。一旦完成分配,leader会将这个方案发给coordinator。coordinator接收到分配方案之后会把方案发给各个consumer,这样组内的所有成员就都知道自己应该消费哪些分区了。所以对于Rebalance来说,Coordinator起着至关重要的作用#

10. Kafka 是如何实现高吞吐率的?

Kafka是分布式消息系统,需要处理海量的消息,Kafka的设计是把所有的消息都写入速度低容量大的硬盘,以此来换取更强的存储能力,但实际上,使用硬盘并没有带来过多的性能损失。

kafka主要使用了以下几个方式实现了超高的吞吐率:

顺序读写;

零拷贝

文件分段

批量发送

数据压缩

11. Kafka 分区数可以增加或减少吗?为什么?

我们可以使用 bin/kafka-topics.sh 命令对 Kafka 增加 Kafka 的分区数据,但是 Kafka 不支持减少分区数。

Kafka 分区数据不支持减少是由很多原因的,比如减少的分区其数据放到哪里去?是删除,还是保留?删除的话,那么这些没消费的消息不就丢了。 如果保留这些消息如何放到其他分区里面?追加到其他分区后面的话那么就破坏了 Kafka 单个分区的有序性。如果要保证删除分区数据插入到其他分区保证有序性,那么实现起来逻辑就会非常复杂。

12 为什么要使用消息队列?

解耦、异步、削峰。

13 如何避免消息重复消费?

在消息生产时,MQ内部针对每条生产者发送的消息生成一个唯一id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列。 在消息消费时,要求消息体中也要有一全局唯一id作为去重和幂等的依据,避免同一条消息被重复消费。

14. 多线程异步和MQ的区别

CPU消耗。多线程异步可能存在CPU竞争,而MQ不会消耗本机的CPU。

MQ 方式实现异步是完全解耦的,适合于大型互联网项目。削峰或者消息堆积能力。 当业务系统处于高并发,MQ可以将消息堆积在Broker实例中,而多线程会创建大量线程,甚至触发拒绝策略。 使用MQ引入了中间件,增加了项目复杂度和运维难度。

15 如何设计一个消息队列?

16. 如何保证数据一致性,事务消息如何实现?

生产者产生消息,发送一条半事务消息到MQ服务器

MQ收到消息后,将消息持久化到存储系统,这条消息的状态是待发送状态。

MQ服务器返回ACK确认到生产者,此时MQ不会触发消息推送事件

生产者执行本地事务

如果本地事务执行成功,即commit执行结果到MQ服务器;如果执行失败,发送rollback。

如果是正常的commit,MQ服务器更新消息状态为可发送;如果是rollback,即删除消息。

如果消息状态更新为可发送,则MQ服务器会push消息给消费者。消费者消费完就回ACK。

如果MQ服务器长时间没有收到生产者的commit或者rollback,它会反查生产者,然后根据查询到的结果执行最终状态。

17. kafka 理解高水位HW和LEO之间的关系

LEO: log End Offset 表示当前分区日志文件中下一条待写入消息的offset

HW(High Watermark):所有副本中最小的LEO

Follower发生故障后会被临时踢出ISR, 这个期间Leader和Follower继续接收数据, 待该Follower恢复后,Follower会读取本地磁盘记录的上次的HW, 并将log文件高于HW的部分截取掉,从HW开始向Leader进行同步。等该Follower的LEO大于等于该Partition的HW,即Follower追上Leader之后,就可以重新加入ISR了

18 kafka和rocketmq如何选型

延时都差不多,rocketmq的管理界面比较好,提供了消息查询界面和延迟队列等功能,用java开发的,比较友好适合二次开发

kafaka主要用来处理大批量的日志,性能都差不多,用scala开发的