CloudQuery 采用 Apache Arrow
已发布 2023 年 5 月 4 日
作者 Yevgeny Pats
这篇文章是与 CloudQuery 合作完成的,并在 CloudQuery 博客上交叉发布。
CloudQuery 是用 Go 编写的开源高性能 ELT 框架。我们之前讨论了构建高性能 ELT 框架所采取的一些架构和设计决策。类型系统是创建高性能和可扩展的 ELT 框架的关键组件,其中源和目标是解耦的。在这篇博文中,我们将介绍为什么我们决定采用 Apache Arrow 作为我们的类型系统,并替换我们内部的实现。
什么是类型系统?
让我们快速回顾一下什么是类型系统,以及为什么 ELT 框架需要一个类型系统。从很高的层面来说,ELT 框架从某个源提取数据,并将其以特定的模式移动到某个目标。
API ---> [Source Plugin] -----> [Destination Plugin]
-----> [Destination Plugin]
gRPC
源和目标是解耦的,并通过 gRPC 进行通信。这对于允许添加新的目标和更新旧的目标,而无需更新源插件代码至关重要(否则会引入无法维护的架构)。
这就是类型系统的用武之地。源插件以尽可能高性能的方式从 API 提取信息,定义一个模式,然后将 API 的结果(JSON 或任何其他格式)转换为定义良好的类型系统。目标插件然后可以轻松地为其数据库创建模式,并将传入的数据转换为目标类型。因此,概括地说,源插件主要向目标发送两件事:1)模式 2)符合已定义模式的记录。在 Arrow 术语中,这些是模式和记录批处理。
为什么选择 Arrow?
在使用 Arrow 之前,我们使用了自己的类型系统,该系统支持 14 种以上的类型。这很好地服务了我们,但我们开始在各种用例中遇到限制。例如,在数据库到数据库的复制中,我们需要支持更多的类型,包括嵌套类型。此外,从性能方面来看,ELT 过程中花费的大量时间都用于将数据从一种格式转换为另一种格式,因此我们想退一步,看看是否可以避免这个著名的 XKCD(通过构建另一种格式)。

这就是 Arrow 的用武之地。Apache Arrow 为平面和分层数据定义了一种与语言无关的柱状格式,并带来了以下优势:
- 跨语言,并为不同的语言提供广泛的库 - 格式是通过 flatbuffers 定义的,这样您可以用任何语言解析它,并且已经在 C/C++、C#、Go、Java、JavaScript、Julia、Matlab、Python、R、Ruby 和 Rust 中得到广泛支持(在撰写本文时)。对于 CloudQuery 来说,这一点很重要,因为它使得用不同的语言开发源或目标插件变得更加容易。
- 性能:Arrow 的采用率正在上升,尤其是在基于柱状的数据库(DuckDB、ClickHouse、BigQuery)和文件格式(Parquet)中,这使得为已经支持 Arrow 的数据库编写 CloudQuery 目标或源插件变得更容易,而且更加高效,因为我们消除了对额外序列化和转换步骤的需求。此外,仅仅是从源插件向目标发送 Arrow 格式的性能已经更高,并且内存效率更高,因为它具有“零拷贝”特性,并且不需要序列化/反序列化。
- 丰富的数据类型:Arrow 支持超过35 种类型,包括复合类型(即所有可用类型的列表、结构和映射)以及使用自定义类型扩展类型系统的能力。此外,已经存在从/到 arrow 类型系统和 parquet 类型系统的内置映射(包括嵌套类型),这已经在许多 arrow 库中支持,如此处所述。
总结
采用 Apache Arrow 作为 CloudQuery 的内存类型系统使我们能够获得更好的性能、数据互操作性和开发者体验。一些将立即获得丰富类型系统提升的插件是我们的数据库到数据库复制插件,例如 PostgreSQL CDC 源插件(以及所有数据库目标),它们将获得对所有可用类型的支持,包括嵌套类型。
我们对这一步感到兴奋,并加入不断壮大的 Arrow 社区。我们已经贡献了超过 30 个上游拉取请求,这些请求很快就得到了 Arrow 维护者的审查,谢谢!