点一下关注吧!!!非常感谢!!持续更新!!!
🚀 AI篇持续更新中!(长期更新)
AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!"快的模型 + 深度思考模型 + 实时路由",持续打造实用AI工具指南!📐🤖
💻 Java篇正式开启!(300篇)
目前2025年08月18日更新到: Java-100 深入浅出 MySQL事务隔离级别:读未提交、已提交、可重复读与串行化 MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈! 大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

章节内容
上节我们完成了如下内容:
- 事务相关配置
- 事务幂等性
- 事务操作
- 案例1:单Producer 保证仅发送一次
- 案例2:消费-转换-生产 事务仅保证一次发送

控制器
基本介绍

Kafka集群架构
- Kafka集群由若干个Broker(服务器节点)组成,构成分布式消息系统。每个Broker都需要配置唯一的broker.id标识其身份,编号范围通常从0开始连续递增,确保整个集群中没有重复的ID。例如,一个3节点的集群可能配置broker.id=0、broker.id=1和broker.id=2。
主题与分区
- 在Kafka集群上创建的主题(Topic)是消息的逻辑分类,每个主题会被划分为若干个分区(Partition)。分区是Kafka并行处理的基本单位,例如一个主题可以配置为10个分区,这样就能同时被10个消费者并行消费。
副本机制
- 每个分区都有若干个副本(Replica),副本数量由配置的副本因子(replication factor)决定。假设设置副本因子为3,则每个分区会有3个副本。
- 副本分为两种角色:
- Leader副本:负责处理该分区的所有读写请求
- Follower副本:从Leader副本同步数据,不直接服务客户端请求
副本状态
Kafka通过副本状态来管理数据同步:
- ISR(In-Sync Replicas):同步副本集合,包含与Leader保持同步的副本。这些副本的数据与Leader基本一致,当Leader失效时,会从ISR中选举新的Leader。
- OSR(Out-of-Sync Replicas):非同步副本集合,包含与Leader同步滞后的副本。这些副本可能由于网络问题、机器故障等原因暂时无法与Leader保持同步。
示例场景:假设一个分区的副本因子为3(1个Leader+2个Follower),其中1个Follower因为网络延迟导致同步滞后超过replica.lag.time.max.ms(默认30秒)配置的时间,就会被移出ISR放入OSR,直到它重新追上Leader的进度才会被重新加入ISR。
Broker选举
控制器信息
集群里第一个启动的Broker在ZooKeeper中创建了临时的节点
shell
<KafkaZkChroot>/controller
其他Broker在该控制器节点创建ZooKeeperWatch对象,使用ZooKeeper的监听机制接收该节点的变更。 即:Kafka通过ZooKeeper的分布式特性选举集群控制器。
下图中,节点 /controller 是一个Zookeeper临时节点,其中Brokerid:0,表示当前控制器是broker.id为0的Broker。 每个新选出的控制器通过ZooKeeper的条件递增操作获得一个全新的、数值更大的controller epoch。其他Broker在知道当前controller epoch后,如果收到由控制器发出的包含较旧epoch的消息,就会忽略它们,以防止脑裂。 比如当一个Leader副本分区所在的Broker宕机,需要选举新的Leader副本分区,有可能两个具有不同纪元数字的控制器都选举了新的Leader副本分区,如果选举出来的Leader副本分区不一样,听谁的?脑裂的时候,有纪元数字,直接使用纪元数字最新的控制器结果。
当控制器发现一个Broker离开集群,那些失去Leader副本分区的Follower分区需要一个新的Leader。
控制器宕机
当Kafka集群中的控制器(Controller)发生宕机时,整个集群的协调和管理功能会受到影响。控制器是Kafka集群中一个特殊的Broker节点,负责管理集群状态、分区Leader选举等关键任务。控制器宕机后需要考虑以下问题:
1. 控制器宕机的影响
- 集群协调功能中断:控制器宕机后,无法进行分区Leader选举、副本重分配等操作,可能导致部分分区无法正常工作
- 元数据同步延迟:新的控制器需要重新加载集群状态信息,从Zookeeper获取最新数据,这期间集群状态可能出现不一致
2. 控制器恢复的步骤
控制器重新选举后,新的控制器需要进行以下操作来恢复集群状态:
- 重新加载元数据 :
- 从Zookeeper读取最新的分区和Broker信息
- 从其他Broker节点同步未保存的元数据
- 验证元数据的完整性和一致性
- 恢复集群状态 :
- 重新计算分区的Leader和Follower副本
- 检查副本的同步状态,确保数据一致性
- 重新分配副本,平衡集群负载
- 恢复集群管理功能 :
- 重新启动关键服务,如副本重分配、Leader选举等
- 监控集群状态,确保恢复过程中不会出现新的问题
3. 控制器恢复的注意事项
- 恢复时间:新控制器启动后,恢复集群状态的时间取决于集群规模和数据量
- 数据一致性检查:在恢复过程中,需要验证数据的一致性,防止数据丢失或损坏
- 监控和日志:在控制器恢复期间,需要密切关注集群状态和日志,及时发现和处理问题
4. 控制器宕机的预防措施
为了降低控制器宕机对集群的影响,可以采取以下预防措施:
- 配置高可用控制器:部署多个控制器节点,避免单点故障
- 定期备份元数据:将元数据备份到安全的位置,如分布式存储系统
- 监控控制器状态:实时监控控制器节点的健康状况和资源使用情况,提前发现和解决问题 下图中,/brokers/ids/0 保存着Broker的信息,此节点为临时节点,如果Broker节点宕机,该节点丢失。 集群控制器负责监听ids节点,一旦节点子节点发生变化,集群控制器就会得到通知。

- 控制器遍历这些Follower副本分区,并确定谁应该成为新的Leader分区,然后向所有包含新Leader分区和现有Follower的Broker发送请求。
- 该请求消息包含了谁是新的Leader副本分区以及谁是Follower副本分区的信息,随后,新Leader分区开始处理来自生产者和消费者的请求,而跟随者开始从新Leader副本分区消费消息。
- 当控制器发现一个Broker加入集群时,它会使用BrokerId来检查新加入的Broker是否包含现有分区的副本。如果有,控制器就把变更通知发送给新加入的Broker和其他Broker,新Broker上的副本分区开始从Leader分区那里消费消息,与Leader分区保持同步。
最后结论
- Kafka使用ZooKeeper的分布式锁选举控制器,并在节点加入集群或退出集群时通知控制器
- 控制器负责在节点加入或离开集群时进行分区Leader选举
- 控制器使用epoch来避免脑裂(脑裂是指两个节点同时认为自己是当前的控制器)
可靠性保证
Kafka副本机制详解
Topic创建与副本配置
在创建Topic时,可以通过--replication-factor
参数指定副本数量(建议设置为3以保证高可用性)。需要注意的是:
- 副本数不能超过当前集群中可用的Broker数量
- 生产环境中通常设置为3,这样允许1个副本失效而不影响服务可用性
- 示例命令:
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
Leader-Follower架构
Kafka采用主从复制架构:
- Leader副本 :
- 每个分区只有一个Leader
- 负责处理所有读写请求
- 维护ISR(In-Sync Replicas)列表
- Follower副本 :
- 被动复制Leader的数据
- 通过定期发送fetch请求同步数据(默认每500ms)
- 不直接服务客户端请求
- 当Leader失效时,Controller会从ISR中选举新的Leader
ISR机制详解
In-Sync Replicas是保证数据一致性的核心机制:
-
维护条件:
- Follower必须定期与Leader保持心跳(默认10秒内)
- 不能落后Leader太多(通过
replica.lag.time.max.ms
控制)
-
异常处理:
- 当Follower超过
replica.lag.time.max.ms
(默认10000ms)未同步时 - Leader会将其从ISR列表中移除
- 监控指标:
kafka.server:type=ReplicaManager,name=IsrShrinks
- 当Follower超过
-
配置建议:
properties# 建议生产环境配置 replica.lag.time.max.ms=30000 unclean.leader.election.enable=false
消息可靠性保证
通过acks
参数控制消息持久化级别:
-
acks=all(最高可靠性):
- 消息写入流程:
- Producer发送消息到Leader
- Leader将消息写入本地日志
- Follower通过fetch请求拉取消息
- Follower持久化后发送ACK给Leader
- Leader收到所有ISR副本的ACK后提交消息
- Leader向Producer返回ACK
- 确保消息不会丢失,但会增加延迟(通常50-100ms)
- 消息写入流程:
-
其他ack级别:
acks=0
:不等待任何确认acks=1
:仅等待Leader确认(默认)- 生产建议:对关键业务设置
acks=all
和min.insync.replicas=2
最佳实践建议
- 监控ISR变化,设置告警
- 保持至少3个副本,且
min.insync.replicas
设置为2 - 对于关键业务:
java
// Producer配置示例
props.put("acks", "all");
props.put("retries", 3);
props.put("max.in.flight.requests.per.connection", 1);
- 定期测试Broker故障场景,验证副本选举机制
副本的分配
当某个Topic的--replication-factor为N(N>1)时,每个Partition都有N个副本,称作Replica,原则上是将Replica均匀地分配到整个集群上,不仅如此,Partition的分配也同样需要均匀分配,为了更好的负载均衡。
副本分配的三个目标:
- 均衡的将副本分撒于各个Broker上
- 对于某个Broker上分配的分区,尽量将分区的各个副本分配到不同的机架上的Broker。
- 如果所有的Broker都有机架信息,尽量将分区的各个副本分配到不同的机架上的Broker
在不考虑机架信息的情况下:
- 第一个副本分区通过轮询的方式挑选一个Broker,进行分配。该轮询从Broker列表的随机位置进行轮询
- 其余副本通过增加偏移进行分配

失效的副本
失效副本判定
replica.lag.time.max.ms 默认大小为 10000 当ISR中的一个Follower副本滞后Leader的时间超过参数设置之后,则判断副本失效,需要将此Follower副本踢出ISR。
实现原理
具体的实现原理:当Follower副本将Leader副本的LEO之前的日志全部同步时,则认为该Follower副本已经追赶上了Leader副本,此时更新该副本的lastCaughtUpTimeMs标识。 Kafka的副本管理器(ReplicaManager)启动时会启动一个副本过期检测的定时任务,而这个定时任务会定时检查当前时间与副本的lastCaughtUpTimeMs差值是否大于参数replica.lag.time.max.ms指定的值。
Kafka的源码注释中也说了一般有两种情况会导致副本失效:
- Follower副本进程卡住,在一段时间内没有向Leader副本发起同步请求,比如频繁的FULL GC。
- Follower副本进程同步过慢,在一段时间内都无法追赶上Leader副本,比如IO开销过大。
如果通过工具增加副本因子,那么新增加的副本在赶上Leader副本之前也都是失效状态的。 如果一个Follower副本由于某些原因(宕机)而下线,之后又上线,在追赶上Leader副本之前也是处于失效状态。
如何查看
失效副本的分区个数是用于衡量Kafka性能指标的重要部分。Kafka本身提供了一个相关的指标,即UnderReplicatedPartitions,可以通过JMX访问:
- kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions 取值范围是大于等于0的整数,需要注意,如果Kafka集群正在做分区迁移(kafka-reassign-partition.sh)的时候,这个值也会大于0。
副本复制
日志复制算法(lgo replication algorithm)必须提供的基本保证是,如果它告诉客户端消息已经被提交,而当前Leader出现故障,新选出的Leader也必须具有该消息,在出现故障时,Kafka会从挂掉Leader的ISR里面选择一个Follower作为这个分区新的Leader。 每个分区的Leader会维护一个 in-sync replica(同步副本列表,又称ISR)。当Producer向Broker发送消息,消息先写入到对应的Leader分区,然后复制到这个分区的所有副本中。ACKS=ALL时,只有将消息成功复制到所有同步副本(ISR)后,这条消息才算被提交。
什么情况会失去同步
一个副本与Leader失去同步的原因有很多,主要包括:
- 慢副本(Slow Replica):Follower replica 在一段时间内一直无法赶上Leader的写进度,造成这种情况的最常见原因之一是Follower replica上的 IO瓶颈,导致它持久化日志的时间比它从Leader消费时间要长
- 卡住副本(Stuck Replica):Follower replica 在很长一段时间内停止从Leader获取消息,这可能是因为GC停顿,或者副本故障
- 刚启动副本(Bootstrapping replica):当用户给某个主题增加副本因子时,新的Follower replicas是不同步的,直到它跟上
Leader日志
当副本落后于Leader分区时,这个副本被认为是不同步或者滞后的,在Kafka中,副本的滞后于Leader是根据replica.lag.tiime.max.ms来衡量。
如何确认某个副本滞后
通过replica.lag.time.max.ms来检测卡住的副本(Stuck replica)在所有情况下都能很好的工作,它跟踪Follower副本没有向Leader发送获取请求的时间,通过这可以推断Follower是否正常。另一方面,使用消息数量检测不同步慢副本(Slow replica)的模型只有在为单个主题或者具有同类流量模式的多个主题设置这些参数时才能很好的工作,但我们发现它不能扩展到生产集群中所有主题。