今天你准备了吗——Kafka面试题

159 阅读11分钟

Kafka面试题

1.Kafka设计是什么样的?

Kafka是将消息以topic为单位进行分类,将向Kafka 的topic发布消息程序称为生产者,将预定topic的程序称为消费者,kafka可以以集群的方式运行,可以由一个或多个服务组成,每个服务叫做broker。

2.Kafka的优点和缺点

1.用于消息系统:和其他的消息中间件一样,都具有解耦削锋异步作用,但是同时提供了大多数消息系统难以实现的分区消息顺序性保障的功能。 2.存储系统:基于消息持久化和多副本机制将消息持久化到磁盘中,相比于其他基于内存存储系统而言,有效降低数据丢失的问题。

3.流式处理平台:

3.Kafka的如何保证消息的顺序性

方案1:Kafka消息的顺序性保证的是分区的顺序性,offset是消息在分区中的唯一标识,所有可以保证同一个分区的数据是有序的,则可以设置topic只使用一个分区,这样消息就全局有序。但是降低了性能,不适合高并发情况;

问题1:当前一条数据发送失败,后一条消息发送成功,那这样就会造成消息乱序?该怎样解决?

kafka的生产者支持幂等性,enable.idempotence 被设置成 true 后,Producer 自动升级成幂等性 Producer,Kafka引入了PID和Sequence Number ,PID:是为每个新的Producer在初始化的时候会被分配一个唯一的PID,对于每条消息发送都会带着一个从0开始递增的Sequence Number。每次提交一次消息,将其对应的序号进行新增+1,对于接收到的每条消息,如果SN比为Broker维护的SN大一,那么就接收这条消息。

如果消息序号比Broker维护的序号大一以上,说明中间有数据尚未写入,也即乱序,此时Broker拒绝该消息;Producer抛出InvalidSequenceNumber 
如果消息序号小于等于Broker维护的序号,说明该消息已被保存,即为重复消息,Broker直接丢弃该消息,Producer抛出DuplicateSequenceNumber

问题2:当你重启了 Producer 进程之后,这种幂等性保证就丧失了,该怎样保证幂等性?

事务型 Producer 能够保证将消息原子性地写入到多个分区中。这批消息要么全部写入成功,要么全部失败;设置 Producer 端参数 transactional. id,因为它允许客户端在启动任何新事务之前确保使用相同 TransactionalId 的事务已经完成,

方案2:productor发送消息指定需要保证顺序的几条消息送到同一个分区,每个分区只对应一个消费者,这样这个消费者消费就是有序的。同一张表的数据可以放到同一个分区。

问题2:每个分区只对应一个消费者,性能大大降低了,所以可以通过多线程实现多个消费者来消费数据?

拉取线程:负责消息的拉取、分发和消息的offset的提交。

工作线程:负责消息的后续的业务处理

方案一:最多消费一次,对消息消费的可靠性要求不高

即kafka拉取线程拉取到消息立即自动提交offset,不管后续的工作线程是否成功。

方案二:至少消费一次:消息被拉取后将消息发送给工作线程,待工作线程处理完后返回提交offset。

拉取线程:拉取对应的Topic消息,并将消息发送给工作线程,同时异步处理已完成业务处理消息的offset

工作线程:完成消息的业务后,把消息的offset更新到新提交的offset池中;Map<Partion,offset>拉取线程会一直检查该Map的每个Partition的offset是否有更新,如果更新,就会提交offset到Kafka

4.Kafka的productor的发送流程

发送消息的三种模式:

1.发后即忘:发送消息之后,只管消息是否发送,不关心消息是否发送成功; 2.同步:发送消息到RecoedAccumlator,等消息收集器中的消息在发送到Kafka集群中,在进行再次发送消息,send()方法调用get()方法来阻塞Kafka的响应,直到成功或失败;

3.异步:发送消息到RecoedAccumlator,不用等消息收集器中的消息在发送到Kafka集群中;

kafka在发送消息需要两个线程协调运行,一个是主线程,另一个是sender线程。在主线程中producer创建消息后,要经过拦截器、序列化器、分区器之后缓存到消息累加器,sender线程负责从消息累加器中将消息发送到Kafka,sender线程取到消息将消息转换为<Node,List>。下面简单介绍下拦截器(非必须)、序列化器、分区器和消息累加器。

拦截器:(非必须的)消息发送前的一些准备工作,按照某个规则过滤不符合要求的消息。 序列化器:将对象转换为字节数组才能通过网络发给kafka,消费端同时需要反序列换器将字节数组转化为对象。

分区器:消息分配分区。只有在没有指定partition字段,那么就需要依赖分区器,消息在序列化之后就会根据key进行hash计算出分区号,之后发往不同的分区。如果key为null,就会以轮询机制发送到主题内的可用的分区。

问题一:分区策略有哪些?

随机策略:也就是每次都随机地将消息分配到每个分区。

轮询策略:顺序轮流将每条数据分配到每个分区中

按照键进行hash值计算:根据键进行hash计算,来分配到不同的分区。

消息累加器:缓存消息方便sender线程可以批量发送,从而减少网络传输消耗以提升性能。消息累加器是个双端队列,消息在缓存到累加器的时候,会根据消息分区去找到对应的双端队列,如果没有就去创建,有的话判断队列是否允许进行再次添加消息,不可以再次创建。

5.Kafka的ack机制

指定分区中必须有多少副本收到这条消息,之后生产者才会认为这条消息写入成功。

ack=1:生产者发送消息后,只要分区leader副本成功写入消息就返回ack。但是如果leader挂掉,不能确保follower将leader的消息进行复制成功。

ack=0:生产者不需要等待broker的ack,这个延迟最低但是存储最弱,当server挂掉就会造成数据丢失。

ack=-1:在1的基础上,确保所有follower同步完数据才会向服务端成功响应。

6.能否讲解一下副本机制

副本就是只能追加消息的日志。

Kafka的副本机制:Kafka的副本分为领导者副本和跟随者副本,follower副本负责将leader的消息通步过来,但是follower不负责对外提供服务,当leader挂了之后,依托于zookeeper提供的监控功能,开启新的一轮选举出新的leader,如果之前老leader回来只能作为follower。

7.解释一下ISR

ISR副本都是与Leader通步的副本。

设置参数:replica.lag.max.messages:Follower 副本能够落后 Leader 副本的最长时间间隔,当前默认值是 10 秒。

这就是说,只要一个 Follower 副本落后 Leader 副本的时间不连续超过 10 秒,那么 Kafka 就认为该Follower 副本与 Leader 是同步的。

8.Consumer 的消费流程

  1. 消费者客户端应用程序启动时,首先会创建KafkaConsumer实例并启动;
  2. KafkaConsumer向服务器订阅对应的Topic,服务器异步返回Broker和Topic的元信息,这里的元信息一般包括:Topic、Parittion、Broker信息;
  3. KafkaConsumer向Broker拉取消息;
  4. Broker返回待消费的消息给KafkaConsumer;
  5. KafkaConsumer返回消息给消费业务程序,进行后续的业务处理。

9.Kafka消息采用的是推模式还是拉模式

拉模式

如果采用的推模式:由broker将消息推送给Consumer,但是对于一些消费较弱的消费者,就很不友好,当broker推送消息的速率大于consumer消费速率,就容器造成consumer崩溃。

如果采用拉取模式:consumer可以根据自己的消费能力进行制定消费策略拉进行消费数据。

10.消费者的处理再平衡策略的消费分区策略

range策略和roundrobin策略以及新增加的StickyAssignor策略

  1. range:按照消费者总数和分区总数整除运算获得一个跨度,让后将分区按照跨度进行分配。如果不够平均分配,那么字典序靠前的消费者会多分配一个分区。有可能出现部分消费者过载的情况。
  2. roundrobin:轮询策略,逐个将分区一次分配给每个消费者。如果同一个消费组每个消费者订阅消息是不同的。
  3. StickyAssignor:粘性策略;分区尽可能均匀,分区尽可能与上次分配的保持一致。

11.Kafka 的消费者如何消费数据

kafka消费就是一个不断轮询的过程,消费者就是要不断的调用poll方法,而poll方法就是返回订阅的主题上的一组信息。消费者每次消费的时候,消费者都会记录消费的offset位置,直到下次消费时,会接着上次位置继续消费。

12.消费者组的初始化流程

1.coordinator选择:辅助实现消费者组的初始化和分区的分配;

2.每个消费者在启动的时候都会选择一个broker作为自己的组协调器,负责监控这个消费组里边所有消费者的心跳、是否宕机,然后触发再平衡。

3.coordinator节点的选择是:groupid(hash值)%50

4.消费者组的消费者都会向每个kafka节点发送请求去查询属于自己的组协调器,并与之建立链接。

5.在成功加入到消费者组之后,组协调器会选择一个消费者作为消费者的leader。

6.组协调器会将所有消费者和topic发给leader

7.消费者leader会指定消费者消费方案(消费者如何消费消息及消费哪个分区的消息),同时把这个方案给组协调器。组协调器在下发给各个消费者。

13.触发再平衡的条件?

1.每个消费者都会与coordinator建立链接,心跳3S,一旦超时,该消费者会被移除,并触发再平衡。

2.消费者消费处理消息的时间过长,超过5min,也会触发再平衡。

14.消息的可靠性怎样保证?

1.通过ack机制

2.消息发送方式:可以通过同步或者异步来获取响应结果,失败重试机制保证消息的可靠性。

3.手动提交offset:等待业务提交完之后才进行提交offset。

15.消息如何避免重复消费?

KafkaBroker上储存的消息,都有一个Offset的标记,然后Kafka的消费者通过Offset标记来维护当前已经消费的数据,消费一批数据broker就会更新offset的值,避免重复消费。Kafka消费者端的自动提交有一个默认的5s的间隔,也就说在5s后下一次向Broker拉取消息的时候提交。

出现重复的情况:

1.在Consumer消费的过程中,应用程序宕机可能会导致offset没有提交,从而产生重复提交的问题;

2.一旦服务端在设定的超时时间内没有收到消费者发起的心跳,则认为这个消费者已经死掉,就会执行Rebalance动作。

  • kafka的consumer会从broker里面取出一批数据,消费线程进行消费。

  • 由于取出的一批消息数量太大,consumer在`session.timeout.ms(group coordinator检测consumer发生崩溃所需的时间)时间之内没有消费完成;

  • consumer coordinator 会由于没有接受到心跳而挂掉。

  • 由于自动提交offset失败,导致重新分配了partition的客户端又重新消费之前的一批数据。

  • 接着consumer重新消费,又出现了消费超时,无限循环下去。

    由于使用了spring-kafka,则把kafka-client的enable.auto.commit设置成了false,表示禁止kafka-client自动提交offset

解决:

1.消费者手动提交,业务逻辑处理完之后就提交Offset

2.减少一次性从Broker中拉取消息的条数。

3.可以针对每一条消息生成MD5然后保存到mysql或者redis里面,在处理消息之前先去mysql或者redis中判断是否已经消费过。