为了账号安全,请及时绑定邮箱和手机立即绑定

我花了8小时研究WarpStream

重写(Rewrite)Kafka 协议的用 Go 并在完全基于对象存储系统上运行,这使得它能够完全在对象存储上运行。

作者自己画的图片!这张图片是作者自己画的哦!

这篇文章最初发布于(https://vutr.substack.com)。

引言

前不久写了一篇关于AutoMQ的文章之后,我打算写写其他的类似的消息系统,比如Redpanda、Pulsar,特别值得一提的是WarpStream,这个在2023年刚宣布的解决方案,作为Kafka的一个稳健的替代选项,能够在云端高效地运行。

虽然我在规划时并不想在找这篇文章的主题时写关于WarpStream的内容,然而到了9月10日,Confluent宣布收购了WarpStream公司并推出了[自带云(BYOC)]模式。这个消息让我比原计划更早地想写写WarpStream。

读到最后,你就可以看看我对WarpStream的一些个人见解。

动力

在我们深入了解卡夫卡之前,让我们先了解一下WarpStream创始人创立WarpStream的初衷。

  • 对于那些负责管理Kafka基础设施的人来说,挑战随即出现。通常,需要一个专门的团队来管理和处理Kafka所有操作上的复杂性。
  • 假设用户想要执行一个基本的操作,比如向我们的Kafka集群添加更多节点。在这种情况下,他们需要添加代理机器,重新平衡所有主题分区,然后等待数据复制。如果集群的利用率已经很高,扩展集群将增加大量负载,可能会使情况变得更糟。缩小集群也很复杂,用户需要移动数据,等待数据复制,并在不中断分区领导的情况下移除代理。
  • 在将Kafka部署提升并移动到云端时,网络成本可能非常高。例如,如果用户在三个可用区之间部署了一个Kafka集群,数据将多次跨网络边界传输,这将产生较高的成本,因为云服务商会对跨区域的数据传输收费。
  • 此外,在云中使用持久性存储,如AWS中的EBS(弹性块存储),成本也很高。Kafka的复制因子会增加存储费用。
  • 无法独立扩展存储层会导致资源浪费,当只是为了扩展存储层而添加更多的机器(CPU、内存和磁盘)时,会浪费云资源。

这就是为什么WarpStream的创始人团队决定用Go语言从头开始构建一个新系统,并让它兼容Kafka协议。

概述

客户必须使用自带计算模型来部署WarpStream。WarpStream通过无状态代理,即WarpStream代理,来取代传统的Kafka集群,这些代理部署在客户的账号下。WarpStream把消息数据存放在对象存储中,例如Amazon S3或Google Cloud Storage等。数据确保始终留在客户VPC内。代理本地磁盘仅用于缓存从对象存储获取的数据(详情请见后续说明)。

如下所示的图片由作者制作。

Jack Vanlightly 是 Confluent 的技术专家,他对 WarpStream 的 BOYC 模型做了很棒的分析。我非常推荐你看看他写的一篇很棒的文章 他写的文章

为了管理元数据,WarpStream 用运行在 WarpStream 云上的远程服务替代了 Zookeeper 或 KRaft 等。

代理

这张图是作者画的。

无状态的设计使得WarpStream代理能够在无需关心数据重平衡的情况下进行扩展。代理在客户的VPC内运行,保护数据隐私;只将元数据传回WarpStream云端。

WarpStream云端

WarpStream架构将数据平面和控制平面分离。数据平面是一群代理。控制平面运行在WarpStream云中,在那里它决定哪些代理将压缩数据文件以优化性能,哪些代理负责数据缓存,以及哪些代理将删除已超过保留期限的对象存储的数据文件。

作者绘制的插图。

控制平面使WarpStream能够兑现其作为Apache Kafka兼容的流处理系统的承诺,让WarpStream更加可靠,通过将共识和协调任务卸载到一个完全托管的控制平面。这种方法让客户使用起来更方便,同时确保所有数据安全地留在其VPC内。

此外,WarpStream 会将集群的元数据单独管理,与数据分离。不像使用 Zookeeper 或 KRaft 这样的方式,WarpStream 通过位于 WarpStream 云上的私有元数据存储来管理元数据。该存储是强一致性的数据库和对象存储的组合,位于 WarpStream 云账户内。

元数据存储中的绝大多数数据是指向对象存储中数据批次的指针。WarpStream 的元数据存储是所有主题分区的领导者,也负责确保 WarpStreams 中消息的有序性。它参与了消息的写入和读取流程;我们会在后面进一步讨论这个。

服务发现

在 Kafka 中,客户端通常通过 URL 或 IP 设置一个引导服务器列表。然后,它们发送元数据请求以识别这些服务器、它们所在的可用区(AZ)以及主题分区的领导。

图片由作者绘制。

客户端利用这些元数据来连接集群中的所有必要代理。在生成数据时,客户端总是尝试与特定主题分区的领导者进行通讯。根据其配置,在消费数据时,它可能会连接到主题分区的副本之一。

相比之下,由于WarpStream的代理是无状态的,可以处理任何请求。部署时,代理会发现所在的可用区,并将这些信息及其内部IP地址发送到WarpStream云中的服务发现系统。

与 Kafka 不同,客户端不需要设置 bootstrap 服务器列表。WarpStream 客户端只需要设置 WarpStream bootstrap URL。客户端会通过 DNS 将 WarpStream bootstrap URL 解析成 IP 地址。然后,WarpStream 的 DNS 服务器会返回可用的 WarpStream 代理 IP 地址。

作者的图片。

接下来,客户端向之前识别的代理发出元数据查询,代理会将查询转发给WarpStream发现服务,并返回一个与客户端处于同一可用区的特定代理的IP地址。

在 Apache Kafka 中,特定的代理充当各个主题分区的“领导者”。而在 WarpStream 中,没有特定代理被指定为任何主题分区的领导者。相反,任何 WarpStream 代理都可以在任意时刻读取或写入任何主题分区的数据。然而,由于客户端期望获取 Kafka 协议中的分区领导者的相关信息,WarpStream 仍然需要提供这些信息。

控制平面必须让客户端认为分配的代理是遵循Kafka协议的领导者。通过这种方法,客户端始终只与一个代理通信,从而减少集群中的连接数量,让负载均衡更简单。

WarpStream 采用轮询的方式来平衡连接到所有代理的负载分布,确保负载均衡。与开源 Kafka 的做法不同,在节点间重新平衡分区,WarpStream 则是在代理之间重新平衡连接。[(https://www.youtube.com/watch?v=DHravjus3Lw&t=1280s)]

写写

我们来看看WarpStream是如何传递消息写入请求的。

这是一张本文作者创作的图片。

  • 在上述服务发现过程之后,生产者知道了需要与哪些代理进行通信。
  • 生产者客户端会分批通过网络向代理发送消息。
  • 当从生产者接收到写入请求时,这些WarpStream代理会缓存来自多个生产者客户端的请求,然后分批将这些记录写入对象存储。

默认情况下,代理程序会将数据缓冲 250 毫秒或直到积累 8 MiB 的数据。用户可以调整缓冲时间以在成本和延迟之间找到平衡:较长的缓冲时间可降低成本但增加延迟,而较短的缓冲时间会提高延迟但降低成本。

  • 文件写入对象存储后,代理将WarpStream的元数据提交到WarpStream元数据存储。同时,消息的顺序也得到了确定。
  • 只有到这个时候,代理才会确认批次中的所有请求,并将确认信息回传给客户端。

由于代理需要进行这些步骤,如缓冲、写入对象存储和提交到元数据存储,这比原来的Kafka方案增加了更多的延迟。

缓存区

WarpStream 使用一致性哈希环将负载分布在各个代理上。每个代理负责所属主题的一个数据子集。当代理从客户端接收到 Fetch() 请求时,然后将请求转发给负责所需文件的代理。

FetchRequest 是消费者发送给 Kafka 代理服务器的请求,用于从该服务器拉取数据。

当请求到达合适的代理时,它将文件块加载到内存中,创建内存缓存。缓存中的每个数据块大约是16兆字节。然后使用这个缓存来处理未来的Fetch()请求,从而提高效率,

为每个AZ维护一个单独的缓存,这样Fetch()请求就不需要跨越AZ边界,从而避免了额外的延迟和跨AZ的数据传输费用。

对于历史读取或4兆字节及以上的大规模数据扫描,代理程序直接从对象存储系统读取数据,因为在这种情况下直接读取的效率更高。

让我们来探索一下WarpStream数据读取过程背后的步骤。

作者绘制的图片。

  • 当一个代理(Agent)——比如说代理(Agent)A——从消费者那里收到一个Fetch()请求时,它会将请求路由到负责所需数据的代理;我们称这一代理为代理(Agent)B。
  • 代理B会联系WarpStream云上的远程元数据存储,以获取包含所需数据的文件信息,以及这些文件的读取顺序。
  • 如果代理B在内存中没有这些数据,它会从对象存储中加载文件块到内存中,创建一个可以在未来请求中使用的内存缓存。
  • 数据从内存中返回给消费者端。
  • 一旦文件被缓存,后续的客户端请求可以直接从内存中获取,减少了对对象存储的重复访问。
消息排列

在 Kafka 里,消息会被确保按顺序消费,就像它们本来就是按顺序写的一样。确定消息的顺序非常容易,因为所有消息写入都必须由领导者们来处理。

然而,WarpStream 允许多个代理节点(其中任何一个都可以是领导者)同时向任何分区写入数据,使得特定分区的数据分散在多个文件中,没有特定顺序。那么 WarpStream 又是如何确保消费者能够按顺序接收消息的呢?

WarpStream 定义了代理在将文件写入对象存储后提交元数据给元数据存储的消息顺序。在这个阶段,元数据存储会确定对象存储中文件消息的顺序。

从给定偏移量读取数据时,代理会查询元数据存储,获取包含该偏移量的数据流。元数据存储返回有序的数据流列表,确保客户端能从这些数据流中正确获取数据。

压实

在后台,WarpStream 的压缩过程会在代理中自动运行。它将最近写入的小文件或大小差异显著的文件合并成更大且更统一的文件。

作者自绘的图片。

主要目标是统一文件大小和优化读取历史数据的过程。这种组织确保了同一分区的数据在物理上存储得更紧密。当工作负载需要回放历史数据或追赶落后进度时,这种组织方式可以从对象存储中实现高吞吐量的顺序读取,从而能够高效地访问大量的数据。

代理组

作者画的图片。

WarpStream的一个架构优势是其灵活的设计。用户甚至可以通过为不同的任务部署独立的代理组来隔离任务负载,例如分别处理生成、消费和后台压缩操作。这些称为“代理组”的小组可以保持操作上的独立,同时仍然从同一个存储中读取数据。

在 Kafka 中,若想达到这种隔离程度,用户需要为每个用途部署独立的集群。

结束语

本文将深入分析WarpStream的技术细节,以理解为什么尽管它直到2023年才被宣布,它迅速吸引了大量关注并最终被Confluent收购。

基于他们在 Datadog 构建可扩展数据存储 Husky 的经验,WarpStream 的创始人开发了一个更优秀的流处理平台,旨在在云端高效地替代和运行 Kafka。WarpStream 提供了一个高度成本效益的 Kafka 替代方案,管理所有复杂性和操作开销(这对许多客户来说非常有价值),同时允许客户将其数据保持在私有 VPC 中。成本优势主要来自两个关键因素:避免跨可用区的数据传输,和利用 100% 的对象存储进行数据持久化。

不过,WarpStream 并不是没有缺点。它旨在提供对 Kafka 的兼容性,但并非完全兼容。一些功能,例如事务,目前尚不支持(但它们承诺很快会添加这些功能)。除了现有的功能差距外,WarpStream 可能还需要一些时间来赶上未来 Kafka 的新功能,以满足用户需求。

最后但也很重要的是,让我们来谈谈延迟。根据WarpStream的创始人所述,在设计系统时,他们为了降低成本而牺牲了一部分延迟。当客户端生产一条消息时,代理首先缓存数据,然后写入对象存储,并提交元数据到远程存储。只有在完成这些步骤后,代理才会向客户端确认生产请求。这使得系统在生产请求上的P99延迟大约为400毫秒。此外,从生产者到消费者的端到端P99延迟大约为1秒。下面是一段创始人的原话:

如果你的工作负载能够容忍大约1秒的P99生产者到消费者延迟,那么WarpStream可以将每GiB的数据流成本降低至原来的1/5到1/10,几乎无运营成本。— 来源

如前所述,用户可以通过以下方法来降低延迟:

  • 用户可以调整写入路径中的缓冲时间;这会减少延迟,因此,由于更频繁的向对象存储发送 PUT 请求,成本会更高。
  • 使用 Amazon S3 Express One,它比标准 S3 更贵。

然而,不过对于不太关注延迟的应用场景,比如数据变更捕获(CDC),这个不足肯定不会成为客户的太大障碍。

我觉得关于WarpStream的文章就说这么多吧。总体来说,如果我遗漏了什么,请告诉我。欢迎大家在评论区留言或讨论。

真的非常感谢你能一直陪我到最后,下回见,期待在下一篇见你!

参考文献

理查德·阿图尔(Richard Artoul),卡夫卡的精神长存 (2023年)

[2]WarpStream官方指南

[3] Yaroslav Tkachenko,云时代下的流媒体平台 (2024)

[4] 极客叙述者,WarpStream:一个用于替代 Kafka 的即插即用工具 (2024)

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消