DEV Community

liliwei
liliwei

Posted on

Iceberg顶层设计-FileIO:云原生表

作者:Daniel Weeks
原文:https://tabular.io/blog/iceberg-fileio/
日期:2021年12月16日,星期四

在这里插入图片描述

在过去的几个月里,我们被问到很多关于 Iceberg FileIO 的问题,比如“它是否支持 Azure 或 Google Cloud?” 或“为什么不使用 Hadoop 中的 S3AFileSystem?”。基于这些对话,关于 FileIO 是什么以及它在各种存储提供者和处理引擎中扮演的角色,似乎存在相当多的困惑。这是一个绝佳的机会,可以更深入研究 Iceberg 的内部设计,并阐明它和传统方式在与存储层连接方面有何不同。

什么是 FileIO?

在这里插入图片描述

FileIO 是核心 Iceberg 库和底层存储之间的主要接口。我经常说它仅仅只是两个操作:open for read 和 open for write。这种说法虽然过于简化,但却体现了此接口的简明直接。冰山之所以能够实现这一点,是因为它拥有与传统数据管理方法完全不同的体系结构。

为什么我们需要 FileIO?

在过去十年中,分布式计算已从工程性挑战发展成为整个数据平台和生态系统的基础。与此同时,从数据中心和自管理的分布式存储(如HDFS)到基于云的存储(如AWS S3)的转变也随之而来。这些转变暴露了传统中存储和计算配对耦合的缺点。

在这里插入图片描述

某些操作(例如 listing )在云存储中昂贵且缓慢,并且在某些情况下产生不一致性,具体取决于存储提供者的保证。传统的分层路径和分区结构与S3等系统中基于 key space 的最优布局相反,这就加剧了这种情况。虽然对象存储可以处理大量数据和请求,但传统的数据管理方法给许多系统带来了压力,不断将它们推向失败的临界点(至少从客户端的角度来看)。
文件系统目录也会引起问题,因为计算运行时布局会发生变化。当作业提交数据时,重命名操作作为一个集合并不是原子的。在云端,一些重命名的实现根本不是原子的,它分为两个操作:复制和删除。这意味着数据的读取者和写入者之间没有真正的隔离。虽然可以通过仔细安排工作流程以避免 冲突/不一致 来避开它,但这容易出错并且无法应对不断增加的并行工作负载和临时性分析需求。

分布式处理中的文件系统

为了了解 Iceberg 如何解决许多分布式处理系统中存在的众多挑战,它有助于认识到分布式存储和计算是一起发展的。这种密切的关系自然致使利用存储层来解决计算领域中出现的一系列问题。我们将看两个这样的例子。

数据布局和任务规划(Dataset Layout and Task Planning)

第一种情况与传统上的数据组织方式有关:按目录。这在同时构建存储和计算的上下文中是有意义的。早期的数据收集通常相当混乱且不一致,而计算则是直接人工使用 MapReduce API 编译的代码。这让 Job 的编写者承担了很多解析和理解存储层中存在的数据的职责工作( hence path based addressing and schema-on-read )。不同的数据被放置在不同的路径和层次结构下,路径的上下文通常用作物理分区,以减少单个作业读取的数据量。模型中的数据由物理文件布局定义,因此处理数据依赖于列出目录来找出 Job 的输入文件。
在这里插入图片描述

随着计算领域的发展,在文件系统之上又添加了一些层级以进一步抽象这种复杂性。Hive metastore 带来了一个逻辑抽象,允许按名称引用数据,但并没有解决物理路径和分区(路径仍然显式地作为表模式中的列出现)。文件系统仍然是必不可少的组件,并发挥着同样的核心作用。

提交数据

第二种情况与分布式运算作业如何产生数据以及文件系统在该过程中所起的作用有关。为了使计算既能分布式处理又具有高可靠性,要有两个特性:需要将执行分解为可并行处理数据的子任务,并且每个任务必须是幂等的以支持重试和预测执行。再次,文件系统开始发挥作用,因为每个任务尝试写入一个文件并利用文件系统层中的条件重命名来消除竞争写入的冲突。
在这里插入图片描述

在这两种情况下,文件系统在定义数据和为并发\冲突解决提供锁定机制方面都发挥着关键作用。在隔离处理大量数据的情况下,这些机制在一定程度上起作用,并且在十多年来一直是分布式处理的基础。不幸的是,这些机制随着分布式处理需求的规模/复杂性的增长而逐渐失效,需要开始适应新的生态系统(例如基于云的基础设施),并且对数据完整性有更严格的要求。

云原生 I/O 架构

Iceberg 设计的一个主要重点是解决数据集和文件结构交互处理所引起的问题。我们构建基于云的数据处理基础设施的经验使我们敏锐地意识到了之前所列举的挑战,Iceberg 提供了一个机会,从根本上重新思考支撑表的存储的接口。
在这里插入图片描述

Iceberg 之所以可以利用像 FileIO 这样的简洁接口,是因为所有的位置信息在元数据结构中都是显式的、不可变的和绝对的。Iceberg 不引用目录,它从文件级别跟踪了表的完整状态。因此,从元数据层次结构的最顶层,你可以直达任何存储位置,而无需进行 listing 操作。同样,提交动作是向元数据树添加一个完全可访问且不需要重命名操作的新分支。
在文件级别跟踪数据还允许 Iceberg 完全抽象物理布局。分区信息以文件级别存储在元数据中,因此物理位置完全独立于逻辑结构。这种分离机制可以通过底层数据的转换支持隐藏分区。

FileIO 实践

计算引擎

我们已经讨论了 FileIO API 存在的原因以及它解决的问题,但它在如何应用和适应现有实现方面还有一些细节。为了了解 FileIO 的使用位置和方式,我们将其用法分为两个不同的类别:元数据操作和数据操作。
在这里插入图片描述

元数据操作在计划和提交阶段执行,其中读取和写入元数据文件(metadata file)、清单列表(manifest list)和清单(manifest)等文件。在 Iceberg 库中,这些操作完全通过 FileIO API 进行。在某些情况下,这些文件是由 workers 读取的(例如,元数据表的分布式处理),但为了简化描述,我们暂时忽略这些差异,因为所有元数据都流经 FileIO 之手。
数据操作与计算引擎在任务处理期间读取和写入数据的位置有关。任务使用 FileIO 接口来读取和写入底层数据文件。在提交过程中收集这些文件的位置并将其添加到表元数据中。值得注意的是,并不是所有的读/写操作都需要经过这条路径,因此引擎可以自定义它们与数据交互的方式。最终,读取位置由核心 Iceberg 库提供,输出位置被收集以重新提交回表中。

FileIO 实现类

Iceberg 也有多个 FileIO 实现,但从广义上讲,它们可以分为两类:HadoopFileIO 和原生 FileIO 实现。
HadoopFileIO 在任何现有的 Hadoop 文件系统实现(HDFS、S3、GCS 等)和 Iceberg 的 FileIO API 之间提供了一个适配器层。这意味着任何具有 Hadoop 文件系统实现的存储系统都可以与 Iceberg 一起使用。
在这里插入图片描述

也可以提供像 S3FileIO 这样的原生实现。但是,如果 S3AFileSystem 可以轻松适应,为什么还要使用原生 S3 实现呢?主要是因为它有许多优点:

  • 契约行为: Hadoop 文件系统实现具有严格的契约行为,导致额外的请求(存在检查、解除目录和路径冲突等),这增加了开销和复杂性。Iceberg 使用完全可寻址且唯一的路径,避免了额外的复杂性。
  • 优化上传: S3FileIO 通过逐步上传数据来优化存储/内存,以最大限度地减少大型任务的磁盘消耗,并在打开多个文件时保持低内存消耗。
  • S3 客户端定制化:客户端使用最新的主流 AWS SDK 版本 (v2),并允许用户完全定制化 S3 客户端(包括任何与 S3 API 兼容的点)。
  • 序列化性能:使用 HadoopFileIO 的任务需要在运行时序列化Hadoop配置,这是相当大的,在恶化的情况下会减慢处理速度,并导致比处理数据更多的开销。
  • 减少依赖关系: Hadoop 文件系统的实现引入了一个大的依赖关系树,而简化的实现降低了整体打包的复杂性。

这些只是 S3 实现的一些例子,但是最近增加的 GCSFileIO(Google Cloud) 和 OSSFileIO (Aliyun) 都存在类似的增强。因此,尽管有一种简单的方式可以支持任何与 Hadoop 兼容的存储层,但 FileIO 提供了另一种可以在任何系统中存储数据的途径,只需基本的读/写操作而不需要完整的文件系统语义。

Iceberg FileIO 是未来

鉴于接口的范围有限,FileIO 似乎是一个非常简单的概念。然而,它所代表的是一种完全不同的思考引擎和表格格式(table format)之间交互的方式。Iceberg 的体系结构开辟了一条前进的道路,消除了许多在存储接口上产生变通办法的遗留约定,并将重点更聚焦于表接口和在数据集及以上级别提供保证所必需的契约上。

Top comments (0)