【原创】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 ...
随机推荐
- Android移动APP开发笔记——Cordova(PhoneGap)通过CordovaPlugin插件调用 Activity 实例
引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式来开发移动手机APP,因此当页面需要获取手机内部某些信息时(例如:联系人信息,坐标定位,短信等),程序就需要调用 ...
- Stealth视频教程学习笔记(第一章)
Stealth视频教程学习笔记(第一章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
- 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求
系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求 实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目 实战使 ...
- Nginx做前端Proxy时TIME_WAIT过多的问题
我们的DSP系统目前基本非凌晨时段的QPS都在10W以上,我们使用Golang来处理这些HTTP请求,Web服务器的前端用Nginx来做负载均衡,通过Nginx的proxy_pass来与Golang交 ...
- Oracle数据库面试题【转载】
1. Oracle跟SQL Server 2005的区别? 宏观上: 1). 最大的区别在于平台,oracle可以运行在不同的平台上,sql server只能运行在windows平台上,由于windo ...
- Atitit 发帖机系列(6) USRQBN2201 setup spec安装程序的实现规范与标准化解决方案
Atitit 发帖机系列(6) USRQBN2201 setup spec安装程序的实现规范与标准化解决方案 安装主要解决一个问题,就是resin的内容启动路径以及端口..这里是使用的端口8077 主 ...
- html学习记录之表格、表单基础
①编码:charset="utf-8": ②描述及关键词:name="description":name="keywords": ③a标签 ...
- Python之文件读写
本节内容: I/O操作概述 文件读写实现原理与操作步骤 文件打开模式 Python文件操作步骤示例 Python文件读取相关方法 文件读写与字符编码 一.I/O操作概述 I/O在计算机中是指Input ...
- 史上最全github使用方法:github入门到精通
[初识Github]首先让我们大家一起喊一句“Hello Github”.YEAH!就是这样. 原文 http://www.eoeandroid.com/thread-274556-1-1.htmlG ...
- WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Che ...