KafKa Broker

3,156 阅读5分钟

Broker

Broker 注册

Kafka 强依赖于 zookeeper ,每当一个 broker 启动时,它会将自己注册到 zookeeper 的临时节点。

Broker 的注册路径为 chroot/brokers/ids/<broker.id>,如果没有配置 chroot,则路径是 /brokers/ids/<broker.id>。是否配置了 chroot 取决于 server.properties 中的zookeeper.connect 参数是否设置了 chroot

brokerzookeeper 中注册的信息以 json 格式保存。其中包括的信息如下:

{
    "listener_security_protocol_map": {
        "PLAINTEXT": "PLAINTEXT"
    },
    "endpoints": [
        "PLAINTEXT://192.168.110.110:9092"
    ],
    "jmx_port": 9999,
    "host": "192.168.110.110",
    "timestamp": "1575450860777",
    "port": 9092,
    "version": 4
}
  • listener_security_protocol_map:指定该 broker 与外界通信所用的安全协议类型,kafka 支持 broker 使用不同的安全协议与 clients 和其他 broker 通信
  • endpoints:指定 broker 的服务 endpoint 列表,每个 endpoints 指明了传输安全协议类型、broker 主机名和端口信息
  • jmx_portbrokerJMX 监控端口,需要在启动 broker 前设置 jmx_port 环境变量
  • hostbroker 主机名或 IP 地址。
  • timestampbroker 启动的时间。
  • portbroker 服务端口号。
  • versionbroker 注册信息的版本,注意这不是 kafka 的版本

Broker 生命周期管理

Kafka 利用 zookeeper 临时节点来管理 broker 生命周期。

诞生
broker 启动时在 zookeeper 中创建对应的临时节点,同时还会创建一个监听器。

监听变化
broker临时节点上的监听器会实时监听节点的状态,一旦 broker 发生变化,监听器会将状态信息同步到 kafka 集群上

死亡
一旦 broker 崩溃,它与 zookeeper 的会话就会失效,导致该临时节点被删除,监听器被触发,然后处理后续事宜。

Controller Broker

从客户端角度来看, KafKa 一种对等的分布式架构,因为每个 Broker 都包含整个集群的元信息,都可以提供完整的服务,但站在服务端的角度来看,kafka 却是主从架构,至于原因,这就要说到 Controller Broker

什么是 Controller Broker

KafKa Broker 有两种角色, ControllerFollower ,顾名思义 Controller 是主Follower 是从,两种角色做的事情大部分都是一样的,只是 Controller 还需要负责一些管理相关的工作

Controller Broker 的职责

Follower Broker 要做的事情它都要做 ,此外 Controller Broker 还要负责:

Topic 管理

  • 创建、删除 Topic
  • leader Replication 选举。例如某个分区的 leader 副本出现故障时,由 Controller Broker 负责为该分区选举新的 leader 副本
  • 分区重分配。例如当使用 kafka-topic.sh 脚本为某个 topic 增加分区数量时,由 Controller 负责分区的重新分配
  • 同步元数据。例如某个分区的 ISR 集合发生变化时,由 Controller 负责通知所有 broker 更新元数据信息
  • preferred leader 选举。preferred leader选举是为了避免部分 Broker 负载过重而提供的一种换 Leader 的方案。
  • ...

管理 Broker 集群

  • 上线新加入的 Broker
  • 下线故障的 Broker
  • ...

Controller Broker 选举

每个 Broker 启动后都会尝试到 Zookeeper 中创建一个 /controller 的临时节点,谁先创建成功谁就是 Controller,其他的 Broker 都是 Follower

/controller 的临时节点的信息如下

{
    "version": 1,
    "brokerid": 2,
    "timestamp": "1569267532839"
}
  • version : 固定为 1(代码中设置固定值 1)
  • brokerid : 对应该 broker 临时节点的 id
  • timestamp : 注册时间

Controller Brokerzookeeper 失去连接时,临时节点会删除,而其他 broker 会监听该节点的变化,当节点删除时,其他 broker 会收到事件通知,重新发起 controller 选举

主从架构中的脑裂

主从架构中如果主节点挂了,从节点会通过一些方式升级为主节点,但这里的问题是如何分辨主机点是真的挂了,还是暂时失联,如果只是暂时失联而从节点又升级为主节点,待原来的的主节点恢复后,集群中就会有两个主节点,后果就是集群中的其他从节点不知道该听谁的命令,这就是脑裂

Controller 脑裂

首先每个 broker 都会在内存中保存当前 /controller 节点的 brokerid ,这个值被称为 activeControllerId

有新的 broker 当选 Controller 后,会去刷新 /controller 节点,/controller 节点发生变化就会触发监听事件,每个 broker (也包括原来的 Controller broker) 都会更新内存中保存的 activeControllerId

如果原来的 Controller broker 还能监听到事件,就会更新 activeControllerId,并检查 brokerid 值与新的 activeControllerId 值是否一致,如果不一致,就“退位”,关闭相应的资源,比如关闭状态机、注销相应的监听器等。

以上理想情况,旧 Controller broker 还能监听到事件,因此整个交接过程还比较顺利。但大部分情况下都是 Controller broker 长时间失去“响应”,才会发生 Controller,这个种情况下旧 Controller broker 是无法处理监听事件的,如果是真挂掉那还好说,如果是假死,选举完成之后又恢复了,集群中就会有两个 Controller ,这就是 Controller 的脑裂

KafKa 解决脑裂

kafka 除了在 zookeeper 中注册了 /controller 这个临时节点,还注册了 /controller_epoch这个持久节点,该节点中存放的是一个整型的 controller_epoch 值,记录了当前是第几代 Controller ,因此被称为控制器的纪元”,初始值为 1,每次发生 Controller 变更就加1

每个和 Controller 交互的请求都会携带 controller_epoch 这个字段,如果请求的 controller_epoch 值小于内存中的 controller_epoch 值,则认为这个请求是向已经过期的 Controller 所发送请求,那么这个请求会被认为是无效的请求。如果这个请求的 controller_epoch 值大于内存中的 controller_epoch 值,那么说明已经有新的控制器当选了。

kafka 通过 controller_epoch 来保证 Controller 的唯一性,进而保证相关操作的唯一性。