The Linux Foundation Projects
Delta Lake

Rivian 通过 Delta-Go 扩展了 Delta Lake 生态系统

作者:Chelsea JonesRahul MadnawatJason Shiverick

高容量事务的实时数据摄取,现已开源

今天,我们很高兴地宣布新的开源 Delta-Go 连接器的可用性——它是 Rivian 架构中的一个关键组件,旨在以高效且经济的方式摄取大量实时数据。我们非常高兴能将此连接器带给社区,希望您也能从中受益,并欢迎贡献以帮助进一步发展此项目!

背景

在 Rivian,我们对可持续发展和尖端技术的承诺促使我们探索新的领域。想象一下每天处理由超过 80,000 辆联网汽车生成的数据,其规模达数 TB。通过高效摄取和分析这些数据,我们可以实现预测性维护、改进性能和可靠性、增强安全性以及定制等新功能。

在这篇博客中,我们将深入探讨并分享我们数据摄取之旅的见解。我们将探索面临的挑战,我们如何通过构建 Delta-Go 连接器来解决这些挑战,以及学到的经验教训。那么,让我们深入探讨吧。

框架选择

为了处理海量数据——每秒 980 万条记录——我们早期面临着大规模摄取流式 IoT 工作负载的挑战。在投资不同的架构和文件格式时,开源格式 Delta Lake 因以下原因成为最佳选择

  • 原子事务:鉴于PCAP(从网络接口捕获的数据包数据)数据从不同来源(传感器、设备和车辆)同时到达,每个来源都贡献其独特的流,因此支持原子事务的存储框架至关重要。
  • 优化查询:使用 Delta 元数据可以优化查询,从而实现经济高效的解决方案。
  • 数据完整性和质量:我们的机器学习工程师和数据科学家在管理模型开发和部署工作流程时必须信任数据输入。

此外,选择合适的编程语言以更好地管理来自不同来源的并发数据流也至关重要。Go (Golang) 因其固有特性成为理想选择

  • 性能:Golang 作为一种编译语言,在执行前会转换为机器代码,从而产生高效的程序。
  • 并发性:Golang 内置了对并发性的支持,简化了创建能够利用多核的程序,这对于高流量应用程序来说是一个福音。
  • 简单性:Golang 拥有简洁的语法,使其成为新手和经验丰富的开发人员寻求易学性的绝佳选择。
  • 工具:Golang 提供了一套强大的开发和部署工具,包括编译器、调试器、链接器和打包器,促进了无缝应用程序开发。

总之,Go 提供了两全其美:性能、并发处理和流线型开发。它是处理高数据量现代应用程序的强大工具。

技术挑战

我们最初的方法是将所有 PCAP 数据写入 Parquet 文件,不包括 Delta 元数据。然后我们使用 Auto Loader 来执行 Spark 作业,将这些 Parquet 文件摄取到 Delta 表中。然而,这种方法有其缺点

  • 挑战 #1:存储开销:以 Parquet 和 Delta 两种格式存储数据导致冗余并增加了存储需求。
  • 挑战 #2:处理开销:格式之间的不断转换和数据的重写在读写操作期间产生了显著的处理成本。我们最终有 20 个 Spark 工作程序不间断地运行,将这些 parquet 文件摄取到我们的 Delta 表中。

"Earlier architecture with data redundancy and extra processing workload"

早期架构的数据冗余和额外的处理工作负载

我们意识到直接从 Go 写入 Delta Lake 格式将是一个更高效的解决方案,避免了双重存储格式的需求并降低了处理复杂性

Delta Lake + Go 连接器

为了减轻这种开销,我们研究了开发一个 Delta-Go 连接器,目标是实现将 PCAP 数据直接写入 Delta 表。

"A new architecture featuring our Delta-Go connector to ingest data from the Edge directly into Delta Lake."

采用我们 Delta-Go 连接器的新架构,将数据从边缘直接摄取到 Delta Lake。

在 Delta-Go 连接器的首次实现中,Spark 和 Delta-Go 的同时写入导致了竞态条件,错误地覆盖了表版本。为了解决这个问题,我们在 Delta-Go 中引入了一个由 DynamoDB 支持的日志存储,确保与 Spark 现有实现的兼容性,并通过让两个引擎使用相同的日志存储后端来防止竞态条件。

我们使用 SQS 队列接收数据通知,我们的数据解析器,一个利用 delta-go 的 Go 应用程序,在 Kubernetes 上运行。得益于 Go 的并发支持,每个 Kubernetes 节点都可以独立并发处理多个传入消息。通过增加处理 goroutine 的数量可以实现在节点内扩展处理,而通过添加更多 Kubernetes 节点可以轻松实现整个系统的扩展。

Delta-Go 连接器轻松地每秒向我们的 delta lake 表写入 10 次提交。随后,我们通过将 delta 事务合并到更大的日志中来优化我们的代码,从而提高了下游处理效率。

以下是使用 Delta-Go 连接器将数据直接添加到 Delta Lake 的示例

logStore, _ := dynamodblogstore.New(
  dynamodblogstore.Options{
    Client: dynamoDBClient,
    TableName: sharedLogStoreTableName,
  })
table := delta.NewTableWithLogStore(store, lock, logStore)
transaction := table.CreateTransaction(delta.NewTransactionOptions())
add, _, _ := delta.NewAdd(store, storage.NewPath(filePath), partitionValues)
transaction.AddAction(add)
transaction.CommitLogStore()

好处

Delta Lake 因其额外的元数据层而成为性能的改变者,该层允许原子事务并提高查询性能。如果没有这一层,查询 Parquet 文件的效率将大大降低。通过消除不间断的 Spark 进程,我们估计与之前的方法相比,每天可节省 500 美元。效率和经济性是相辅相成的。

Delta-Go 连接器与 Spark 无缝集成,这得益于共享的 Delta Lake 日志存储。这个通用的日志存储可以防止并发问题,让您可以放心地将 Spark Optimize 与 Delta-Go 一起使用。

将 Delta-Go 提升到新的水平

我们热衷于 Go,重视它的简单性、并发管理和效率。受 Delta-rs 的启发,我们致力于进一步提升 Go 开发人员的用户体验,力求在生态系统中提供相似的简单性和功能。此外,我们欣赏开源 Delta Lake 格式提供的强大功能,使我们能够有效地处理海量数据。

作为开源的坚定支持者,我们自豪地提供我们的Delta-Go 连接器,以帮助您的公司提高效率并节省成本。然而,需要注意的是,该连接器当前的功能是根据我们特定的业务需求量身定制的。还有很大的扩展和贡献空间。欢迎克隆我们的仓库并共同协作增强 Delta-Go 连接器!