Apache Kafka 的核心设计是日志(Log)—— 一个简单的数据结构,使用顺序操作。以日志为中心的设计带来了高效的磁盘缓冲和 CPU 缓存使用、预取、零拷贝数据传输和许多其他好处,从而使 Kafka 能够提供高效率和吞吐量的功能。对于那些刚接触 Kafka 的人来说,主题(topic)以及提交日志的底层实现通常是他们学习的第一件事。
但是 log 本身的代码在整个系统中只占相对较小的一部分。Kafka 的代码库中有很大一部分是负责在集群中多个 brokers 之间安排 partitions (即日志)、分配领导权(allocating leadership)、处理故障(handling failures)等。这是使 Kafka 成为一个可靠和可信的分布式系统的代码。
从历史上看,Apache ZooKeeper 是分布式代码工作的关键部分。ZooKeeper 提供了权威的元数据存储,这些元数据存储了系统中最重要的东西:分区存在哪里,哪个副本(replica)是 leader 等等。早期使用 ZooKeeper 是有意义的,它是一个强大且经过验证的工具。但归根结底,ZooKeeper 是一个基于一致日志的特殊文件系统/触发器API。Kafka 是一个建立在一致日志之上的发布/订阅系统。这使得运维人员需要跨两个日志实现、两个网络层和两个安全实现(每个实现都有不同的工具和监视钩子)对通信和性能进行调优、配置、监视、保护和评估,这就使得系统变得很复杂。这种固有的和不可避免的复杂性促使了最近的一个提议,即用一个完全运行在 Kafka 内部的仲裁服务(internal quorum service)来取代 ZooKeeper。
从 Kafka 中移除对 Zookeeper 的依赖早在2019年社区就有人提出来了,这是一项艰巨的工作。去年4月,社区做了一些事以加快这个进度,并在年底前交付一个原型系统。
时间已经过去了近一年。现在,KIP-500 早期代码已经提交到 trunk,预计将包括在即将发布的 Kafka 2.8版本中。在那个版本,我们可以在没有 ZooKeeper 的情况下运行 Kafka。我们称其为 Kafka Raft 元数据模式(Kafka Raft Metadata mode),通常简称为 KRaft(发音类似于 craft)模式。
需要注意的是,有一些特性在这个抢先体验版本中是不可用的。我们还不支持使用 ACL 和其他安全特性或事务。同样,在 KRaft 模式下,分区重分配和 JBOD 都不受支持(预计在今年晚些时候的 Apache Kafka 版本中会提供这些功能)。因此,请考虑使用 Quorum Controller 实验软件——我们不建议将其置于生产工作负载之下。但是,如果你确实尝试过这个软件,你会发现它有很多新的优点:它的部署和操作更简单,你可以把 Kafka 作为一个单独的进程来运行,并且每个集群可以容纳更多分区。
仲裁控制器:事件驱动的共识
如果你选择使用新的仲裁控制器(quorum controller)运行 Kafka,则先前由 Kafka 控制器和 ZooKeeper 承担的所有元数据职责将合并到这一新服务中,并在 Kafka 群集本身中运行。如果有需要的话,仲裁控制器还可以在专用硬件上运行。
但在内部,它变得很有趣。仲裁控制器使用新的 KRaft 协议来确保元数据在仲裁中被精确地复制。这个协议在很多方面与 ZooKeeper 的 ZAB 协议和 Raft 相似,但有一些重要的区别,其中一个显著且非常有用的区别是它使用了事件驱动的架构(event-driven architecture)。
仲裁控制器使用事件源存储模型存储其状态,该模型确保始终可以准确地重新创建内部状态机。用于存储此状态的事件日志(也称为元数据主题)通过快照定期地进行删除(abridged),以确保日志不会无限增长。仲裁中的其他控制器通过响应活动控制器创建并存储在其日志中的事件来跟踪活动控制器。因此,如果一个节点由于网络分区事件而暂停,那么它可以在重新加入时通过访问日志来快速地赶上它错过的任何事件。这大大减少了不可用窗口,从而缩短了系统的最坏情况恢复时间。
KRaft 协议的事件驱动特性意味着,与基于 ZooKeeper 的控制器不同,仲裁控制器在成为活动状态之前不需要从 ZooKeeper 加载状态。当领导权发生变化时,新的活动控制器已经在内存中拥有所有提交的元数据记录。此外,KRaft 协议中使用的事件驱动机制也用于跨集群跟踪元数据。以前使用 RPC 处理的任务现在得益于事件驱动以及使用实际日志进行通信。这些改变带来的一个令人愉快的结果是,Kafka 现在可以比以前支持更多的分区,下面小结将介绍这个。
扩展 Kafka:支持数百万个分区
Kafka 集群可以支持的分区数由两个属性决定:每个节点的分区数限制和集群级别的分区限制。两者都很有趣,但是到目前为止,元数据管理一直是集群级别限制的主要瓶颈。以前的 Kafka 改进建议(KIP)已经改进了每个节点的限制,尽管总有更多的事情可以做。但是 Kafka 的可伸缩性主要依赖于增加节点来获得更多的容量。这就是集群级别限制变得重要的原因,因为它定义了系统内可伸缩性的上限。
新的仲裁控制器旨在处理每个集群中更多的分区。为了对此进行评估,社区进行了专门的测试,这些测试测量关闭和恢复 Controller 所花费的时间。下面是社区在运行200万个分区的集群进行的。
可以看出,基于 ZooKeeper 的 Controller 在关闭和恢复时都花费了很多时间,而基于 Quorum 的 Controller 则表现良好。原因是,基于 ZooKeeper 的 Controller 需要 Kafka 和 ZooKeeper 进行数据同步,这个直接消耗了大量的时间,也正是这个导致了 基于 ZooKeeper 的 Controller 不可能支持太多的分区。而基于 Quorum 的 Controller 数据是由同一个组件提供,所以数据同步时间会小很多。
体验无 ZooKeeper 依赖的 Kafka 集群
新的仲裁控制器在 trunk 中以实验模式提供,预计将包含在即将发布的 Apache Kafka 2.8 版本中。那么我们能用它做什么呢?如上所述,一个简单但非常酷的新特性是创建单个进程 Kafka 集群的能力,如下面的简短演示所示。
当然,如果要扩展以支持更高的吞吐量并添加复制以实现容错功能,则只需添加新的 broker 进程。 最后,需要注意的是,这是基于 KRaft 的仲裁控制器的早期实验版本,请不要将其用于重要的工作负载中。
本文参考自:Apache Kafka Made Simple: A First Glimpse of a Kafka Without ZooKeeper
本博客文章除特别声明,全部都是原创!原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【即将发布的 Apache Kafka 2.8 将不需要依赖 Zookeeper,单集群支持数百万个分区】(https://www.iteblog.com/archives/9946.html)