Eclipse Aerospace 借助 Databricks 简化飞行数据摄取
Eclipse Aerospace simplifies flight-data ingestion with Databricks
Eclipse Aerospace 与 Databricks 合作,利用 PySpark 自定义数据源将专有飞行数据格式直接接入 Spark,无需再经 AWS Lambda 中转解码。
随着航空航天、制造业、生命科学及其他数据密集型行业的企业推进运营现代化,它们正将更多传感器、遥测和科学数据引入数据平台。但这些数据中的大部分仍难以大规模使用,因为它们以主流分析引擎无法直接读取的专用或专有格式存储。这带来了一个现实的行业挑战:团队必须在构建缓慢、内存密集型的自定义转换、维护专用连接器,或在数据分析前增加额外的解码阶段之间做出选择。
PySpark 自定义数据源提供了一条更简单的路径。它让团队能够使用 Python 将专用格式引入 Spark,而无需从零构建单独的连接器。对于轻型喷气机制造商和运营商 Eclipse Aerospace 而言,与 Databricks 合作提供了一种方式,使近二十年的专有飞行数据能够更便捷地供服务中心和工程师使用,而无需增加昂贵的常开基础设施。Databricks 提供了无服务器数据平台和 Spark 集成,而 Eclipse Aerospace 则贡献了其现有的飞行数据解码器和航空航天专业知识。
Eclipse Aerospace 与 Databricks 共同开发了一条从飞行数据到分析的更直接路径,减少了此前多阶段流程的延迟、重复和运营开销,同时保留了 Databricks Serverless 的灵活性。
Eclipse Aerospace 的数据摄取挑战
Eclipse Aerospace 依赖 Databricks 存储近 20 年的飞行数据,总计超过 3TB。它通过来自超过一百万飞行小时的数据为服务中心和工程师提供支持,这些数据从多个来源获取并验证,包括:近实时卫星遥测;完整飞行历史的大批量上传;以及外部数据源。其所有遥测数据都以需要自定义解码器的专有文件格式存储,这些解码器已用多种语言开发,包括 Rust 和 Scala。
在 Databricks Runtime 15.4 LTS 中提供 Pyspark 自定义数据源之前,Eclipse Aerospace 团队有三种可行方案来解码其专有文件类型并将其加载到 Databricks 中:
- 将文件作为二进制类型加载并使用 Python 用户定义函数(UDF)拆分
- 在专用计算资源上使用 Scala 自定义解码器
- 在加载到 Databricks 之前将文件解码为中间文件类型
对于简单的自定义文件类型,UDF 是一种自然的选择。它们以性能换取可读性。然而,当消息格式具有可变长度时,UDF 存在长消息导致内存耗尽的真实风险,因此无法使用。现有的 Scala 解码器可用于实现原生 Data Source v1/v2,但在 Databricks 中使用它需要专用计算资源。用户期望能够快速上传和查看数据,这需要保持该计算资源始终开启,其成本高于其他无服务器选项。这使得团队只剩下最后一个选项:通过 AWS Lambda 上基于 Rust 的解码器将文件解码为中间文件格式,在本例中为 Avro。
该解决方案成本低廉,但它:
- 引入了多跳摄取模式带来的延迟
- 在 Lambda 解码器与消费 Avro 输出的下游 Spark 作业之间重复了模式逻辑
- 这给团队带来了管道可观测性方面的成本;Spark UI 和作业指标只能看到从 Avro 着陆区开始的世界,因此调试缓慢或失败摄取过程的工程师不得不去平台完全不同的部分查找 Lambda 日志
- 意味着要同时支付存储原始二进制文件及其 Avro 副本的费用
为什么 Databricks 和 PySpark 自定义数据源很重要
Databricks 已经是 Eclipse Aerospace 存储和处理飞行数据的平台。决定性优势在于 Spark 原生执行、PySpark 自定义数据源和 Databricks Serverless 的结合。Databricks Serverless 自动分配和管理按需计算,因此 Eclipse Aerospace 无需预置或保持专用基础设施运行。PySpark 自定义数据源使得无需构建 JVM 连接器即可包装现有的 Rust 解码器。由于解码现在在 Spark 内部运行,同一平台提供了 Spark UI、作业指标和下游 Delta 工作流,而不是将关键的摄取步骤交给单独的 Lambda 管道。
大多数数据工程依赖于常见的数据格式,但一些最有价值的数据仍然隐藏在 PySpark 无法直接访问的格式中,例如用于科学数据的 HDF5 以及航空航天数据的行业标准如 ARINC 429。Databricks Serverless 为团队提供了一种灵活的方式来大规模解锁这些数据,而 Rust 支持的实现可以提供超越纯 Python 方法的性能。
PySpark 自定义数据源允许你用纯 Python 定义可读写的文件格式,像任何其他数据源一样使用。其主要优点是简单性,允许用户定义用纯 Python 读写的函数,以及定义并行化等重要特性。Eclipse Aerospace 团队更进一步:通过构建 Rust 支持的 Python 包,它提供了与类似的基于 PyArrow 的纯 Python 数据源相比两倍的基准性能。与没有 Arrow 的原生 Python 实现相比,它提供了近 20 倍的性能。
以下示例代码仓库演示了针对 ARINC 429 的自定义数据源。随附代码包含超出本文范围的设计决策,以及你可以自行运行的基准测试。
这如何通过 PySpark 自定义数据源变得可解决
Apache Spark 4.0 发布了 Python 数据源 API(在 Databricks 文档中称为 PySpark 自定义数据源),允许你为批处理或流数据注册自定义格式,例如:
该 API 在 Apache Spark 4.0 中引入并在 Databricks 上可用,从 Databricks Runtime 15.4 LTS 起正式可用,并且也在 Serverless 环境 2 及更高版本上受支持。由于该 API 用 Python 实现,它不需要单独的 JVM 连接器或 JAR。
该 API 是用于创建原生数据源的简化接口,用户实现几个类并通过以下方式注册它们:
这些解码器有两种形式:原生 Python 和 Apache Arrow 格式,后者是性能高得多的选择。Apache Arrow 是一种“用于扁平数据和嵌套数据的语言无关的列式内存格式”,使其成为不同语言共享数据对象之间的理想接口。该 API 利用这一点,允许用户直接返回 pyarrow.RecordBatch 对象,Spark 将把它们作为批次消费,而不是每行物化一个 InternalRow。
这引出了一个问题:能否让 Python 作为控制层,由 Rust 承担解码的重任,同时全程保持 Apache Arrow 格式?
解决方案架构概览
其背后的架构是一个单一的逻辑连接器,其解码路径几乎完全由编译代码构成,而 Python 层足够薄,对 Eclipse Aerospace 现有的 Rust SDK 改动极小。这个薄 Python 层使用 PyO3/Maturin 构建为独立包,导入管道后就像任何其他数据源一样使用。为确保最佳性能和关注点分离,团队遵循了几条架构原则。

解码器并不知道 Spark 的存在。 核心 Rust crate 不依赖 PyO3、Arrow 或 Spark,只接收字节并返回结构化记录。这使得 Eclipse Aerospace 能够基本原样移植现有的解码逻辑,因为 SDK 无需为此重写,只需包装。
Arrow 是唯一跨越外部函数接口(FFI)边界的东西,而且它跨越边界时无需复制。 Rust 胶水层使用 arrow-rs 构建一个 Arrow RecordBatch,然后通过 Arrow C Data Interface 将其作为 pyarrow.RecordBatch 交给 Python。在此过程中没有序列化步骤,因为不会重新编码字节,也不会构建逐行的 Python 对象。Rust 分配的缓冲区就是 Python 读取的缓冲区。
PySpark 层有意保持轻量。 它解析选项、决定如何分区(参考示例中每个输入一个 InputPartition),并定义 schema。在 PySpark 自定义数据源中,DataSource、DataSourceReader 及其流式等价物都必须可序列化,这样 Spark 才能 pickle 读取器实例并将其发送到 worker。通过让 PySpark 层保持轻量,Spark pickle 并发送到 worker 的 DataSourceReader 实例只持有纯 Python 状态(文件路径、表示批大小的整数)。由 PyO3 支持的 Rust 对象在 read() 内部构造,此时读取器已经到达 worker。它本身永远不会成为被 pickle 的内容的一部分。
原生代码以 Python wheel 形式发布,使用 Maturin 构建。在 Databricks 上,该 wheel 是一个构建产物,作为普通 Python 依赖附加到作业或笔记本环境。由于实现是编译的,版本和架构兼容性需要谨慎处理,不过正如示例仓库所展示的,适当的 CI/CD 流程可以管理这一点。
连接器如何在 Databricks 中运行
在 Databricks Serverless 上,运行时路径很直接:
- 专有遥测文件落到云存储中。
- Databricks Spark 读取调用为自定义格式注册的 PySpark 自定义数据源。
- 在 Databricks 上运行的 Spark 创建一个包含输入路径和读取选项的可序列化读取器,然后在 worker 上调度输入分区。
- 每个 worker 在
read()内构造 Rust 解码器,并将文件字节传递给编译后的解码器。 - Rust 通过 Arrow C Data Interface 返回 Arrow RecordBatch,避免序列化和逐行 Python 对象。
- 在 Databricks 上运行的 Spark 消费这些批次,并将解码后的数据写入下游表(如 Delta)。
- 解码错误、坏记录、Spark UI 阶段和作业指标在 Databricks 工作流中仍然可见。
这是与之前设计的关键区别:原始文件作为 Spark 读取的一部分被解码,而不是先复制到中间的 Avro 暂存区。
这对 Eclipse Aerospace 产生了什么影响?

通过用单次 Spark 原生读取取代多阶段的 Lambda 和 Avro 工作流,Eclipse Aerospace 让飞行数据更快可用,同时减少了基础设施、存储和运维开销。新的 Arrow 原生 PySpark 自定义数据源连接器还将解码引入 Spark,提升了对管道性能的可观测性,并让 schema 和数据质量逻辑可以集中在一处管理。
实现自定义数据源显著简化了 Eclipse Aerospace 的基础设施,其效果体现在四个不同方面:延迟、成本、可观测性和工程时间。
延迟。将多跳管道(上传、Lambda、解码、写入 Avro、读取 Avro、加载到 Delta)合并为单次 Spark 原生读取,消除了多个网络跳转,以及文件在队列中等待下一阶段拾取的多个环节。新连接器可以在文件上传后一分钟内处理记录(包括启动时间),并且由于并行性,通常可以在两分钟内并行处理大型、数 GB 的批次。
成本。移除 Lambda 跳转和 Avro 中间层,消除了 Eclipse Aerospace 必须运行、监控和付费的一整层基础设施。他们不再需要为每份飞行数据存储两份副本(原始二进制文件及其 Avro 转换),在近二十年的保留飞行历史中,这相当于大量重复存储。这意味着大多数文件仍保留在 AWS 的 Glacier 存储中,如果将来需要原始数据,可以轻松重复解码。
可观测性。由于解码步骤现在发生在 Spark 内部,它会像作业的任何其他阶段一样显示在 Spark UI 和标准作业指标中。Eclipse Aerospace 使用自定义的“badRecordsPath”(模仿 CSV/JSON 加载器)来捕获格式错误的数据,并维护广泛的数据质量管道,直接从解码器捕获统计信息。
工程时间。Schema 逻辑过去需要定义两次:一次在生成 Avro 的 Lambda 解码器中,另一次在消费它的下游 Spark 作业中。消息格式的任何变更都意味着要在两个不同的代码库中更新两处,并且存在两个定义逐渐偏离的风险。使用单一、版本化的连接器,schema 只需定义一次,就放在解码逻辑旁边。这也意味着相同的架构模式——一个包装 Rust 解码器的轻量 Python DataSource——现在可以复用于 Eclipse Aerospace 支持的其他专有格式,而不是必须为每种格式重新发明。
Eclipse Aerospace 的经验表明,如何将专用数据格式引入 Databricks,而无需围绕它们构建单独的摄取平台。通过将解码器保留在 Rust 中、使用 Python 作为集成层,并通过 Apache Arrow 传递记录,自定义数据源直接在 Spark 中读取原始文件,并保持与 Databricks Serverless 灵活性的兼容。
对于处理专有或行业特定格式的团队来说,可复用的模式很简单。工程师可以将领域特定的解码逻辑保留在源格式附近,通过 PySpark 自定义数据源将其暴露出来,并让 Spark 负责分区、执行、可观测性和下游处理。
想要开始使用?请查看以下内容:
常见问题
什么是 PySpark 自定义数据源?
PySpark 自定义数据源是用 Python 实现的用户定义 Spark 数据源。它让团队能够在标准 Spark 工作流中读取特殊文件格式,而无需构建单独的 JVM 连接器。
自定义 Arrow 原生 PySpark 自定义数据源连接器解决了什么数据摄取问题?
Arrow 原生 PySpark 自定义数据源连接器可将专有飞行遥测数据摄取到 Databricks 中,而无需依赖多阶段管道、专用的常开计算资源或原始文件的重复 Avro 副本。
什么是 Databricks Serverless?
Databricks Serverless 是一项完全托管的计算服务,让您无需在云账户中预置或管理任何基础设施即可运行工作负载。Databricks 会为您自动分配、扩展和优化计算资源。
Databricks Serverless 如何连接到 Arrow 原生 PySpark 自定义数据源连接器?
该连接器使用 PySpark 自定义数据源在无服务器计算上的 Spark 中运行文件读取逻辑。Python 负责控制流,而 Rust 和 Apache Arrow 负责高性能解码和数据传输。这使得专有文件可以直接读取,而无需专用的常开计算资源或中间 Avro 管道。PySpark 自定义数据源在 Databricks Runtime 15.4 LTS 及更高版本,或无服务器环境版本 2 中可用。
来源:Databricks Blog · databricks.com