这是一篇关于 Kafka 集群基本的组织和管理方式的原理总结,我尽量让它不枯燥。
内容提要:
- 背景知识
- 名词介绍
- 集群的基本组织方式
- broker 的启动
- broker 的监听
- controller 的选举和作用
- controller 的选举
- controller 的重新选举
- controller 管理 broker 的离开和加入
- leader 和 follower 的关系
请您用绝对的理智和清醒的头脑去压制住心里的爱和难过,站在未来的高点去否定当下没意义的事。
1. 背景知识
本文需要了解 Zookeeper 的基础知识,可以参考这篇:https://segmentfault.com/a/1190000016349824。
本文涉及到 ZooKeeper的点包括:
- ZooKeeper 一种常用的分布式协调服务,Kafka 用到了它的数据发布和订阅、命名服务、分布式协调/通知、集群管理、Master 选举等功能。
- ZooKeeper 在内存中用一棵树存储数据,树中的每个节点用于存储数据,数据节点分为永久的和临时的两种,只要创建临时节点的客户端下线了临时节点就会被删除,永久节点不会。
- 客户端可以监听指定的数据节点,当特定的事件发生时,ZooKeeper 会通知客户端,比如监听节点的删除、创建或修改。
- ZooKeeper 的中文意思是“动物管理员”,因为很多用到 ZooKeeper 的项目名或者 logo 都是动物,比如 Pig、Hadoop 等。
由于是一遍学习理论一遍验证它,因此最好有可以访问的 Kafka 集群或者单机的 Kafka,单机 Kafka 的安装使用可以参考 [Kafka 101-1] Kafka安装使用。
2. 名词介绍
先罗列一下将会出现的新名词,认个眼熟(有些名词用中文说很奇怪,所以会用英文):
英文 | 中文 | 解释 |
---|---|---|
cluster | 集群 | 所有 Kafka broker 组成的集群 |
controller | 控制者 | Kafka broker 中比较特殊的一个,相当于其他主从结构系统中的 master |
replication | 副本 | 同一分区的数据会在不同的 broker 上存储多份,每一份都称为一个副本 |
leader | 领导者 | 同一分区的副本中 |
follower | 跟随者 | 持有分区副本的 broker,不是领导者的就是跟随者,唯一的任务就是从领导者同步最新的消息,相当于备用领导者 |
3. 集群的基本组织方式
broker 的启动
当每个 broker 启动时,会在 ZooKeeper 中的 /brokers/ids
路径下创建一个节点来注册自己,节点 ID 为配置文件中的 broker.id
参数,不同节点不可以指定相同的 ID,后注册的 broker 会报 NodeExists
的错。
如果不指定
broker.id
或者指定成 -1,节点 ID 会从reserved.broker.max.id
这个参数加 1 的值开始,这个参数默认值是 1000,所以经常可以看见 1001、1002 的 broker ID。
用 ZooKeeper 的命令行工具来查看一下数据节点的情况(不同安装方式 ZooKeeper 的命令会有所不同):
我用 ls /
查看了 ZooKeeper 根路径下的节点,可以看到 brokers
、controller
、consumers
等节点,ZooKeeper 的命令很简单,可以用 help
来查看所有的命令,不过我一般只用 ls
和 get
两个。
来看下 /brokers/ids
路径下的内容:
可以看到下面注册了两个节点,1001 是我额外又启动的一个 broker(修改配置文件,log.dirs
和 listeners
参数改成不一样的即可),我把 broker.id
设置成了-1,注册出来就是 1001。用 get /brokers/ids/0
命令来查看 broker 注册的信息,里面包含了 broker 的 IP 和端口、注册时间、版本以及其它属性,这种树形结构和文件系统结构非常类似。
broker 的监听
每个 broker 除了注册自身之外,还会监听 /brokers/ids
这个节点,当这个节点下增加或删除子几点时,ZooKeeper 会通知监听了的 broker。每个 broker 创建的节点都是临时节点,如果 broker 下线,/brokers/ids
下对应的节点就会被删除。
注意:broker 下线,只会删除
/brokers/ids
下的节点,其它的节点中可能还包含这个 broker 的 ID,比如/brokers/toics
下的节点会记录每个分区的副本存储在哪些 broker 上,这些节点不会删除这个 broker 的 ID,因为这个 broker 还有可能恢复,如果恢复不了,可以用相同的 ID 启动一个新的 broker,新的 broker 会代替原来 broker 的位置,开始同步数据。
4. controller 的作用
controller 除了是一个普通的 broker 之外,还是集群的总扛把子,它负责副本 leader 的选举、topic 的创建和删除、副本的迁移、副本数的增加、broker 上下线的管理等等,这一小节主要关注副本 leader 的选举这一个功能。
controller 的选举
和很多主从架构的分布式系统不同(比如HDFS 的 namenode 和 datanode 是指定的),Controller 的选举靠“命”。
选举过程如下:每个 broker 启动的时候其实都想成为 controller,成为 controller 的方法就是在 ZooKeeper 中创建 /controller
临时节点节点并注册自己的信息,先注册上的 broker 就是 controller,后来的发现已经有这个节点就知道已经有人抢先了,就放弃了,但是它们会监听这个节点的状态,伺机而动。
用 get /controller
命令看下这个节点的内容:
可以看到,ID 为 0 的 broker 目前是 controller。
controller的重新选举
当 controller 下线时,因为无法和 ZooKeeper 保持心跳,/controller
临时节点会被删除,每个 broker 发现这一点之后,就开始新一轮的选举(其实就是抢)。选举出新 controller 的同时,/controller_epoch
中的值也会加 1,这个节点记录 controller 的代数,broker 也会监听这个节点,并且知道当前 controller 的代数,旧的 controller 的指令即使继续发送指定给它们,指令也会被忽略。
重新选举的过程过程也可以手动触发,我们在 ZooKeeper 里用 rmr /controller
命令删掉这个节点,然后再查看这个节点:
果然,controller 换人了。
controller 管理 broker 的离开和加入
当有 broker 下线时,由于这个 broker 可能是多个分区的 leader,所以 controller 需要给这些分区重新选举一个新的 leader,说是选举,其实就是直接指定每个分区副本列表里的下一个 broker,举个例子:
iamabug-5 这个 topic 创建时有三个分区,每个分区有三个副本,分区 0 的 leader 最好是 1004,为什么说是最好呢,因为 leader 需要处理所有客户端的请求,任务比较重,Kafka 有一套负载均衡机制来确定每个分区的 leader 应该在哪台 broker 上,这个 broker 叫做 preferred_leader
,且跟在 1004 后面的 broker ID 是 1002,在没有 broker 下线的时候,看下分区 0 的 leader:
这样的状态是正常的,注意 leader_epoch
值为 6,表示当前 leader 的代数,现在我把 1004 这台 broker 关掉,会发生什么变化:
leader 变成 1002 了,并且 leader_epoch
变成了 7,这个过程中,controller 会向这个分区的所有副本,也就是 1001 和 1002 发送 leader 变更的通知,然后 1002 就成为 leader 并开始处理客户端的生产和消费请求。
假如 1004 这台 broker 又重新上线呢?
可以看到,1004 会重新变成这个分区的 leader,并且 leader_epoch
又加了 1,因为它是 preferred leader,但这个过程并不是立马发生的,broker 有一个参数叫做 leader.imbalance.check.interval.seconds
,默认值为 300,也就是每 5 分钟会检测一次每个分区的 leader 是不是 preferred leader, 如果不是的话,会主动更换 leader。
因为实验了听多次,我偷偷启动了很多次 broker 进程,所以 broker 的 ID 前后有点不一样。
leader 和 follower 的关系
我们已经知道,在每个分区的多个副本中,有一个是 leader,其它是 follower,follower 就干一件事,从 leader 同步数据,然后等着 leader 挂掉,自己有机会成为 leader。
leader干两件事,一是服务用户发来的生产和消费请求,二是监控 follower 同步数据的进度,只有一直和 leader 保持同步的 follower 才有机会成为下一个 leader,那么保持同步的标准是什么呢?标准就是,如果一个 follower 超过 10 秒没有向 leader 请求数据或者请求数据了,但是没有在 10 秒内跟上 leader 的最新消息,那么这个 follower 就是不同步的,当然这里的 10 秒是个可配置的参数,叫做 replica.lag.time.max.ms
。
对于能够和 leader 保持同步的 follower,有个专门的名词就做 ISR,是 in-sync replicas 的缩写,其实在上面的截图里也可以看到每个 partition 也会维护哪些 follower 是在 ISR 里的。
本文内容有点多,时间有点紧,可能错误疏漏较多,欢迎指出,并请见谅!
欢迎交流讨论,吐槽建议,分享收藏。
勤学似春起之苗,不见其增,日有所长
辍学如磨刀之石,不见其损,日有所亏
关注【大数据学徒】,用技术干货助你日有所长