【原创】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 ...
随机推荐
- 【腾讯Bugly干货分享】浅谈Android自定义锁屏页的发车姿势
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57875330c9da73584b025873 一.为什么需要自定义锁屏页 锁屏 ...
- 【WEB】初探Spring MVC框架
Spring MVC框架算是当下比较流行的Java开源框架.但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了.“心塞”的同时,只好默默 ...
- C语言#自动生成四则运算的编程
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> ...
- Repeater绑定数组并显示其值
web开发中,尤其是对于数据展示,不得不说Repeater是一个万能的控件,而且使用也很方便. 在ASP.NET中将数组绑定到Repeater中请问如何在Repeater前台页面中显示该数组的值? s ...
- IoC组件Unity再续~根据类型字符串动态生产对象
回到目录 这个根据类型字符串动态去生产一个接口的对象,在实现项目中用途很广,这即省去了配置config文件的麻烦,又使用生产对象变更可配置,你完全可以把这种多态持久化到数据库里或者XML文件里,在使用 ...
- 锋利的JQuery —— 事件和动画
大图猛戳
- 简单的JPA注解例子
package ssh.entity; import java.math.BigDecimal; import java.util.Date; import javax.persistence.*; ...
- Jquery 选择器 详解
在线文档地址:http://tool.oschina.net/apidocs/apidoc?api=jquery 各种在线工具地址:http://www.ostools.net/ 一.基本选择器 $( ...
- 理论经典:TCP协议的3次握手与4次挥手过程详解
1.前言 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提供一种面向连接的.可靠的字节流服务. 面向连接意味着两个使用TCP的应用(通常是一个客户和一 ...
- DELPHI支付宝支付代码
真实业务场景的考虑 按照支付宝或者微信支付的开发手册的说法,一个标准的客户端接入支付业务模型应该是这样的,我忽略时序图,只用文字描述: 用户登录客户端,选择商品,然后点击客户端支付. 客户端收集商品信 ...