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 维护者的审查,谢谢!