【原创】kafka controller源代码分析(一)
Kafka集群中的一个broker会被作为controller负责管理分区和副本的状态以及执行类似于重分配分区之类的管理任务。如果当前的controller失败了,会从剩下的broker中选出新的controller。
- NonExistentPartition —— 这个状态表示该分区要么没有被创建过或曾经被创建过但后面被删除了
- NewPartition —— 分区创建之后就处于NewPartition状态。在这个状态中,分区应该已经分配了副本,但是还没有选举出leader和ISR
- OnlinePartition —— 一旦分区的leader被推选出来,它就处于OnlinePartition状态
- OfflinePartition —— 如果leader选举出来后,leader broker宕机了,那么该分区就处于OfflinePartition状态。
- 如果是OfflinePartitionLeaderSelector的话,新的leader就是一个可用的副本(该部分最好不在ISR中),而新的ISR就是以前的ISR或者是刚刚选出来的leader,而接收LeaderAndIsr请求的副本集合就是当前可用的副本集合;
- 如果是ReassignedPartitionLeaderSelector的话,新的leader就是一个可用的已分配的副本,新的ISR就是当前的ISR,而接收请求的副本集合就是重分配的副本集合;
- 如果是PreferredReplicaPartitionLeaderSelector的话,新的leader就是第一个分配的副本,新的ISR就是当前的ISR,接收请求的副本就是已分配的副本集合;
- 如果是ControlledShutdownLeaderSelector的话,新的leader就是ISR中没有被关闭的副本,新的ISR就是去除关闭状态副本的ISR,而接收副本就是当前可用的已分配副本
- 获取给定zk路径下所有子节点的集合,并与当前controller中保存的topic集合比较,找出新增topic集合和被删除的topic集合
- 更新controller中保存的当前topic集合
- 从zk的/brokers/topics/[topic]路径下找出那些新增topic对应的分区副本分配记录信息
- 更新controller中保存的topic分区副本分配记录,去掉那些被删除topic的记录,并加入上一步中获取到的那些新增topic的分配记录
- 如果新增了topic,那么调用onNewTopicCreation方法为新增topic注册分区变更监听器并设置分区状态,最后发送元数据更新请求通知各个broker
- 获取待删除topic集合(方法参数传过来的),与controller中保存的topic集合比较,找到那些不存在的topic
- 如果确实存在不存在的topic集合,那么删除zk中/admin/delete_topics下对应的子节点
- 从待删除的topic集合中去掉那些不存在的topic
- 遍历更新后的待删除topic集合,判断每个topic当前是否正处于其他状态变更过程中,比如PreferredLeaderSelector或ReassignedLeaderSelector。如果是的话调用DeleteTopicManager的markTopicIneligibleForDelete方法标记该topic为暂时不能被删除状态
- 将所有带删除的topic都加入到controller的topic删除列表中等待专有线程对其执行删除操作
- 获取zookeeper中新增分区topic对应的分区副本分配记录,与controller中保存的分区副本记录相比较,找出新增的分区记录
- 如果这些新增分区所属的topic当前正在执行删除操作,那么直接记录一个日志错误返回,即跳过增加分区的操作,否则调用controller的onNewPartitionCreation方法来创建这些分区
- 获取目标分区对应的副本分配记录,并从中找出可用的已分配副本。如果当前没有可用的副本那么报错表示该状态转换失败;否则选举出第一个副本broker作为leader,把当前可用的副本集合作为ISR
- 一旦确定了leader和ISR之后,在zookeeper上的/brokers/topics/[topic]/partitions/[partitionId]/state节点下创建出对应的leader和ISR路径
- 更新controller的分区leader缓存信息,并且把LeaderAndIsr请求加入到brokerRequestBatch中
- 如果分区状态机本身没有启动,直接抛出异常退出
- 查看目标分区在状态中的当前状态,如果没有任何记录设置当前状态为NonExistentPartition
- 如果要转换到NewPartition状态,当前必须处于NonExistentPartition状态,然后更新controller中的分区副本分配缓存信息,并将分区状态设置为NewPartition
- 如果要转换到OnlinePartition状态,当前必须处于NewPartition、OnlinePartition或OfflinePartition中的一种。如果当前状态是NewPartition,首先为该分区选举出leader和ISR并写入zookeeper中保存;如果是OnlinePartition或OfflinePartition,则使用electLeaderForPartition方法(后面会说到)重新为分区选举leader,最后设置分区状态为OnlinePartition
- 如果要转换到OfflinePartition状态,当前必须处于NewPartition、OnlinePartition或OfflinePartition中的一种。当分区的leader不存在或不可用时会执行这样的转换。该转换也仅仅是变更分区状态为OfflinePartition
- 如果要转换到NonExistentPartition状态,当前必须处于OfflinePartition,同样地,转换操作也仅仅是设置目标分区状态为NonExistentPartition
- 从zookeeper中获取目标分区的leader和ISR,以及controller_epoch信息
- 如果zk中的controller_epoch比当前controller保存的值大,说明当前controller曾经可能失败过并选举过别的controller且那个controller也干预过目标分区的leader选举。如果是这样的话直接终止正在进行中的leader选举
- 否则,使用指定的leader选举器进行leader选举,获取leader、ISR和AR的信息并写入zookeeper中保存
- 如果zookeeper更新失败(比如无法连接zookeeper等),从步骤1开始重试,直至成功为止
- 更新controller缓存的leader、ISR信息,并将leader、ISR、AR信息加入到元数据请求队列中等待后面发送元数据更新请求
- 如果启动了状态机,首先开启leader选举计时器
- 获取要进行状态变更的副本所在的所有broker Id,与controller中缓存的副本列表比较,找出新增加的broker
- 在Zookeeper中获取这些新增加broker的元数据信息并封装到一个Broker列表中返回
- 找出那些已被删除的broker,然后使用给定的broker列表更新controller中可用broker缓存
- 分别调用addBroker和removeBroker方法更新对应的broker线程
- 最后调用onBrokerStartup和onBrokerFailure回调函数分别处理新增加的broker和删除的broker
- 获取controller中保存的分区副本分配缓存记录
- 找出每个分区的AR信息,遍历AR中的每个broker,如果这个broker可用(是否在controller的可用broker列表缓存中),则将该副本状态置于OnlineReplica,否则将副本状态置于ReplicaDeletionIneligible状态——controller failover时候broker会宕机,处于该broker的所有副本都要置于这个状态
- NonExistentReplica -> NewReplica:将当前leader和ISR封装到一个LeaderAndIsr请求中发送给新的replica broker,并发送UpdateMetadata请求给每个当前可用的broker
- NewReplica -> OnlineReplica:将新增副本加入到AR中
- OnlineReplica, OfflineReplica -> OnlineReplica:将当前leader和ISR封装到一个LeaderAndIsr请求中发送给新的replica broker,并发送UpdateMetadata请求给每个当前可用的broker
- NewReplica, OnlineReplica, OfflineReplica, ReplicaDeletionIneligible -> OfflineReplica:首先发送StopReplicaRequest请求给副本(但不删除副本),然后将该副本从ISR中移除,之后发送LeaderAndIsr请求给leader副本更新ISR并发送UpdateMetadata请求给所有可用的broker
- OfflineReplica -> ReplicaDeletionStarted: 发送StopReplicaRequest请求给副本(同时删除该副本)
- ReplicaDeletionStarted -> ReplicaDeletionSuccessful:在状态机中标记副本状态
- ReplicaDeletionStarted -> ReplicaDeletionIneligble:在状态机中标记副本状态
- ReplicaDeletionSuccessful -> NonExistentReplica:从controller的分区副本分配缓存中移除某个副本
- 如果状态机没有启动,直接抛出异常退出
- 获取controller中保存的给定副本的状态,如果无缓存记录,初始化状态为NonExistentReplica,然后获取controller中缓存的该分区的副本分配记录
- 根据给定的目标状态进入不同的分支:
- 如果要转换为NewReplica:必须验证当前状态是NonExistentReplica,然后从zookeeper中找出该副本分区的leader、ISR等信息。如果不存在这些信息,就等待leader选举之后发请求给该副本;如果存在这些信息,还要判断一些leader是否就是自己,如果是的话抛错因为被选举为leader的副本是不能进行状态转换到NewReplica的。如果以上步骤都没有抛错,就把发送LeaderAndIsr请求给该副本并发送UpdateMetadata请求给所有可用的broker。最后设置副本状态为NewReplica
- 如果要转换为ReplicaDeletionStarted,必须验证当前状态是OfflineReplica,然后更新副本状态并发送停止副本的请求(通过回调函数来完成)
- 如果要转换为ReplicaDeletionIneligible,说明该副本目前不能被删除,首先要验证当前状态必须是ReplicaDeletionStarted,然后更新状态为ReplicaDeletionIneligible即可
- 如果要转换为NonExistentReplica,必须验证当前状态是ReplicaDeletionSuccessful,之后在controller缓存中把副本从所有分区的AR中移除并从状态缓存中移除该副本的记录
- 如果要转换为OnlineReplica,必须验证当前状态是NewReplica、OnlineReplica、OfflineReplica或ReplicaDeletionIneligible中的一种。如果是NewReplica状态,找出当前分区的AR集合,如果该副本不在AR中则把它加入到AR;如果是其他状态的话则需要先检查是否存在leader,如果不存在的话意味着该分区从未处于OnlinePartition状态,也就是说broker从未开启过该分区的消息日志写入,因此在本方法中也就什么都不做。但如果存在leader信息,将发送LeaderAndIsr请求给该副本,并发送UpdateMetadata请求给所有可用的broker,最后设置状态即可
- 如果要转换为OfflineReplica,必须验证当前状态是NewReplica、OnlineReplica、OfflineReplica或ReplicaDeletionIneligible中的一种。首先发送停止副本的请求使得副本不在从leader出获取消息,然后找出分区的leader和ISR。如果不存在则抛出异常,否则将分区副本从ISR中移除并发送LeaderAndIsr请求更新移除后的ISR,最后设置副本状态即可
【原创】kafka controller源代码分析(一)的更多相关文章
- 【原创】kafka controller源代码分析(二)
四.TopicDeletionManager.scala 管理topic删除的状态机,具体逻辑如下: TopicCommand发送topic删除命令,在zk的/admin/delete_topics目 ...
- 【原创】kafka server源代码分析(一)
这个是Kafka server的核心包,里面的类也很多,我们还是一个一个分析 一.BrokerStates.scala 定义了目前一个kafka broker的7中状态 —— 1. NotRunni ...
- 【原创】kafka admin源代码分析
admin包定义了命令行的一些实现 一.AdminOperationException.scala 一个异常类,表示执行admin命令时候抛出的异常 二.AdminUtils.scala admin一 ...
- 【原创】kafka consumer源代码分析
顾名思义,就是kafka的consumer api包. 一.ConsumerConfig.scala Kafka consumer的配置类,除了一些默认值常量及验证参数的方法之外,就是consumer ...
- 【原创】kafka server源代码分析(二)
十四.AbstractFetcherManager.scala 该scala定义了两个case类和一个抽象类.两个case类很简单: 1. BrokerAndFectherId:封装了一个broker ...
- 【原创】kafka producer源代码分析
Kafka 0.8.2引入了一个用Java写的producer.下一个版本还会引入一个对等的Java版本的consumer.新的API旨在取代老的使用Scala编写的客户端API,但为了兼容性 ...
- 【原创】kafka client源代码分析
该包下只有一个文件:ClientUtils.scala.它是一个object,里面封装了各种client(包括producer,consumer或admin)可能会用到的方法: 1. fetchTop ...
- 【原创】k8s源代码分析-----kubelet(1)主要流程
本人空间链接http://user.qzone.qq.com/29185807/blog/1460015727 源代码为k8s v1.1.1稳定版本号 kubelet代码比較复杂.主要是由于其担负的任 ...
- 【原创】k8s源代码分析-----kubelet(8)pod管理
本文QQ空间链接:http://user.qzone.qq.com/29185807/blog/1460540474 本文csdn博客链接:http://blog.csdn.net/screscent ...
随机推荐
- 关于MySQL的在线扩容
原文地址:http://bucketli.iteye.com/blog/1294032 主要简单总结下,mysql在线扩容和缩容一般涉及到的内容,主要包括三个方面,1.在线也就意味着需要把增量的数据重 ...
- Intel VT-x 基本概念
看IaaS 资料时,捎带研究下硬件虚拟化,主要参考<基于intel VT-x 的Xen 全虚拟化实现>,<intel 开发手册 第三卷 19/20章> Intel VT 是in ...
- Aoite 系列(03) - 一起来 Redis 吧!
Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数 ...
- [安卓] 12、开源一个基于SurfaceView的飞行射击类小游戏
前言 这款安卓小游戏是基于SurfaceView的飞行射击类游戏,采用Java来写,没有采用游戏引擎,注释详细,条理比较清晰,适合初学者了解游戏状态转化自动机和一些继承与封装的技巧. 效果展示 ...
- zend studio 常用快捷键
zend studio是一款很棒的PHP语言编译器,强大的功能让很多程序员爱不释手,而快捷键更是程序员加快编写代码的利器,那么一起来看看有哪些好用的快捷键吧. 复制当前行:ctrl+alt+↓ 删除当 ...
- 分享最新的博客到LinkedIn Timeline
使用Octopress作为我的博客框架有两年了.使用起来一直很顺手,这个工具真正的把博客跟写代码等同起来,非常酷炫.再加上各种各样的定制化,简直是随心所欲.我针对自己的需求对Octopress框架进行 ...
- JavaScript 误区
接触JavaScript两年多遇到过各种错误,其中有一些让人防不胜防,原来对JavaScript的误会如此之深,仅以此文总结一下常见的各种想当然的误区 String replace string的re ...
- spring源码分析(一)IoC、DI
创建日期:2016.08.06 修改日期:2016.08.07 - 2016.08.12 交流QQ:992591601 参考书籍:<spring源码深度解析>.<spring技术内幕 ...
- hibernate HQL和Criteria
package com.test; import java.util.Date; import java.util.List; import org.hibernate.Query; import o ...
- 关于python的最大递归层数详解
在阅读http://www.cnblogs.com/skabyy/p/3451780.html这篇文章的时候,实验yield的流式迭代素数的时候发现有个问题,故详细记录下来. 首先来看看python默 ...