作者丨Prince Mahajan
编译丨诺亚
出品 | 51CTO技术栈(微信号:blog51cto)
如何通过云原生设计提升Apache Kafka引擎的性能、可用性和成本效率?本文作者围绕这一中心议题,介绍了一项名为Kora的事件流处理平台的重新设计过程及关键技术创新。文章首先指出成功云原生平台的必备特性,包括多租户支持、易于扩展、数据驱动管理、跨客户安全隔离以及支持快速创新。Kora的设计旨在满足这些需求,同时保持与现有Kafka协议的兼容性,并在多云环境下提供一致体验。
当我们着手重建托管Apache Kafka服务核心的引擎时,我们知道必须满足成功云原生平台的几个独特要求。这些系统需要从底层开始就是多租户的,能够轻松扩展以服务于成千上万的客户,并且主要由数据驱动的软件而非人工操作员来管理。它们还应确保在工程师可以持续快速创新的环境中,跨客户具有强大的隔离性和安全性,即使工作负载不可预测。
去年,我们展示了Kafka引擎的重新设计。我们设计和实施的大部分内容也将适用于其他构建大规模分布式云系统的团队,如数据库或存储系统。我们希望与更广泛的社区分享我们的经验,希望这些经验能对从事其他项目的人有所帮助。
我们的高层级目标可能与你自己基于云的系统的目标相似:提高性能和弹性,增加对我们自己和客户的成本效率,并在多个公有云上提供一致的体验。我们还有一个额外的要求,即与当前版本的Kafka协议保持100%兼容。
我们重新设计的Kafka引擎名为Kora,是一个事件流处理平台,在AWS、Google Cloud和Azure的70多个区域运行着数万个集群。你可能不会立即达到这样的规模,但下面描述的许多技术仍然适用。
以下是我们在新的Kora设计中实施的五个关键创新。如果你想深入了解其中任何一个,我们在这个主题上发表了一篇白皮书,该白皮书在2023年的国际超大数据库会议(VLDB)上获得了最佳行业论文奖。
要构建高可用性和水平可扩展的系统,你需要一个使用可扩展和可组合构建块构建的架构。具体来说,一个可扩展系统所做的工作应随着系统规模的增加而线性增长。原始的Kafka架构没有满足这个标准,因为许多负载方面的增长与系统规模的增加是非线性的。
例如,随着集群规模的增加,连接数呈二次方增长,因为所有客户端通常都需要与所有代理通信。类似地,由于每个代理通常在所有其他代理上都有跟随者,复制开销也呈二次方增长。最终结果是,添加代理会导致开销的不成比例增加,相对于它们带来的额外计算/存储能力。
第二个挑战是确保租户之间的隔离。特别是,一个表现不佳的租户可能会对集群中每个其他租户的性能和可用性产生负面影响。即使有有效的限制和节流,可能总会有一些负载模式是有问题的。即使客户端表现良好,节点的存储也可能会被降级。在集群中的随机分布,这将影响所有租户和潜在的所有应用程序。
我们使用一种称为单元的逻辑构建块解决了这些挑战。我们将集群划分为一组跨越可用性区域的单元。租户被隔离到单个单元中,这意味着该租户拥有的每个分区的副本都被分配到该单元中的代理上。这也意味着复制被限制在该单元内的代理之间。向单元中添加代理在单元级别上带来了与以前相同的问题,但现在我们有了一个选项,即在不增加开销的情况下在集群中创建新的单元。此外,这为我们提供了一种处理嘈杂租户的方法。我们可以将租户的分区移动到隔离单元中。
为了衡量这个解决方案的有效性,我们设置了一个包含24个代理和六个代理单元的实验性集群(有关完整配置的详细信息,请参见我们的白皮书)。当我们运行基准测试时,集群负载——我们为衡量Kafka集群负载而设计的一个自定义指标——在使用单元时为53%,而不使用单元时为73%。
通过将架构分层以优化不同存储类型的使用,我们在提高性能和可靠性的同时降低了成本。这源于我们分离计算和存储的方式,主要是两方面:使用对象存储保存冷数据,以及使用块存储代替实例存储保存更频繁访问的数据。
这种分层架构使我们能够增强弹性——当只需要重新分配热数据时,分区的重新分配变得容易得多。使用EBS卷而不是实例存储也提高了持久性,因为存储卷的生命周期与相关虚拟机的生命周期解耦。
最重要的是,分层允许我们显著改善成本和性能。成本降低是因为对象存储是存储冷数据更经济实惠和可靠的选择。而性能提高是因为一旦数据被分层,我们可以将热数据置于高性能存储卷中,如果没有分层,这将是成本高昂的。
对于计划在多个云上运营的任何服务来说,提供统一且一致的跨云客户体验至关重要,但这在几个方面都是具有挑战性的。云服务复杂,即使它们遵循标准,不同云和实例之间仍存在差异。实例类型、实例可用性和甚至对于类似云服务的计费模式都可能以微妙但重要的方式有所不同。例如,Azure块存储不允许独立配置磁盘吞吐量/IOPS,因此需要配置大容量磁盘来扩展IOPS。相比之下,AWS和GCP允许你独立调整这些变量。
许多SaaS提供商回避这种复杂性,让客户自己担心实现一致性能所需的配置细节。显然,这并不理想,因此在Kora中,我们开发了抽象化的方法来消除这些差异。
我们引入了三种抽象,使客户能够远离实现细节,专注于更高层次的应用程序属性。这些抽象可以帮助大幅简化服务并限制客户需要自行回答的问题。
故障处理对于可靠性至关重要。即便是在云端,由于云提供商中断、软件错误、磁盘损坏、配置错误或其他原因,故障也是不可避免的。这些可能是完全或部分故障,但无论哪种情况,都必须迅速解决,以免影响性能或系统访问。
不幸的是,如果你正在大规模运营云平台,手动检测和处理这些故障是不可能的。它会占用过多的操作员时间,并且意味着可能无法快速解决问题以维持服务水平协议。
为了解决这个问题,我们构建了一个解决方案来处理所有此类基础设施退化的案例。具体来说,我们构建了一个反馈循环,包括一个退化检测组件,该组件从集群收集指标并使用它们来决定是否有任何组件发生故障以及是否需要采取行动。这使我们能够在不需任何手动操作员介入的情况下,每周自动处理数百次退化。
实现多种反馈循环跟踪代理性能并在必要时采取行动。当发现问题时,会标记为特定的代理健康状态,并针对每个状态采用相应的缓解策略。这三个反馈循环分别解决了本地磁盘问题、外部连接问题和代理退化问题。
确实,我们的自动化缓解每月在所有三大云提供商中检测并自动缓解数千次部分退化,节省了宝贵的操作员时间,同时确保对客户的影响最小。
在任何有状态服务中跨服务器平衡负载是一个难题,直接影响到客户体验的服务质量。负载分布不均会导致客户受到最繁忙服务器提供的延迟和吞吐量限制。有状态服务通常有一组键,你需要平衡这些键的分布,以便总体负载均匀分布在服务器上,从而客户能够从系统中获得最大性能和最低成本。
例如,Kafka运行的状态性代理负责平衡分区及其副本到各个代理的分配。根据客户活动,这些分区上的负载可能会以难以预测的方式激增或下降。这需要一套指标和启发式方法来确定如何放置分区以最大化效率和利用率。我们通过一个平衡服务来实现这一点,该服务跟踪来自多个代理的一套指标,并持续在后台工作以重新分配分区。
重新平衡分配需要谨慎进行。过于积极的重新平衡会因这些重新分配产生的额外工作而破坏性能并增加成本。而过慢的重新平衡则会让系统在修复不平衡之前明显退化。我们必须实验了很多启发式方法,以收敛到一个适合各种工作负载的适当反应水平。
有效平衡的影响可能是巨大的。我们的一位客户在为他们启用重新平衡后,负载大约减少了25%。类似地,另一位客户由于重新平衡,延迟大幅减少。
如果你正在为你的组织构建云原生基础设施,无论是使用新代码还是使用像Kafka这样的现有开源软件,我们希望本文中描述的技术能帮助你实现性能、可用性和成本效率的目标。
为了测试Kora的性能,我们在相同的硬件上进行了小规模实验,比较了Kora和我们的全云平台与开源Kafka。我们发现Kora提供了更大的弹性,扩展速度提高了30倍;相比我们自管理客户或其他云服务的故障率,可用性提高了10倍以上;并且延迟明显低于自管理的Kafka。虽然Kafka仍然是运行开源数据流系统的最佳选择,但对于寻求云原生体验的人来说,Kora是一个很好的选择。
参考链接:
https://www.infoworld.com/article/3715426/5-tips-for-building-highly-scalable-cloud-native-apps.html
来源: 51CTO技术栈