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)中,这使得编写 CloudQuery 目标或源插件更容易数据库已经支持 Arrow,并且效率更高,因为我们消除了额外序列化和转换步骤的需要。此外,鉴于其“零拷贝”特性并且不需要序列化/反序列化,仅将 Arrow 格式从源插件发送到目标的性能就已经更高效且内存效率更高。
- 丰富的数据类型:Arrow 支持超过 35 种类型,包括复合类型(即所有可用类型的列表、结构和映射)以及使用自定义类型扩展类型系统的能力。此外,已经内置了从/到箭头类型系统和 parquet 类型系统(包括嵌套类型)的映射,这在许多箭头库中已经支持,如此处所述。
总结
采用 Apache Arrow 作为 CloudQuery 内存类型系统使我们能够获得更好的性能、数据互操作性和开发人员体验。一些将立即获得丰富类型系统提升的插件是我们的数据库到数据库复制插件,例如 PostgreSQL CDC 源插件(以及所有数据库目标),它们将获得对所有可用类型的支持,包括嵌套类型。
我们对这一步以及加入不断发展的 Arrow 社区感到兴奋。我们已经贡献了超过 30 个上游拉取请求,这些请求得到了 Arrow 维护人员的快速审查,谢谢!