《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。
文章目录
- 一、本文面试题目录
-
-
- 11. 什么是Kafka的分区(Partition)?为什么要进行分区?
- 12. 分区的数量对Kafka的性能有什么影响?如何确定分区数量?
- 13. Kafka的分区副本(Replica)有什么作用?
- 14. 什么是首领副本(Leader Replica)和追随者副本(Follower Replica)?它们的职责分别是什么?
- 15. 简述Kafka的副本同步机制(ISR机制)。
- 16. ISR(In-Sync Replicas)、OSR(Out-of-Sync Replicas)、AR(Assigned Replicas)的区别是什么?
- 17. 当Leader副本故障时,Kafka如何进行故障转移?
- 18. 什么是Kafka的消费者组(Consumer Group)?它的作用是什么?
- 19. 消费者组内的消费者如何分配分区?有哪些分配策略?
- 20. 消费者重平衡(Rebalance)是什么?触发重平衡的场景有哪些?
- 21. 重平衡会带来什么问题?如何避免或减轻其影响?
- 22. Kafka的消息是如何被持久化的?
-
- 二、100道Kafka 面试题目录列表
一、本文面试题目录
11. 什么是Kafka的分区(Partition)?为什么要进行分区?
Kafka的分区(Partition) 是Topic的物理分片,是Kafka实现并行处理和水平扩展的核心机制。每个Topic可以被划分为多个Partition,每个Partition是一个有序的、不可变的消息序列,消息被追加到Partition的末尾并分配唯一的偏移量(Offset)。
进行分区的主要原因:
- 提高吞吐量:多个Partition可以并行处理读写操作,大幅提升系统整体吞吐量
- 实现负载均衡:不同Partition可以分布在不同的Broker上,均衡集群负载
- 支持水平扩展:通过增加Partition数量或Broker节点扩展系统容量
- 保证局部有序性:每个Partition内部的消息是严格有序的,满足有序性需求
- 方便数据管理:可以针对不同Partition设置不同的存储和清理策略
示例:创建一个包含3个分区的Topic
# 使用kafka-topics.sh创建Topic
bin/kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic user-tracking \
--partitions 3 \
--replication-factor 2
12. 分区的数量对Kafka的性能有什么影响?如何确定分区数量?
分区数量对性能的影响:
- 正面影响:
- 更多分区可以提供更高的并行度,提高吞吐量
- 可以分布到更多Broker上,充分利用集群资源
- 负面影响:
- 过多分区会增加集群元数据管理开销
- 增加ZooKeeper的负担(旧版本)
- 增加消费者重平衡(Rebalance)的时间
- 每个分区都有副本,过多分区会占用更多内存和磁盘资源
确定分区数量的方法:
基于吞吐量需求:
- 先测试单个分区的吞吐量(如每秒1000条消息)
- 根据总吞吐量需求计算大致分区数(如需要每秒5000条则至少5个分区)
考虑消费者数量:
- 分区数应大于等于消费者组中消费者的数量,否则部分消费者会空闲
- 一般建议分区数是消费者数量的1-10倍
参考经验值:
- 对于一般业务场景,单个Topic的分区数建议在10-100之间
- 对于高吞吐量场景,可增加到数百个,但需监控集群性能
考虑存储和副本因素:
- 分区数 × 副本数不应过多,避免超出集群存储能力
示例:通过kafka-configs.sh查看和修改分区相关配置
# 查看Topic的分区配置
bin/kafka-topics.sh --describe --bootstrap-server localhost:9092 --topic user-tracking
# 增加分区数量(注意:只能增加不能减少)
bin/kafka-topics.sh --alter \
--bootstrap-server localhost:9092 \
--topic user-tracking \
--partitions 5
13. Kafka的分区副本(Replica)有什么作用?
Kafka的分区副本(Replica)是指为每个Partition创建的多个数据备份,分布在不同的Broker节点上。其主要作用如下:
提供数据冗余:
- 多个副本存储相同的数据,防止单点故障导致的数据丢失
- 即使部分Broker宕机,数据仍可从其他副本中获取
保证高可用性:
- 当Leader副本所在的Broker故障时,可从Follower副本中选举新的Leader
- 确保消息的生产和消费可以继续进行,不中断服务
提高读取性能:
- 允许消费者从Follower副本读取数据(可选配置)
- 分担Leader副本的读取压力,提高整体读取吞吐量
支持灵活的可靠性配置:
- 可以根据业务需求配置不同的副本数量
- 重要数据可配置更多副本,非重要数据可配置较少副本
示例:创建带有3个副本的Topic
bin/kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic payment-transactions \
--partitions 4 \
--replication-factor 3 # 每个分区有3个副本
14. 什么是首领副本(Leader Replica)和追随者副本(Follower Replica)?它们的职责分别是什么?
在Kafka中,每个Partition的多个副本中,有一个被指定为首领副本(Leader Replica),其余的则是追随者副本(Follower Replica)。
首领副本(Leader Replica)的职责:
- 处理所有针对该Partition的读写请求
- 维护消息的偏移量(Offset)信息
- 负责将新消息同步给所有Follower副本
- 决定哪些消息可以被消费者读取(已提交的消息)
追随者副本(Follower Replica)的职责:
- 从Leader副本同步消息,保持与Leader的数据一致性
- 当Leader副本故障时,参与Leader选举,可能成为新的Leader
- 不处理客户端的读写请求(默认配置下)
- 监控Leader的状态,确保自己与Leader保持同步
示例:查看分区的Leader和Follower分布
# 查看Topic的详细信息,包括每个分区的Leader和Follower
bin/kafka-topics.sh --describe --bootstrap-server localhost:9092 --topic payment-transactions
# 输出示例(简化):
# Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
# Partition: 1 Leader: 2 Replicas: 2,0,1 Isr: 2,0,1
15. 简述Kafka的副本同步机制(ISR机制)。
Kafka的副本同步机制主要通过ISR(In-Sync Replicas,同步副本集合) 实现,确保消息在多个副本之间的一致性:
ISR定义:
- ISR是指与Leader副本保持同步的Follower副本集合,包括Leader本身
- 只有ISR中的副本才有资格被选举为新的Leader
同步过程:
- 生产者发送消息到Leader副本
- Leader将消息写入本地日志,并向Follower发送同步请求
- Follower从Leader拉取消息,写入本地日志,并向Leader发送确认
- 当Leader收到足够多的ISR副本确认后,标记消息为"已提交"(Committed)
- 只有已提交的消息才会被消费者读取
同步条件:
- Follower必须在规定时间内(replica.lag.time.max.ms,默认30秒)向Leader发送fetch请求
- Follower的消息偏移量与Leader的差距不能超过规定阈值(replica.lag.max.messages,已过时)
动态调整:
- 当Follower落后太多或长时间未通信,会被移出ISR
- 当Follower重新跟上Leader的进度,会被重新加入ISR
示例:修改ISR相关配置(server.properties)
# Follower多久未发送请求会被踢出ISR,默认30000ms
replica.lag.time.max.ms=30000
# 首领在认为消息已提交前需要收到的确认数
min.insync.replicas=2
16. ISR(In-Sync Replicas)、OSR(Out-of-Sync Replicas)、AR(Assigned Replicas)的区别是什么?
ISR、OSR和AR是Kafka中描述副本状态的三个重要概念,它们的区别如下:
AR(Assigned Replicas,已分配副本):
- 定义:为某个Partition配置的所有副本的集合
- 包含:Leader副本 + 所有Follower副本
- 特点:数量等于副本因子(replication factor),一旦配置后不会轻易改变
- 示例:如果一个Partition的副本因子是3,那么AR就包含3个副本
ISR(In-Sync Replicas,同步副本):
- 定义:与Leader副本保持同步状态的副本集合
- 包含:Leader副本 + 所有与Leader保持同步的Follower副本
- 特点:是AR的子集,会动态变化;只有ISR中的副本可以被选举为新Leader
- 同步标准:在规定时间内与Leader通信,且消息偏移量差距在允许范围内
OSR(Out-of-Sync Replicas,非同步副本):
- 定义:与Leader副本不同步的Follower副本集合
- 包含:AR中除去ISR的所有副本
- 特点:因落后太多或长时间未通信而被移出ISR;不参与消息确认和Leader选举
- 可能原因:网络问题、Follower负载过高、硬件性能不足等
三者关系:AR = ISR + OSR,其中ISR始终包含Leader副本。
示例:查看分区的AR、ISR状态
bin/kafka-topics.sh --describe --bootstrap-server localhost:9092 --topic order-events
# 输出示例解释:
# Partition: 0 Leader: 2 Replicas: 2,0,1 Isr: 2,0
# 说明:AR = [2,0,1],ISR = [2,0],OSR = [1]
17. 当Leader副本故障时,Kafka如何进行故障转移?
当Leader副本所在的Broker发生故障时,Kafka通过以下机制进行故障转移,确保服务连续性:
故障检测:
- ZooKeeper(或Kafka控制器)监控所有Broker的心跳状态
- 当Leader所在Broker超过一定时间(默认6秒)未发送心跳,判定为故障
触发Leader选举:
- 控制器(Controller)负责检测到Leader故障后发起选举
- 控制器是Kafka集群中的一个特殊Broker,负责管理分区Leader选举
选举新Leader:
- 从该Partition的ISR(同步副本集合)中选择新的Leader
- 选举优先级:通常选择ISR中副本偏移量最大的Follower(最接近Leader的状态)
- 如果ISR为空,可配置是否允许从OSR中选举(unclean.leader.election.enable)
更新元数据:
- 新Leader选举完成后,控制器更新集群元数据
- 将新的Leader信息广播给所有Broker和消费者
恢复服务:
- 新Leader开始处理读写请求
- 其他Follower开始从新Leader同步数据
- 客户端(生产者和消费者)通过元数据更新知道新的Leader位置
示例:配置故障转移相关参数(server.properties)
# 控制器检测Broker故障的超时时间
controller.socket.timeout.ms=30000
# 是否允许从非同步副本中选举Leader(不推荐开启)
unclean.leader.election.enable=false
# 副本同步的超时时间
replica.lag.time.max.ms=30000
18. 什么是Kafka的消费者组(Consumer Group)?它的作用是什么?
Kafka的消费者组(Consumer Group) 是由多个消费者实例组成的群体,共同消费一个或多个Topic的消息。每个消费者组有一个唯一的ID,组内的消费者协同工作。
消费者组的主要作用:
负载均衡:
- 多个消费者共同分担消费压力,提高消息处理能力
- 每个Partition的消息只会被组内的一个消费者消费
高可用性:
- 当组内某个消费者故障时,其负责的Partition会被分配给其他消费者
- 保证消费过程不中断,提高系统可用性
并行处理:
- 不同Partition的消息可以被不同消费者并行处理
- 提高整体消息处理吞吐量
灵活的消费模式:
- 同一个Topic可以被多个消费者组同时消费(发布-订阅模式)
- 每个消费者组独立维护自己的消费偏移量
示例:使用Java客户端创建消费者组
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Properties;
import java.util.Arrays;
public class ConsumerGroupExample {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
// 消费者组ID,相同ID的消费者属于同一个组
props.put("group.id", "order-processing-group");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
// 订阅主题
consumer.subscribe(Arrays.asList("order-events"));
// 消费消息的逻辑...
}
}
19. 消费者组内的消费者如何分配分区?有哪些分配策略?
消费者组内的分区分配是指将订阅Topic的所有Partition分配给组内的消费者,确保每个Partition只被一个消费者消费。Kafka提供了多种分配策略:
分配过程:
- 消费者加入组后,由组协调器(Coordinator)负责分配
- 协调器从组内选择一个消费者作为leader,负责执行分配逻辑
- 分配结果被广播给所有消费者
- 每个消费者只处理分配给自己的Partition
主要分配策略:
Range(范围分配,默认策略):
- 按Topic分组,为每个Topic的Partition按顺序分配
- 为每个消费者分配连续的Partition范围
- 优点:简单直观;缺点:可能导致分配不均
RoundRobin(轮询分配):
- 将所有Topic的Partition排序后,按轮询方式分配给消费者
- 优点:分配更均衡;缺点:当消费者订阅不同Topic时可能不够灵活
Sticky(粘性分配):
- 尽量保持现有分配不变,仅在必要时进行最小调整
- 优点:减少重平衡时的分配变化,降低开销;缺点:实现复杂
CooperativeSticky(协作粘性分配):
- 是Sticky策略的改进版,支持增量重平衡
- 不需要暂停所有消费者,提高重平衡效率
示例:配置消费者分配策略
Properties props = new Properties();
// 其他配置...
// 设置分配策略,可指定多个,按优先级尝试
props.put("partition.assignment.strategy",
"org.apache.kafka.clients.consumer.StickyAssignor");
// 或者使用轮询策略
// props.put("partition.assignment.strategy",
// "org.apache.kafka.clients.consumer.RoundRobinAssignor");
20. 消费者重平衡(Rebalance)是什么?触发重平衡的场景有哪些?
消费者重平衡(Rebalance) 是指消费者组内重新分配Partition与消费者之间映射关系的过程。当组内消费者数量或订阅的Topic分区数量发生变化时,会触发重平衡,以确保Partition被均匀分配。
触发重平衡的主要场景:
消费者加入组:
- 新的消费者启动并加入已有的消费者组
- 例如:为提高处理能力,增加新的消费者实例
消费者离开组:
- 消费者主动关闭(正常退出)
- 消费者崩溃或网络故障导致与协调器失联(超过session.timeout.ms)
订阅的Topic发生变化:
- 消费者组订阅了新的Topic
- 已订阅的Topic被删除
Topic的分区数量发生变化:
- 管理员为已订阅的Topic增加了分区数量
- 注意:Kafka不支持减少分区数量
消费者长时间未发送心跳:
- 消费者处理消息时间过长,超过max.poll.interval.ms
- 协调器认为消费者已失效,将其移出组并触发重平衡
示例:重平衡相关配置
Properties props = new Properties();
// 其他配置...
// 消费者会话超时时间,默认10秒
props.put("session.timeout.ms", "10000");
// 两次poll之间的最大间隔,默认5分钟
props.put("max.poll.interval.ms", "300000");
// 每次poll请求获取的最大记录数
props.put("max.poll.records", "500");
21. 重平衡会带来什么问题?如何避免或减轻其影响?
重平衡带来的问题:
消费暂停:
- 重平衡期间,所有消费者停止消费消息
- 导致消息处理延迟增加,可能影响业务
重复消费:
- 重平衡后,消费者可能处理之前已处理过的消息
- 尤其在未及时提交偏移量的情况下
负载不均:
- 重平衡后可能出现分区分配不均的情况
- 导致部分消费者负载过重,部分空闲
系统开销增大:
- 重平衡过程需要协调多个组件通信
- 频繁重平衡会消耗大量集群资源
避免或减轻影响的方法:
减少重平衡频率:
- 合理设置session.timeout.ms和heartbeat.interval.ms
- 确保消费者能及时发送心跳,避免被误判为失效
优化重平衡性能:
- 使用Sticky或CooperativeSticky分配策略
- 控制消费者组大小,避免过大的消费者组
处理重复消费:
- 实现消息处理的幂等性
- 及时提交消费偏移量
平滑扩展:
- 避免频繁增减消费者实例
- 扩展时一次增加足够数量的消费者
示例:优化重平衡配置
Properties props = new Properties();
// 其他配置...
// 心跳间隔,应小于session.timeout.ms的1/3
props.put("heartbeat.interval.ms", "3000");
// 会话超时时间,根据业务处理时间设置
props.put("session.timeout.ms", "10000");
// 使用协作粘性分配策略,支持增量重平衡
props.put("partition.assignment.strategy",
"org.apache.kafka.clients.consumer.CooperativeStickyAssignor");
// 自动提交偏移量的间隔
props.put("auto.commit.interval.ms", "5000");
22. Kafka的消息是如何被持久化的?
Kafka采用磁盘存储的方式持久化消息,通过一系列优化机制实现了高性能的持久化操作:
日志文件结构:
- 每个Partition对应一个日志目录,包含多个日志片段(Segment)
- 每个Segment由一个数据文件(.log)和一个索引文件(.index)组成
- 数据文件存储实际消息,索引文件存储消息偏移量与物理位置的映射
写入机制:
- 消息被追加到当前活跃Segment的末尾(顺序写)
- 先写入操作系统的页缓存(Page Cache),再异步刷盘
- 支持配置刷盘策略(如按时间或消息数量)
刷盘策略:
- 可配置log.flush.interval.messages(按消息数)
- 可配置log.flush.interval.ms(按时间)
- 默认依赖操作系统的刷盘机制,平衡性能和可靠性
日志保留策略:
- 按时间保留:log.retention.hours(默认168小时/7天)
- 按大小保留:log.retention.bytes
- 超过保留期限的Segment会被后台线程删除或压缩
零拷贝技术:
- 读取消息时使用零拷贝(mmap + sendfile)技术
- 避免用户态和内核态之间的数据拷贝,提高读取性能
示例:配置消息持久化相关参数(server.properties)
# 消息保留时间,默认7天
log.retention.hours=168
# 每个分区的最大保留字节数,默认-1(无限制)
log.retention.bytes=-1
# 每个Segment文件的最大大小,默认1GB
log.segment.bytes=1073741824
# 检查日志是否需要清理的间隔时间
log.retention.check.interval.ms=300000
# 刷盘策略:每500条消息刷盘
log.flush.interval.messages=500
# 刷盘策略:每5秒刷盘
log.flush.interval.ms=5000
Kafka的持久化设计兼顾了性能和可靠性,通过顺序写入、页缓存、零拷贝等技术,即使使用磁盘存储也能实现高性能的消息处理。