Apache Kafka 移除 ZK Proposals

Zookeeper 和 KRaft
这里有一篇 Kafka 功能改进的 proposal 原文 。要了解移除 ZK 的原因,可以仔细看看该文章 。以下是对该文章的翻译 。
动机
目前,Kafka 使用 Zookeeper 保存与分区(patitions)、brokers 相关的元数据,以及选举 Kafka 控制器(某个 broker) 。我们将移除对 Zookeeper 的依赖 。如此一来,Kafka 在管理元数据方面,将获得更好的可扩展性和鲁棒性,同时支持更多的分区 。在部署、配置 Kafka 方面,也将得到极大的简化 。
将元数据视为 Event Log
我们常说将状态做为事件流管理的好处 。一个在流中描述消费者位置的数字:offset 。消费者通过回放 offset 之后的事件,就能获取最新状态 。日志建立一套清晰、有序的事件机制,并确保每个消费者能获取到自己的时间线 。
虽然我们的用户享受这些便利,但是忽略了 Kafka 本身 。我们将作用到元数据的变更看作彼此孤立,互不相干 。当控制器将状态变更通知到集群中的其他 broker 时,其他 broker 可能会收到一些变更,但不是全部变更 。虽然控制器会重试几次,但最终会停止重试 。这将导致 broker 之间处于不同步的状态 。
更糟糕的是,虽然 Zookeeper 存储 record,但是 Zookeeper 中保存的状态经常与控制器保存在内存中的状态无法匹配 。例如,当分区 leader 在 Zookeeper 中变更其 ISR(in-sync Replica)时,通常情况下,控制器会延误几秒钟才能获知其变更 。对于控制器来说,没有通用的方法追踪 Zookeeper 的 event log 。虽然控制器可以设置一次性守卫,但是守卫的数量由于性能问题会受到限制 。当触发守卫时,守卫不负责通知控制器当前状态,仅仅是通知控制器状态发生了变更 。同时,控制器重读 znode,然后设置一个新的守卫,但是,从最初守卫发出通知,到控制器完成重读,重新设置守卫期间,状态可能已经产生了新的变更 。如果不设置守卫,控制器将永远无法得知变更 。某些情况下,重启控制器是解决状态不一致的唯一手段 。
【Apache Kafka 移除 ZK Proposals】元数据与其存储在独立的系统中,不如存储在 Kafka 中 。这种情况下,控制器状态与 Zookeeper 状态之间和差异相关的问题将不复存在 。与其挨个通知 broker,不如让 broker 们从 event log 中消费元数据事件 。这样就确保了元数据变更能够按相同的顺序同步到 broker 中 。broker 将元数据存储在本地文件中 。当这些 broker 启动时,它们只需要从控制器中(某个 broker)中读取变更,而无需全量读取状态 。在这种情况下,我们消耗更少的 CPU 资源就能获得更多分区 。
简化部署与配置
Zookeeper 是一套独立的系统,有其配置文件语法,管理工具以及部署模式 。这意味着系统管理员为了部署 Kafka,需要学习如何管理和部署两套独立的分布式系统 。这对系统管理员来说,是非常艰巨的任务,尤其是在他们不熟悉部署 JAVA 服务的情况下 。统一系统将极大地改善运行 Kafka 的初次体验,并有助于拓宽其应用范围 。
由于 Kafka 和 Zookeeper 的配置文件是分离的,因此极易产生错误 。例如,管理员在 Kafka 中设置了 SASL(Simple Authentication Security Layer,简单认证安全层),并且错误的认为对所有在网络中传输的数据都做了加密 。事实上,还需要在外部系统 Zookeeper 中配置加密 。统一两个系统将获得完整的加密配置模型 。
最后,未来我们可能需要支持单节点 Kafka 模型 。对于那些要测试 Kafka 功能的人来说,无需启动守护进程,将提供极大的便利性 。移除 Zookeeper 依赖,将使其成为可能 。
架构介绍
本 KIP(Kafka Improvement Proposal,Kafka 改进 Proposal) 展现的是一个可扩展的后 Zookeeper 时代的 Kafka 系统的总体愿景 。为了突出重要部分,我忽略了大多数细节,比如 RPC 格式、磁盘格式等等 。在后续 KIP 中,我们将逐步深入描述细节 。与 KIP-4 类似,提出总体愿景,后续的 KIP 中逐步扩充 。
总览

Apache Kafka 移除 ZK Proposals

文章插图
 
目前,一套 Kafka 集群包括几个 broker 节点,Zookeeper 节点做为一套外部 quorum (投票机制,少数服从多数) 。我们画了 4 个 broker 节点和 3 个 Zookeeper 节点 。这是小集群所需的正常配置 。控制器(用橙色标识)在被选举后,从 Zoopeeper 的 quorum 中加载其状态 。从控制器连接其他节点的线,在 broker 中代表更新控制器推送的消息,比如 LeaderAndIsr、UpdateMetadata 消息 。
注意,这张图有误导的地方 。除控制器以外,其他 broker 也可以与 Zookeeper 通信 。因此,每个 broker 都应该画一条连接 ZK 的线 。无论如何,画太多线将导致该图难以阅读 。该图还忽略了,在不需要控制器介入的情况下,能够修改 Zookeeper 中的状态的外部命令行工具和工具包 。正如上面讨论的那样,这些问题导致了控制器内存中状态无法真正的反映 Zookeeper 中的持久化状态 。


推荐阅读