Kafka源码阅读 —— KafkaController(3)
来源:互联网 发布:应用文理学院网络学堂 编辑:程序博客网 时间:2024/04/30 18:09
执行 kafka-topics.sh –create
Kafka官网给出的创建Topic的命令如下: bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
这条命令中的信息包括:zookeeper地址、分区副本数、分区数和topic名。
执行新建Topic的第一步是给各个Partition分配replica:
首先,分配replica有个前提:partition副本数 < broker 数,否则无法做到一个broker上只能有同一partition的一个副本。
分配算法很简单,在代码的注释里有个例子,这里简化了一下:
分区1的副本1,副本2,副本3分别位于broker-0,broker-1,broker-2,而分区2则从broker-2开始进行分配,三个副本分别位于broker-1,broker-2,broker-0上,分区3依次类推,位于broker-3,broker-1,broker-2上。
总结下,broker数目为m,副本数为n,则第i个分区从broker编号(i-1)%m 开始分配,i分区的第j个副本分配到编号((i-1)%m+(j-1))%m的broker上。
在实现中,分区1第一个replica分配的broker id是随机的,后面的分配都加上这个随机的偏移量。kafka中,分配返回的结果是 Map[Int, Seq[Int]]
类型,对应的是 partitionId -> replicaList,其中replica id和broker id是等价的,因为一个broker上只能有一个副本。replicaList中的顺序是有意义的,partition选举leader时,会参考这个顺序。
分配完replica后,AdminUtils将副本分配信息以json串的方式写入到zookeeper路径/brokers/topics/[topic]/下。到此,命令create topic的工作就做完了,剩下的工作由zookeeper数据变化触发。
状态机响应zookeeper变化
在埋到源码里面之前,先想想,Controller创建Topic,需要执行什么操作呢?
- 从zookeeper中读取Topic的信息,在map中保存Partition和所有Replica的状态。Partition状态的含义应该包含是否选举Leader,Leader是否在线等;而Replica的状态也类似,主要是该replica是否在线;
- 选举Partition的leader,并将Partition相关信息发送给各个broker;
- broker收到Controller发送的Partition信息,创建replica,如果是Leader,需要将ISR,AR,high wartermark等信息保存下来,如果是Follower,则添加到Leader的Fecher,定期从Leader拉取数据。
接下来,看看Kafka是怎么实现这些的呢?
在KafkaController leader选举成功后,在PartitionStateMachine.registerListeners()
中注册了路径/brokers/topics/上的监听器TopicChangeListener
,在create topic命令修改zookeeper中的数据后会触发函数TopicChangeListener.handleChildChange
,它监听topics下子目录列表的变化,执行逻辑如下:
KafkaController.onNewTopicCreation函数代码如下:
/* - topics: 新增topic列表 - newPartitions:新增的partition列表*/ def onNewTopicCreation(topics: Set[String], newPartitions: Set[TopicAndPartition]) { //对每个topic注册/brokers/topics/[topic]/下的监听器 topics.foreach(topic => partitionStateMachine.registerPartitionChangeListener(topic)) //执行新建partition操作 onNewPartitionCreation(newPartitions) }
上面代码执行了两个操作:
- 添加监听路径/brokers/topics/[topic]/下数据变化的Listener类
AddPartitionsListener
,有新的partition加入时函数AddPartitionsListener.handleDataChange
被调用,最终通过KafkaController.onNewPartitionCreateaion创建新的partition。 - 对所有新增topic下的分区调用onNewPartitionCreation。在onNewPartitionCreation中,partition经历了两步状态变化:NonExistentPartition->
NewPartition
->OnlinePartition;同时,partition下的所有replica也一样发生了状态变化:NonExistentReplica->NewReplica->OnlineReplica。Partition的状态变化是通过PartitionStateMachine实现的,而replica的状态变化则是通过ReplicaStateMachine实现的。
那么,在partition和replica状态变化过程中执行了什么操作呢?执行顺序如下:
- NonExistentPartition-> NewPartition:从zookeeper中读取partition的replica 分配信息到ControllerContext中;
- NonExistentReplica -> NewReplica:在create topic的场景下,仅更新replica的状态为NewReplica;
- NewPartition->OnlinePartition:选举Leader,这里的Leader选举方法很简单,直接选择活着的replica列表中的第一个作为Leader,replica分配过程中顺序是有意义的。得到Leader后,向Partition下所有活着的replica发送LeaderAndIsrRequest,replica收到消息后执行的动作参见“Kafka源码阅读 —— KafkaController(2)”;
- NewReplica->OnlineReplica:在create topic场景下,仅更新replica状态为NewReplica,
用一个图总结一下create topic执行过程:
Partition状态机
Partition的状态有:NewPartition,OnlinePartition,OfflinePartition和NonExistentPartition这四种。下面是这几个状态之间的转换图:
大部分的转换都仅仅只更新Partition的状态,其他状态到OnlinePartition,都需要选举Leader,更新zookeeper,并向Partition下的所有replica发送LeaderAndIsrRequest请求;
Replica状态机
Replica的状态的可能值有:NewReplica,OnlineReplica,OfflineReplica,ReplicaDeletionStarted,ReplicaDeletionSuccessful,NonExistentReplica,ReplicaDeletionIneligible。
NewReplica,OnlineReplica,OfflineReplica这三种状态是在正常服务时,replica可能的状态;Replica的状态变化比较复杂一下,详细说下变化到某个状态需要执行的操作:
- NewReplica:如果在zookeeper中存在分区的LeaderAndIsr信息(该Replica不是在新增topic时新增的),则给该replica发送LeaderAndIsrRequest消息;否则仅更新状态;
- OnlineReplica:如果是NewReplica->OnlineReplica,则将replica加入到context的相应partition的AR中;如果是从其他状态变更到OnlineReplica,则发送LeaderAndIsrRequest到当前replica;
- OfflineReplica:首先给当前replica所在broker发送StopReplicaRequest(deletePartition=false)消息;其次,将replica从所在Partition的ISR中移除,变化写入到zookeeper中后给除去当前replica的所有replica发送LeaderAndIsrRequest,更新这些replica所在broker上存放的LeaderAndIsr信息,也别忘了,发送LeaderAndIsrRequest的同时还会发送UpdateMetadataRequest信息;
- ReplicaDeletionStarted:这个状态表示replica进入删除逻辑,给当前replica所在broker发送StopReplicaRequest(deletePartition=true)消息;“Kafka源码阅读 —— KafkaController(2)”说道过,在这种情形下,broker会删除replica对应的log文件。
- ReplicaDeletionSuccessful:仅更新状态;
- NonExistentReplica:删除Replica完成,从context中抹去;
- ReplicaDeletionIneligible:仅更新状态,这个属于删除异常状态,如删除操作开始后replica所在broker出现failover;
- Kafka源码阅读 —— KafkaController(3)
- Kafka源码阅读 —— KafkaController(1)
- Kafka源码阅读 —— KafkaController(2)
- Kafka源码阅读 —— KafkaController(4)
- Kafka源码阅读 —— KafkaController(5)
- 【Kafka源码】KafkaController启动过程
- kafka源码解析之十二KafkaController(上篇)
- kafka源码解析之十二KafkaController(中篇)
- kafka源码解析之十二KafkaController(下篇)
- KAFKA源码阅读——FetchRequestPurgatory, ProducerRequestPurgatory
- kafka源码分析之kafkacluster的管理-KafkaController
- KAFKA源码阅读———处理ProduceRequest,FetchRequest
- KAFKA源码阅读——ReplicaFetcherManager,同步log
- storm-kafka-plus源码阅读
- kafka源码阅读环境搭建
- Kafka源码阅读环境搭建
- kafka源码阅读环境搭建
- Kafka源码深度解析-序列11 -Server核心组件之1-KafkaController选举过程/Failover与Resignation
- 表ADT
- java财务报表
- 2753: [SCOI2012]滑雪与时间胶囊
- call()和apply()的区别
- Could not obtain transaction-synchronized Session for current thread
- Kafka源码阅读 —— KafkaController(3)
- XRecyclerView和万能baseeAdapter 实现上拉下拉刷新列表
- windows下docker安装tensorflow利用Jupyter编程
- 破解实验室刷卡系统
- CentOS 安装高版本git
- Kafka源码阅读 —— KafkaController(4)
- 数据结构(三)——单链表的整表创建与删除
- JS一些代码笔记
- 微信开发学习:点歌台