|NO.Z.00074|——————————|BigDataEnd|——|Hadoop&kafka.V59|——|kafka.v59|稳定性|控制器|
一、控制器
### --- 控制器
~~~ Kafka集群包含若干个broker,broker.id指定broker的编号,编号不要重复。
~~~ Kafka集群上创建的主题,包含若干个分区。
~~~ 每个分区包含若干个副本,副本因子包括了Follower副本和Leader副本。
~~~ 副本又分为ISR(同步副本分区)和OSR(非同步副本分区)。
~~~ 控制器就是一个broker。
~~~ 控制器除了一般broker的功能,还负责Leader分区的选举。

二、broker选举
### --- broker选举
~~~ 集群里第一个启动的broker在Zookeeper中创建临时节点<KafkaZkChroot>/controller 。
~~~ 其他broker在该控制器节点创建Zookeeper watch对象,使用Zookeeper的监听机制接收该节点的变更。
~~~ 即:Kafka通过Zookeeper的分布式锁特性选举集群控制器。
~~~ 下图中,节点/myKafka/controller 是一个zookeeper临时节点,其中"brokerid":0 ,
~~~ 表示当前控制器是broker.id为0的broker。
[zk: localhost:2181(CONNECTED) 0] get /myKafka/controller
{"version":1,"brokerid":0,"timestamp":"1632434689604"}
cZxid = 0x432
ctime = Fri Sep 24 06:04:49 CST 2021
mZxid = 0x432
mtime = Fri Sep 24 06:04:49 CST 2021
pZxid = 0x432
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x100001417d10001
dataLength = 54
numChildren = 0
### --- 每个新选出的控制器通过 Zookeeper 的条件递增操作获得一个全新的、数值更大的 controllerepoch。
~~~ 其他 broker 在知道当前 controller epoch 后,
~~~ 如果收到由控制器发出的包含较旧epoch 的消息,就会忽略它们,以防止“脑裂”。
~~~ 比如当一个Leader副本分区所在的broker宕机,需要选举新的Leader副本分区,
~~~ 有可能两个具有不同纪元数字的控制器都选举了新的Leader副本分区,
~~~ 如果选举出来的Leader副本分区不一样,听谁的?脑裂了。有了纪元数字,
~~~ 直接使用纪元数字最新的控制器结果。
[zk: localhost:2181(CONNECTED) 1] get /myKafka/controller_epoch
4
cZxid = 0x1b
ctime = Thu Sep 23 22:48:42 CST 2021
mZxid = 0x433
mtime = Fri Sep 24 06:04:49 CST 2021
pZxid = 0x1b
cversion = 0
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
~~~ # 当控制器发现一个 broker 已经离开集群,
~~~ # 那些失去Leader副本分区的Follower分区需要一个新Leader(这些分区的首领刚好是在这个 broker 上)。
~~~ 1. 控制器需要知道哪个broker宕机了?
~~~ 2. 控制器需要知道宕机的broker上负责的时候哪些分区的Leader副本分区?
~~~ # 下图中, <KafkaChroot>/brokers/ids/0 保存该broker的信息,
~~~ # 此节点为临时节点,如果broker节点宕机,该节点丢失。
~~~ # 集群控制器负责监听ids 节点,一旦节点子节点发送变化,集群控制器得到通知。
[zk: localhost:2181(CONNECTED) 2] get /myKafka/brokers/ids/0
{"listener_security_protocol_map":{"PLAINTEXT":"PLAINTEXT"},"endpoints":["PLAINTEXT://hadoop01:9092"],"jmx_port":-1,"host":"hadoop01","timestamp":"1632434690085","port":9092,"version":4}
cZxid = 0x437
ctime = Fri Sep 24 06:04:50 CST 2021
mZxid = 0x437
mtime = Fri Sep 24 06:04:50 CST 2021
pZxid = 0x437
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x100001417d10001
dataLength = 186
numChildren = 0
### --- 控制器遍历这些Follower副本分区,并确定谁应该成为新Leader分区,
~~~ 然后向所有包含新Leader分区和现有Follower的 broker 发送请求。
~~~ 该请求消息包含了谁是新Leader副本分区以及谁是Follower副本分区的信息。
~~~ 随后,新Leader分区开始处理来自生产者和消费者的请求,
~~~ 而跟随者开始从新Leader副本分区消费消息。
~~~ 当控制器发现一个 broker 加入集群时,
~~~ 它会使用 broker ID 来检查新加入的 broker 是否包含现有分区的副本。
~~~ 如果有,控制器就把变更通知发送给新加入的 broker 和其他 broker,
~~~ 新 broker上的副本分区开始从Leader分区那里消费消息,与Leader分区保持同步。
### --- 结论:
~~~ Kafka 使用 Zookeeper 的分布式锁选举控制器,并在节点加入集群或退出集群时通知控制器。
~~~ 控制器负责在节点加入或离开集群时进行分区Leader选举。
~~~ 控制器使用epoch 来避免“脑裂”。“脑裂”是指两个节点同时认为自己是当前的控制器。
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
bdv013-kafka
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通