kafka常见面试问题

323 阅读7分钟

1.分区、消费者组,消费者 ,主题,生产者的慨念

同一个消费者组可以有多个消费者,一个消费者组共同消费一个topic消息,如果同一个组中的消费者已经消费了这条消息,那么其他消费者就不会消费这条消息了。多个消费者组订阅同一个topic的话,组之间的消费是互相隔离的,比如消费者组A消费了一条消息,消费者组B也会再次消费这条消息。

一个topic表示一类消息,可以指定这个消息存在几个分区(可以看作消息块,类似分库分表吧,把数据存在不同的物理空间上)上。在同一个消费者组中,一个消费者可以消费多个分区,一个分区只能有一个消费者消费。

一般在什么情况下需要指定分区数量呢?如何去指定呢

如果是Kafka是集群的话,我们可以把同一个topic消息均匀的分布到每个节点(broker)上面。比如我有三个kafka节点,我对这个topic的分区设置成三个,并且在写入分区的策略上设置成轮询方式这样消息就均匀的存储到了这三个节点上,再配合多个消费者消费(消费者消费分区也是有消费策略的),这样就提高了消息的生产和消费的速度。当然如果分区数量大于或者小于broker的数量,或者写入分区策略这些因数也会影响到消息的均匀分布情况。

指定主题的分区个数:

// topic 配置,也可以不用对topic就行设置,如果不设置分区,就是读取默认是server.properties里面的num.partitions 如果没有,分区就默认写道一个分区里面。
@Configuration
public class KafkaTopicConfig {
​
  /**
   * 创建 Topic
   */
  @Bean
  public NewTopic topicinfo() {
    // 创建topic,需要指定创建的topic的"名称"、"分区数"、"副本数量(副本数数目的值要小于等于Broker数量)"
    return new NewTopic(KafkaPrducer.TOPIC_TEST.toString(), 3, (short) 1);
  }

生产者是按照什么逻辑写到各个分区的呢

// kafka 中通过实现Partitioner接口去控制写入哪个分区的,不通过的版本可能会不一样,每个版本都有个默认的实现的 DefaultPartitioner,也可以自己去实现这个类,然后在配置文件中指定你要使用的实现类
//配置文件中指定要使用的写入分区策略的实现类:spring.kafka.producer.properties.partitioner.class = org.apache.kafka.clients.producer.RoundRobinPartitioner
public interface Partitioner extends Configurable, Closeable {
  int partition(String var1, Object var2, byte[] var3, Object var4, byte[] var5, Cluster var6);
​
  void close();
​
  default void onNewBatch(String topic, Cluster cluster, int prevPartition) {
  }
}

offset概念 按照消费者消费partion消息的偏移量来记录,记录在zookeeper中

如何保证消息写入的幂等性

生成者向broker 分区写入消息,broker给生产者返回Ack,如果返会Ack网络异常,生产消息端重新生产该条消息,消息产生重复,出现消息非幂等问题。kafka设置props.put("enable.idempoetence",true)开启冥等性。

幂等性实现原理
broker的分区消息会记录生产者的id+序号,这样在重复生产消息保存到分区的时候,如果发现生产者的序号小于等于当前记录消息的序号,就会识别出该条消息是已经保存过的消息了,就不保存直接返回ack 生产者Ack配置(生成者消息不丢失的措施:防止消息丢失的方式,以及同步异步消息发送,异步的化提供函数失败可以重新写入,包括副本同步,保证消息生产的稳定性;消费者:等待消息消费成功,再返回offset;保证消费者不重复消费:保证offset和消费业务逻辑保证事务,比如将mysql和保存数据的业务代码写到一个事务里里面,保证不重复消费)
1.ack 配置成0时,生产者不用等broker的leader分区做出ack响应 2ack 配置成1时,生产者等待leader响应之后产生下一条3.ack 配置成-1、all时候的等待leader 和 follower 都写入成功然后再返回Ack发吓一条消息

消息写入分区策略、消费策略

1.生产者写入消息的分区策略 1.轮询策略(默认) 2.随机策略(一般不用了) 3.根据key进行hash,可能存在数据倾斜,可能存在大量key的hash相同,造成改分区的数据偏多 4.自定义分区

2.消费者消费分区的分配策略 1.rang分配(默认) 2.轮询策略 3.粘性分配,在reblance的时候尽量保证于上一次分配相同。没有reblance的时候按轮询

3.消费者再均衡机制(reblance期间停止所有消费) 1.consumer的个数发生变化,消费者对应的消费分区重新分配 2.消费者组订阅的topic数量发生变化,也会发生再均衡 3.订阅topic的分区发生变化,也会发生再均衡

reblance触发时机以及不良影响 consumer group成员发生变更,比方说有新的consumer实例加入,或者有consumer实例离开组,或者有consumer实例发生奔溃。consumer group订阅的topic数发生变更,这种情况主要发生在基于正则表达式订阅topic情况,当有新匹配的topic创建时则会触发rebalance。consumer group 订阅的topic分区数发生变更。

reblance可能造成offset的丢失造成重复消费问题

leader的选举

kafka leader的选举必须要快,否则出现消息的积压影响消息的正常消费,启动的时候随机选举,尽量将leader分散到各个节点。leader由controller isr选举,controller针对broker的,controller是zk选举的

kafka读写流程

1.生产者从zk中获取leader位置,然后把消息发给leader2.消费者从zk中获取leader位置以及offset信息,然后访问leader拉取数据

kafka数据存储形式

1.topic的消息存在partion,partion又各个segement

4.分区分配策略

消费者如何防止消息重复消费

1、kafka是通过offset来标记消费的。默认情况下,消费完成后会自动提交offset,避免重复消费。

Kafka消费端的自动提交逻辑有一个默认的5秒间隔,也就是说在5秒之后的下一次向Broker拉取消息的时候提交。

所以在Consumer消费的过程中,应用程序被强制kill掉或者宕机,可能会导致Offset没提交,从而产生重复提交的问题。

2、Kafka里面有一个Partition Balance机制,就是把多个Partition均衡的分配给多个消费者。

Consumer端会从分配的Partition里面去消费消息,如果Consumer在默认的5分钟内没办法处理完这一批消息。

就会触发Kafka的Rebalance机制,从而导致Offset自动提交失败。

而在重新Rebalance之后,Consumer还是会从之前没提交的Offset位置开始消费,也会导致消息重复消费的问题。

如何避免1、提高消费端的处理性能避免触发Balance,比如可以用异步的方式来处理消息,缩短单个消息消费的市场。或者还可以调整消息处理的超时时间。还可以减少一次性从Broker上拉取数据的条数。

3、可以针对消息生成md5然后保存到mysql或者redis里面,在处理消息之前先去mysql或者redis里面判断是否已经消费过。这个方案其实就是利用幂等性的思想。————————————————版权声明:本文为CSDN博主「天帅风ztm」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:blog.csdn.net/qq_17199495…