继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Kafka为什么放弃了ZooKeeper

PIPIONE
关注TA
已关注
手记 1117
粉丝 149
获赞 703

多年来,阿帕奇·卡夫卡 依赖于 阿帕奇·祖克 来管理元数据、集群配置信息并在跨集群之间保持分布式状态。ZooKeeper 在处理诸如控制器选择和跟踪代理的状态等关键方面起到了重要作用。然而,Kafka 最近脱离了 ZooKeeper,转而使用新的内部 KRaft(Kafka Raft) 共识协议,标志着 Kafka 架构的一个重要进步。让我们探讨一下这次转变背后的动机,它带来的好处,以及 KRaft 如何从根本上改变了 Kafka 的架构。

让我们快速了解一下Zookeeper(ZK)在这整个过程中扮演了什么角色。

  1. 元数据管理:ZK 存储和管理了 Kafka 的元数据,包括主题设置、分区领导者详情和代理注册信息。
  2. 控制器选举:在 Kafka 中,控制器是一个被选举出来的代理,负责处理诸如分配分区和领导者选举等管理任务。ZK 负责决定谁来当这个控制器。
  3. 容错性:ZK 帮助 Kafka 检测服务器故障,使得处理集群内的变更变得更加容易。
  4. 可扩展性:ZK 让 Kafka 能够在某种程度上横向扩展,通过独立维护集群状态来实现。

尽管ZK为Kafka提供了许多必要的服务,但随着Kafka的使用越来越广泛以及集群规模的显著增加,一些限制和挑战也随之显现。

关于Zookeeper的挑战:

  1. 操作复杂性 :管理ZK集群和Kafka增加了操作复杂性。用户需要监控并维护两个独立的分布式系统,这增加了管理负担,并需要额外的专业知识。没有简单的方法让控制器读取ZK事件日志,因此ZK中的任何状态变更通常需要相当长的时间才能传播,甚至更糟,控制器可能永远不会得知。唯一的但不是理想的解决方案是重启控制器。
  2. 可扩展性瓶颈 :Kafka中的某些操作,如分区重新分配,会产生高负载,导致大型集群中的性能下降。
  3. 延迟和性能问题 :Kafka中的延迟敏感应用程序需要更快的元数据更新。然而,Kafka和ZK之间的通信不够顺畅,导致某些情况下更新丢失。
  4. 复杂的故障场景 :在分布式设置中,故障可能发生在多个点。如果ZK出现问题,整个Kafka集群都会受到影响,导致潜在的停机时间或数据不一致性。
  5. 复杂的部署模型 :Kafka和ZK遵循不同的部署模型、设置和工具,这增加了第一天部署和支持的额外负担。Kafka团队的想法是减少第一天的摩擦,创建一个简单且无过多负担的架构,以方便采用。

卡夫卡的新架构概述:

KRaft 架构引入了一个单一集成系统,其中 Kafka代理同时处理数据存储和元数据管理,完全取代了 ZK。它参考了 Raft 共识协议的论文(我已经写了一篇详细的文章介绍它 -> 这里)。以下是它的运作方式:

  1. 元数据分区:在KRaft模式下,Kafka使用一组内部元数据分区来存储元数据,而不是使用Zookeeper节点。这些元数据分区在代理之间进行复制,确保了持久性和高可用性。
  2. 控制器节点:KRaft使用Raft共识协议来选举一个控制器。这个控制器管理分区分配和领导者选举等管理任务,这些任务以前由Zookeeper处理。控制器的更新会快速复制到备用控制器中,以减少停机时间。
  3. 自管理的元数据日志:现在,Kafka将元数据更新存储在一个单独的内部日志中,该日志会在代理间复制,从而保证元数据更新的一致性和可靠性。代理通过拉取控制器的元数据日志中的更新来实现元数据访问的分布式和高效。MetadataFetchAPI请求被设计成增量更新以减少总体延迟;代理启动后,它会读取其磁盘存储中的本地元数据信息;根据代理提供的本地偏移量,控制器判断增量更新是否足够或是否需要完整的元数据更新。代理发出的MetadataFetchAPI请求也用于确认代理是否可以继续接受新的请求。

让我们稍微解释一下KRaft吧:KRaft——

目标是建立一个基于由自我管理的多数派维护的复制元数据日志的Kafka架构。日志复制是Kafka的关键组成部分,也是共识协议(如Raft)的核心。这就是为什么KRaft应运而生。它深受Kafka日志复制协议(不同于Raft建议的推送机制,它采用了拉取机制)的影响,但遵循Raft共识协议的基本原则。可以将其视为从Kafka的日志复制开始,并加入了Raft的领导选举机制。

几个关键概念:

如果你熟悉Kafka复制,,大多数相同的概念同样适用于Raft复制,只需将ISR提交语义替换为多数投票提交语义,并添加选举领导者。

Leader 任期:在 Raft 中,这被称为一个“任期”,它是一个单调递增的序列,在每次选举新的领导者时都会增加。它既用来防止僵尸节点,也用来解决日志分歧。日志记录通过在日志中的位置和追加该记录的领导者任期来唯一标识。

选票人: 选票人是一个副本(复制品),有资格参与投票,在选举中并可能成为领导者。选票人也会从现任领导者那里获取记录并复制它们。

高水位:虽然在基于法定人数的复制协议中没有ISR这个概念,我们仍然有一个高水位来控制记录何时被视为“已提交”。这是复制到大多数投票者处的最大偏移量。该协议旨在确保已提交的记录不会丢失。

候选者: 当一个选民决定选举一位新领导时,它会通过提升领导的纪元并投自己一票来启动选举。我们称这些为候选人

领导者:当一个候选者从它的同伴(包括自己)那里获得最多票数时,它将成为当前纪元的领导者。每个纪元中只有一个领导者,它会处理客户端关于新记录的请求。这个单一的领导者和其他所有投票者共同组成一个法定投票团体。

追随者:已经给某个当前候选人投过票或者从当前领导者那里获取信息的投票者被称为追随者。如果在可配置的超时时间内,追随者没有收到当前领导者的消息,或者当前正在进行的选举没有得出结果,他们就有可能成为候选人。

观察者: 观察者是一个节点,不能投票也不能成为领导者。然而,与其它投票者一样,它仍然可以从领导者那里获取并复制记录。换句话说,观察者仅负责找到领导者并复制日志记录。

主要功能:,

  • 发起投票:由选民发起以开始一次选举。选民可以通过投票API发起选举。选民会在以下三种情况下发起新的选举:

1. 如果在 quorum.fetch.timeout.ms 超时前,仍未能从当前领导者那里接收到 FetchResponse

2. 如果从当前领导者那里接收到 EndQuorumEpoch 请求

3. 如果在宣布自己为候选人后,未能在 quorum.election.timeout.ms 时间截止前获得多数票
  • BeginQuorumEpoch :用于新领导者通知选民其任期。在传统的 Raft 中,领导者会向选举中的其他节点发送一个空的追加日志请求以声明其任期。在 KRaft 的拉取协议中,我们需要一个单独的 BeginQuorumEpoch API 来完成相同的操作,并确保选举结果能够迅速被发现。在该协议中,一旦领导者获得足够的选票,它将向选举中的所有选民发送 BeginQuorumEpoch 请求。
  • EndQuorumEpochEndQuorumEpoch API 允许领导者优雅地退下来,以便选举可以立即开始,而无需等待选举超时。主要的使用场景是支持优雅关闭。
  • Fetch :选民和观察节点向当前领导者发送 Fetch 请求以复制日志更改。对于选民来说,这也是一种验证领导者是否在线的方法。

最后想说的,

从 ZK 转换到 KRaft 体现了 Kafka 在提升性能、可靠性与简洁性方面的承诺。虽然 ZK 在许多年内一直很好地服务于 Kafka,但随着 Kafka 集群的增长和使用需求的增加,其局限性变得越来越突出。借助 KRaft,Kafka 对其架构进行了重新定义,打造了一个更加强大、灵活且易于操作的系统。这一转型标志着 Kafka 发展史上的一个激动人心的新阶段。

参考下(待补充)

https://cwiki.apache.org/confluence/display/KAFKA/KIP-500:用自管理的元数据仲裁组替换ZooKeeper

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP