Kafka控制器选举原理

1. Kafka控制器介绍

  在Kafka集群中会有一个或多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态。当某个分区的leader副本(一个分区会有多个副本,其中只有leader副本对外提供读写服务)出现故障时,由控制器负责为该分区选举新的leader副本。当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。当为某个Topic增加分区数量时,由控制器负责分区的重新分配。
  分区集合介绍:分区中的所有副本统称为AR(Assigned Replicas)。所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR(In-Sync Replicas)。与leader副本同步滞后过多的副本(不包括leader副本)组成OSR(Out-of-Sync Replicas)。
  leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态,当follower副本落后太多或失效时,leader副本会把它从ISR集合中剔除。当OSR集合中有follower副本“追上”了leader副本,那么leader副本会把它从OSR集合转移至ISR集合。默认情况下,当leader副本发生故障时,只有在ISR集合中的副本才有资格被选举为新的leader。

2. Kafka控制器选举原理

  Kafka中的控制器选举工作依赖于Zookeeper,成功竞选成为控制器的broker会在Zookeeper中创建/controller临时(Ephemeral)节点,此临时节点的内容参考如下:

{"version":1,"brokerid":0,"timestamp":"1593330804078"}

  其中version与Kafka版本相关,对同一个Kafka版本来说为固定值。brokerid表示成为控制器的broker的id编号,timestamp表示竞选成为控制器时的时间戳(精确到毫秒)。
  在任意时刻,集群中有且只有一个控制器。每个broker启动的时候会去尝试读取/controller节点的brokerid的值,如果读取到的brokerid的值不为-1,表示已经有其他broker节点成功竞选为控制器,所以当前broker就会放弃竞选;如果Zookeeper中不存在/controller节点,或者这个节点的数据异常,那么就会尝试去创建/controller节点。当前broker去创建节点的时候,也有可能有其他broker同时去尝试创建这个节点,只有创建成功的那个broker才会成为控制器。每个broker都会在内存中保存当前控制器的brokerid值,这个值可以标识为activeControllerId。
  Zookeeper中还有一个与控制器有关的/controller_epoch节点,这个节点是持久(Persistent)节点,节点中存放的是一个整型的controller_epoch值。controller_epoch值用于记录控制器发生变更的次数,即记录当前的控制器是第几代控制器,我们也可以称之为“控制器纪元”。
  controller_epoch的初始值为1,即集群中的第一个控制器的纪元为1,当控制器发生变更时,每选出一个新的控制器就将该字段值加1。每个和控制器交互的请求都会携带controller_epoch这个字段,如果请求的controller_epoch值小于内存中的controller_epoch值,则认为这个请求是向已经过期的控制器发送的请求,那么这个请求会被认定为无效的请求。如果请求的controller_epoch值大于内存中的controller_epoch值,那么说明已经有新的控制器当选了(也就是说接收到这种请求的broker已经不再是控制器了)。由此可见,Kafka通过controller_epoch来保证控制器的唯一性,进而保证相关操作的一致性。
  具备控制器身份的broker需要比其他普通的broker多一份职责,具体细节如下:

  • 监听分区的变化。
  • 监听主题的变化。
  • 监听broker相关的变化。
  • 从Zookeeper中读取获取当前所有与主题、分区及broker有关的信息并进行相应的管理。
  • 启动并管理分区状态机和副本状态机。
  • 更新集群的元数据信息。

  当/controller节点的数据发生变化时,每个broker都会更新自身内存中保存的activeControllerId。如果broker在数据变更前是控制器,在数据变更后自身的brokerid值与新的activeControllerId值不一致,那么就需要“退位”,关闭相应的资源,比如关闭状态机、注销相应的监听器等。有可能控制器由于异常而下线,造成/controller这个临时节点被自动删除;也有可能是其他原因将此节点删除了。
  当/controller节点被删除时,每个broker都会进行选举,如果broker在节点被删除前是控制器,那么在选举前还需要有一个“退位”的动作。如果有特殊需要,则可以手动删除/controller节点来触发新一轮的选举。当然关闭控制器所对应的broker,以及手动向/controller节点写入新的brokerid的所对应的数据,同样可以触发新一轮的选举。

3. 总结

  Kafka控制器选择的流程并不复杂,但是考虑的各种边界条件还是比较周到的,程序的健壮性比较好。有时候我们需要根据业务场景去设计或者调整某种分布式集群,Kafka控制器的选举也可以是一个很好的借鉴,尤其是/controller_epoch的设计,考虑到了控制器可能会因为某种原因过时,保证了控制器的唯一性。

4. 参考文献

《深入理解Kafka:核心设计与实践原理》

posted @ 2020-06-28 16:02  lvnux  阅读(1062)  评论(0编辑  收藏  举报