Controller与broker之间的消息通道
当Controller做出动作时,需要向集群中的broker发送控制消息。发送的消息三种:LeaderAndIsrRequest、UpdateMetadataRequest和StopReplicaRequest, broker收到消息后,通过KafkaApis.handle进行处理————事实上,KafkaApis.handle是broker上的业务线程执行的主要工作,根据不同的消息类型分发给不同的函数处理。
ControllerChannelManager类负责向broker发送消息,其中包含一个map,存放brokerId -> ControllerBrokerStateInfo的映射。
ControllerBrokerStateInfo的定义如下:
case class ControllerBrokerStateInfo(channel: BlockingChannel,
broker: Broker,
messageQueue: BlockingQueue[(RequestOrResponse, (RequestOrResponse) => Unit)],
requestSendThread: RequestSendThread)
其中channel
是连接broker的阻塞通道,broker
参数是broker的IP,端口等信息,messageQueue
是消息队列,存放的是需要发送的request,requestSendThread
是发送线程。其实就是简单地生产者——消费者模式,KafkaController向对应broker的messageQueue中放入消息,requestSendThread负责发送消息,收到相应后通过callback函数——就是messageQueue中的第二个参数进行处理。
ControllerBrokerRequestBatch类中包含三个Map,即leaderAndIsrRequestMap
,stopReplicaRequestMap
和updateMetadataRequestMap
,因为KafkaController一个操作一般会需要向多个broker发送消息,通过新建ControllerBrokerRequestBatch实例,并组装向各个broker的消息,可以简化代码。需要说明的是,在向ControllerBrokerRequestBatch中添加LeaderAndIsrRequest消息时,同时会添加一条给所有broker的UpdateMetadataReuqest消息,因为Metadata存在于所有broker上,其中包含集群中所有TopicAndPartition的信息,在leader变化时需要更新所有broker的metadata。
LeaderAndIsrRequest消息
LeaderAndIsrRequest消息中包含关键信息的两个字段:
//(topic,partitionId) -> partitionStateInfo,即partition和对应的Leader,ISR,AR,leader_epoch信息
partitionStateInfos: Map[(String, Int), PartitionStateInfo],
//本条消息中可能包含多个partition -> partitionStateInfo;leaders变量是这些partition的leader所在broker的集合
leaders: Set[Broker]
收到LeaderAndIsr消息后,由ReplicaManager.becomeLeaderOrFollower进行处理,对于某个partition,如果当前Broker上的副本将成为Leader,则在ReplicaManager.makeLeaders函数中,执行成为Leader的必要操作,包括更新相应Partition实例的ISR, leaderEpoch,leaderReplicaId(当前broker),hw等。对于其他成为Follower的副本,则需要添加到相应Partition的Fecher,用于同步Leader上的log,此外,同样通过makeFollowers函数更新Partition实例ISR(清空),AR,leaderEpoch信息。
makeLeaders和makeFollowers中对topic == "__consumer_offsets"
的情况都作了特殊处理,成为Leader时,需要从log中把属于当前分区的Offset项恢复到OffsetCache中,而成为Follower时,在之前为Leader的情况下,需要把属于当前Partition的Offset项清除。
UpdateMetadataRequest消息
UpdateMetadataRequest消息中包含的重要字段有:
//和LeaderAndIsrRequest中一样,就是partition的状态信息,Leader,ISR,AR,leader_epoch
partitionStateInfos: Map[TopicAndPartition, PartitionStateInfo],
//所有还活着的broker列表
aliveBrokers: Set[Broker]
KafkaApis类中存在一个MetadataCache类的实例,MetadataCache类中有两个重要字段:
//topic->(partitionId, partitionStateInfo),即集群中所有partition的状态信息
val cache: mutable.Map[String, mutable.Map[Int, PartitionStateInfo]],
//brokerId -> Broker,即活着的Broker
var aliveBrokers: Map[Int, Broker]
收到UpdatemetadataRequest消息后,KafkaApis类更新MetadataCache实例中的chace字段和aliveBroker字段,当consumer请求metadata时直接从cache中获取。MetadataCache实例在所有broker上都是一致的,也就是说,无论consumer向哪个broker发起请求,都能获取所有topicAndPartition的metadata信息。
StopReplicaRequest消息
StopReplicaRequest消息中的字段包含:
//是否是删除partition场景
deletePartitions: Boolean,
//须执行stop操作的partitions,同一broker上只有partition的一个replica
partitions: Set[TopicAndPartition]
收到stopReplica的消息后,ReplicaManager会移除replica所在的partition的Fetcher,即不再向该partition的leader拉取新的数据,如果不是删除partition(参数deletePartition=false)场景,这是唯一需要做的一件事。如果是删除partition场景,则还需要去删除partition(参数deletePartition=true)在本地的log。