Kafka控制器事件处理全流程分析
前言
大家好,我是 yes。
这是Kafka源码分析第四篇文章,今天来说说 Kafka控制器,即 Kafka Controller。
源码类的文章在手机上看其实效果很差,这篇文章我分为两部分,第一部分就是直接图文来说清整个 Kafka 控制器事件处理全流程,然后再通过Controller选举流程进行一波源码分析,再来走一遍处理全流程。
一些在手机上看的同学可以直接看前半部分,没有一堆代码比较舒适,也能看明白整个流程,后面源码部分看个人了。
不过建议电脑端看效果更佳。
正文
在深入源码之前我们得先搞明白 Controller是什么?它有什么用?这样在看源码的时候才能有的放矢。
Controller是核心组件,它的作用是管理和协调整个Kafka集群。
具体管理和协调什么呢?
- 主题的管理,创建和删除主题;
- 分区管理,增加或重分配分区;
- 分区
Leader选举; - 监听
Broker相关变化,即Broker新增、关闭等; - 元数据管理,向其他
Broker提供元数据服务;
为什么需要Controller?
我个人理解:凡是管理或者协调某样东西,都需要有个Leader,由他来把控全局,管理内部,对接外部,咱们就跟着Leader干就完事了。这其实对外也是好的,外部不需要和我们整体沟通,他只要和一个决策者交流,效率更高。
再来看看朱大是怎么说的,以下内容来自《深入理解Kafka:核心设计与实践原理》。
在Kafka的早期版本中,并没有采用 Kafka Controller 这样一概念来对分区和副本的状态进行管理,而是依赖于 ZooKeeper,每个 broker都会在 ZooKeeper 上为分区和副本注册大量的监听器(Watcher)。
当分区或副本状态变化时,会唤醒很多不必要的监听器,这种严重依赖 ZooKeeper 的设计会有脑裂、羊群效应,以及造成 ZooKeeper 过载的隐患。在目前的新版本的设计中,只有 Kafka Controller 在 ZooKeeper 上注册相应的监听器,其他的 broker 极少需要再监听 ZooKeeper 中的数据变化,这样省去了很多不必要的麻烦。
简单说下ZooKeeper
了解了 Controller的作用之后我们还需要在简单的了解下ZooKeeper,因为Controller是极度依赖ZooKeeper的。(不过社区准备移除ZooKeeper,文末再提一下)
ZooKeeper是一个开源的分布式协调服务框架,最常用来作为注册中心等。ZooKeeper的数据模型就像文件系统一样,以根目录 "/" 开始,结构上的每个节点称为znode,可以存储一些信息。节点分为持久节点和临时节点,临时节点会随着会话结束而自动被删除。
并且有Watcher功能,节点自身数据变更、节点新增、节点删除、子节点数量变更都可以通过变更监听器通知客户端。

Controller是如何依赖ZooKeeper的
每个Broker在启动时会尝试向ZooKeeper注册/controller节点来竞选控制器,第一个创建/controller节点的Broker会被指定为控制器。这就是是控制器的选举。
/controller节点是个临时节点,其他Broker会监听着此节点,当/controller节点所在的Broker宕机之后,会话就结束了,此节点就被移除。其他Broker伺机而动,都来争当控制器,还是第一个创建/controller节点的Broker被指定为控制器。这就是控制器故障转移,即Failover。
当然还包括各种节点的监听,例如主题的增减等,都通过Watcher功能,来实现相关的监听,进行对应的处理。
Controller在初始化的时候会从ZooKeeper拉取集群元数据信息,保存在自己的缓存中,然后通过向集群其他Broker发送请求的方式将数据同步给对方。
Controller 底层事件模型
不管是监听Watcher的ZooKeeperWatcher线程,还是定时任务线程亦或是其他线程都需要访问或更新Controller从集群拉取的元数据。多线程 + 数据竞争 = 线程不安全。因此需要加锁来保证线程安全。
一开始Kafka就是用大量的锁来保证线程间的同步,各种加锁使得性能下降,并且多线程加锁的方式使得代码复杂度急剧上升,一不小心就会出各种问题,bug难修复。
因此在0.11版本之后将多线程并发访问改成了单线程事件队列模式。将涉及到共享数据竞争相关方面的访问抽象成事件,将事件塞入阻塞队列中,然后单线程处理。
也就是说其它线程还是在的,只是把涉及共享数据的操作封装成事件由专属线程处理。

先小结一下
到这我们已经清楚了Controller主要用来管理和协调集群,具体是通过ZooKeeper临时节点和Watcher机制来监控集群的变化(当然还有来自定时任务或其他线程的事件驱动),更新集群的元数据,并且通知集群中的其他Broker进行相关的操作(这部分下文会讲)。
而由于集群元数据会有并发修改问题,因此将操作抽象成事件,由阻塞队列和单线程处理来替换之前的多线程处理,降低代码的复杂度,提升代码的可维护性和性能。
接下来我们再讲讲Controller通知集群中的其他Broker的相关操作。
Controller的请求发送
Controller从ZooKeeper那儿得到变更通知之后,需要告知集群中的Broker(包括它自身)做相应的处理。
Controller只会给集群的Broker发送三种请求:分别是 LeaderAndIsrRequest、StopReplicaRequest和 UpdateMetadataRequest
LeaderAndIsrRequest
告知Broker主题相关分区 Leader和ISR副本都在哪些 Broker上。
StopReplicaRequest
告知Broker停止相关副本操作,用于删除主题场景或分区副本迁移场景。
UpdateMetadataRequest
更新Broker上的元数据。
Controller事件处理线程会把事件封装成对应的请求,然后将请求写入对应的Broker的请求阻塞队列,然后RequestSendThread 不断从阻塞队列中获取待发送的请求。

先解释下controllerBrokerStateInfo,它就是个 POJO类,可以理解为集群每个broker对应一个controllerBrokerStateInfo.

然后再看下ControllerChannelManager,从名字可以看出它管理Controller和集群Broker之间的连接,并为每个Broker创建一个RequestSendThread 线程。

再小结一下
接着上个小结,事件处理线程将事件队列里面的事件处理之后再进行对应的请求封装,塞入需要通知的集群Broker对应的阻塞队列中,然后由每个Broker专属的requestSendThread发送请求至对应的Broker。
总的步骤如下图:

现在应该已经清楚Controller大概是如何运作的,整体看起来还是生产者-消费者模型。
接下来就进入源码环节。
Controller选举流程源码分析
事件处理的流程都是一样的,只是具体处理的事件逻辑不同,我们从Controller选举入手,来走一遍处理流程。
ControllerChangeHandler
选举会触发此handler,可以看到直接往ControllerEventManager的事件队列里塞。

这个QueueEvent和ControllerEventManager,我们先来看看是啥。不过在此之前先了解下ControllerEvent和ControllerEventProcessor 。
ControllerEvent:事件

ControllerEventProcessor : 事件处理接口
此接口的唯一实现类是 KafkaController 。

ControllerEventManager:事件处理器
此类主要用来管理事件处理线程和事件队列。

QueuedEvent:封装了ControllerEvent的类
主要是记录了下入队时间,并且提供了事件需要调用的方法。

ControllerEventThread:事件处理线程
整体而言还是很简单的,从队列拿事件,然后处理。

KafkaController#process
就是个switch,根据事件调用对应的processXXXX方法。

来关注下controller 重选事件

然后在onControllerFailover里面会调用sendUpdateMetadataRequest方法

中间省略调用,内容太多了,不是重点,到后来调用ControllerBrokerRequestBatch#sendRequest

最后还是调用了controllerChannelManager#sendRequest.

然后 RequestSendThread#doWork,不断从请求队列里拿请求,发送请求。

一个环节完成了!我们来看下整体流程图

最后我们来看下元数据到底有啥和KafkaController的一些字段。
ControllerContext:元数据
主要有运行中的Broker、所有主题信息、主题分区副本信息等。

KafkaController
基本上关键的字段都解释了,关于状态机那一块篇幅有限,之后再说。

最后
整体的流程就是将Controller相关操作都封装成一个个事件,然后将事件入队,由一个事件处理线程来处理,保证数据的安全(从这也可以看出,不是多线程就是好,有利有弊最终还是看场景)。
最后在通知集群中Broker的过程是每个Broker配备一个发送线程,因为发送是同步的,因此每个Broker线程隔离可以防止某个Broker阻塞而导致整体都阻塞的情况。
前面有说到Kafka Controller 强依赖 ZooKeeper。但是现在社区打算移除 ZooKeeper,因为ZooKeeper不适合频繁写,并且是CP的。而且用Kafka 还需要维护ZooKeeper集群,提升了系统的复杂度和运维难度,降低了系统的稳定性。
像位移信息,已经通过内部主题的方式保存,绕开了ZooKeeper。
社区打算通过类 Raft 共识算法来选举Controller,并且把元数据存储在 Log 中的方式来做。
我是 yes,从一点点到亿点点,我们下篇见。
往期推荐:
消息队列面试连环问:如何保证消息不丢失?处理重复消息?消息有序性?消息堆积处理?

Kafka控制器事件处理全流程分析的更多相关文章
- springboot 事务执行全流程分析
springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...
- Kafka处理请求的全流程分析
大家好,我是 yes. 这是我的第三篇Kafka源码分析文章,前两篇讲了日志段的读写和二分算法在kafka索引上的应用 今天来讲讲 Kafka Broker端处理请求的全流程,剖析下底层的网络通信是如 ...
- 监控视频采集与Web直播开发全流程分析
内容概要: 摄像头 => FFmpeg => Nginx服务器 => 浏览器 从摄像头拉取rtsp流 转码成rtmp流向推流服务器写入 利用html5播放 1.开发流程 1.1 通过 ...
- Kafka控制器选举流程剖析
1.概述 平时在使用Kafka的时候,可能关注的更多的是Kafka系统层面的.今天来给大家剖析一下Kafka的控制器,了解一下Kafka控制器的选举流程. 2.内容 Kafka控制器,其实就是一个Ka ...
- 全球首个全流程跨平台界面开发套件,PowerUI分析
一. 首个全流程跨平台界面开发套件,PowerUI正式发布 UIPower在DirectUI的基础上,自主研发全球首个全流程跨平台界面开发套件PowerUI(PUI)正式发布,PowerU ...
- Kafka工作流程分析
Kafka工作流程分析 生产过程分析 写入方式 producer采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(patition)中,属于顺序写磁盘(顺序写磁盘 ...
- Kafka之工作流程分析
Kafka之工作流程分析 kafka核心组成 一.Kafka生产过程分析 1.1 写入方式 producer采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(pa ...
- MindStudio模型训练场景精度比对全流程和结果分析
摘要:MindStudio是一套基于华为昇腾AI处理器开发的AI全栈开发平台 本文分享自华为云社区<MindStudio模型训练场景精度比对全流程和结果分析>,作者:yd_24730208 ...
- 【Heritrix基础教程之4】开始一个爬虫抓取的全流程代码分析
在创建一个job后,就要开始job的运行,运行的全流程如下: 1.在界面上启动job 2.index.jsp 查看上述页面对应的源代码 <a href='"+request.getCo ...
随机推荐
- Java中抽象类和接口的介绍及二者间的区别
接口(Interface)和抽象类(Abstract Class)是支持抽象类定义的两种机制. 一.抽象类 在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称 ...
- 力扣Leetcode 面试题51. 数组中的逆序对 - 归并排序
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出: 5 限制: 0 <= ...
- laravel+vue+vuetify 前端匹配不到数据记录 No matching records found
后端数据:使用guzzle获取api数据,(安装扩展包guzzle) use GuzzleHttp\Client; //获取请求远程产品信息需要的参数public function getParams ...
- 集成react-native-image-picker时,报错Couldn't get file path for photo
1. 版本环境: "react": "16.13.1", "react-native": "0.63.2", " ...
- [易霖博YCTF]Web WriteUp
中午队里师傅发到群里的比赛,借来队里师傅账号和队里其他师傅一起做了一下,ak了web,师傅们tql.学到挺多东西,总结一下. rce_nopar 进入题目给出源码: <?php if(isset ...
- 剑指 Offer 19. 正则表达式匹配
题目描述 请实现一个函数用来匹配包含'. '和'*'的正则表达式.模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次).在本题中,匹配是指字符串的所有字符匹配整个模式. ...
- 如何让SpringBoot工程在log/控制台中实时打印MyBatis执行的SQL语句
工程下载:https://files.cnblogs.com/files/xiandedanteng/gatling20200429-4.zip 其实就是一句话设置的事情,实现步骤: 在applica ...
- 20190923-09Linux磁盘分区类 000 017
df 查看磁盘空间使用情况 df: disk free 空余硬盘 1.基本语法 df 选项 (功能描述:列出文件系统的整体磁盘使用量,检查文件系统的磁盘空间占用情况) 2.选项说明 表1-32 选项 ...
- 阿里云前端路线 | CSS快速掌握
1.1什么是CSS 翻译为“层叠样式表”或者“级联样式表”, 简称样式表. 1.2CSS的主要作用 它主要是用来给HTML网页来设置外观或者样式 外观或者样式:HTML网页中的文字的大小.颜色.字体, ...
- node-vuecli 脚手架安装
1. vuecli 简介 Vue CLI 致力于将 Vue 生态中的工具基础标准化 Vue CLI 是一个基于 vue.js 进行快速开发的完整系统,是一个全局安装的 npm包,基于webpack构建 ...