DeltaFS: A Scalable No-Ground-Truth Filesystem For Massively-Parallel Computing——论文阅读

论文发表于 SC 2021 Paper元数据论文阅读汇总

“High-Performance Computing (HPC)” 高性能计算

“Remote Procedure Call (RPC)” 远程过程调用

“Directed Acyclic Graph (DAG)” 有向无环图

“Log-Structured Merge Tree (LSM-Tree)” 日志结构合并树

背景

尽管现代高性能计算(HPC)应用程序可以根据需要请求内存原子性,它们的持久状态(存储为文件并通过共享的底层并行文件系统访问)始终在全局范围内同步 [65, 66, 79]。即使在全球最大的 HPC 计算机上也是如此:每个进程都被保证始终看到每个其他进程的最新文件系统命名空间变化,而不管这些进程是否进行通信,也不管可能的巨大性能损失。如今的并行文件系统在语义上几乎与 50 年前为单核机器开发的相同。然而,它们现在面临着像并行计算系统一样迅速扩展的问题 [75],由于性能瓶颈抵消了大规模并行性的好处。

全局同步

文件系统是应用程序与持久性数据交互的主要方式。本地文件系统管理单个节点的文件,分布式并行文件系统如 Lustre [66]、GPFS [65]、PVFS [18] 和 Panasas PanFS [79] 管理着超级计算机 [75] 的文件。通过在大型对象存储设备池中分条存储数据,分布式文件系统实现了对文件数据的快速并发访问 [20, 26]。然而,在元数据管理方面,使用着与早期网络文件系统没有太大差异的策略:所有客户端元数据变更都会同步处理。它们首先被发送到服务器,由服务器进行检查和串行化,然后附加到服务器的预写日志中,最终合并到由服务器管理的文件系统的磁盘上的元数据表示中 [31, 52, 64]。

尽管这种策略未必是在大型超级计算机上处理文件元数据的最佳方式,但现代并行文件系统继续使用这种策略的一个重要原因是,它通过不断的全局同步使分布式应用程序进程能够像在本地机器上一样进行通信 [61]。但早期的网络文件系统并没有考虑到今天的大规模并行计算环境。LANL 的早期 CM-5 计算机(当时最快的计算机)有 1024 个 CPU 核心,但今天最快的计算机可能有 700 万个核心 [30, 51]。充分利用现代超级计算机的最佳方式是让其所有计算核心保持运行,所以在当今的计算系统中,并行文件系统中的全局同步正成为性能瓶颈,逐渐抵消了这些系统最初实现的并行性。

最先进技术的不足

为了获得更高的元数据性能,现代可伸缩的并行元数据服务使用多个元数据服务器上的动态命名空间分区[60, 77, 79, 82]。在这些文件系统中,每个元数据服务器管理文件系统命名空间的一个分区,整体的元数据性能取决于这些服务器的数量和计算能力。然而,动态命名空间分区并没有消除全局同步,它只是将其分割。同时,这些可扩展的文件系统可能需要大量专用的元数据服务器来实现高性能。而且,由于应用程序以不同的方式使用文件系统,很难事先确定要为文件系统分配的计算资源的数量。当应用程序的需求与估算的数量相差过多时,会导致性能瓶颈或资源的浪费。

提高性能的另一种方式是采用高效的基于日志的元数据格式,隐藏了现代并行文件系统元数据服务器的处理延迟[47, 60]。这样的系统能够迅速吸收大量客户端的更改,而无需立即对其进行快速读取的优化,用一组独立的服务器线程在后台异步执行操作,因此客户端无需被阻塞。然而,在后台进程无法跟上前台插入时,将被迫等待这些后台操作所需的时间,客户端仍然会经历延迟。

先前的研究还通过深度客户端日志记录实现的超快文件创建速度[12, 60, 85]。然而,仅使用客户端日志记录并不能解决读性能问题,也不支持作业间通信。

从通用到无全局真相

随着我们不断提高计算机的容量和并行性,并行元数据系统将无法适用于所有场景[7, 71]。尽管在应用程序使用文件系统进行通信的情况下,全局同步的高成本将继续是必要的,但今天的并行应用程序在很大程度上是非交互式的批处理作业,不一定从早期网络文件系统的许多语义中受益[31, 52, 64]。

一个现代的 HPC 应用程序首先提交到作业调度队列[75]。当被调度时,它从并行文件系统读取数据,将结果写入并行文件系统,然后结束。从作业的角度来看,它读取的输入可能在提交作业时已经准备好且静态。它生成的输出可能在作业完成之前没有被检查,除非作业拥有者尝试了解作业的进度[2, 12, 45]。这实际上是顺序数据共享。我们认为,并行文件系统可以通过发布和共享文件系统命名空间的快照来实现,而无需进行全局同步,如图1所示。为了实现这一点,我们设想运行一个公共命名空间注册表,所有作业都可以将它们的命名空间作为快照发布到该注册表。当一个作业启动时,它选择快照的子集作为输入,并以发布包含所有作业输出的新快照而结束。后续作业可以使用新的快照作为其输入,实现高效的跨作业数据传播。

在这里插入图片描述

在基于日志的文件系统元数据格式的情况,命名空间快照可以很紧凑且易于生成:每个快照只是指向一组先前执行的文件系统元数据更改的指针[58, 60, 86]。由于每个作业都引用一个快照来启动,甚至不需要全局文件系统命名空间。当一个作业需要从多个输入快照中读取数据时,它只需合并这些快照以形成一个单一的、具体化的文件系统视图,以实现快速的元数据读取性能。该作业可以在其计算节点上启动自己的文件系统元数据服务器进程来执行合并,然后提供读取服务。这使得作业能够更好地利用当今计算平台中的大规模并行性,实现可扩展的读取性能,而不受集中式元数据管理资源的限制。此外,无关的作业无需进行通信:它们只需处理不同的快照。

本文工作

我们提出了 DeltaFS,这是在现代并行计算平台上提供分布式文件系统元数据的新方法,主要提出三个优化点:

  • 如今的文件系统客户端在进行元数据读取和写入时,往往与其服务器进行过于频繁的同步。DeltaFS 通过客户端日志记录,以及根据需要对文件系统命名空间更改进行后续合并,提供了对文件系统命名空间同步和串行化的放松。

  • 如今的文件系统将所有应用作业映射到单个文件系统命名空间。DeltaFS 使作业能够自我管理其同步范围,以避免虚假共享,并将每个作业的文件系统命名空间占用最小化,以提高性能。

  • 现代文件系统主要通过在多个专用元数据服务器上进行动态命名空间分区来实现扩展 [60, 77, 79, 82]。文件系统元数据性能受到专用于这些元数据服务器的计算资源量的限制。DeltaFS 在客户端节点上动态实例化文件系统元数据处理函数,实现了对文件系统元数据性能的高度灵活的扩展,超越了一组固定的专用服务器。

DeltaFS 的核心是将全局同步的文件系统元数据转化为每个作业的元数据日志记录,这些记录可以在后续作业请求时动态合并,形成新的文件系统命名空间视图。为此,DeltaFS 定义了一种高效的基于日志的文件系统元数据格式,应用作业进程可以使用该格式记录其由于执行而导致的命名空间更改。DeltaFS 不要求将所有客户端更改合并回由服务器管理的全局树,以获取一致的文件系统视图。相反,作业可以选择性的合并先前作业生成的日志,以进行有序的数据共享。不相关的应用作业无需进行通信。

通过 DeltaFS,我们设想并行文件系统将大幅减少,变成应用程序在计算节点上独立实例化的服务。可伸缩的对象存储为每个作业的命名空间管理提供了共享的底层存储。不存在全局命名空间,相反,应用程序仅在需要时进行通信,并且通信主要通过共享和发布存储在共享底层对象存储中的不可变日志记录进行,以实现最小化同步。同时,不再需要专用的元数据服务器。使用 DeltaFS,作业可以动态利用其计算节点进行元数据处理,克服了并行文件系统元数据设计中出现的局限和瓶颈。我们将这种管理分布式文件系统元数据的新方法称为无全局真相,因为不需要全局同步。不相关的作业不需要看到彼此的文件或被彼此的命名空间更新延迟。尽管没有全局文件系统命名空间,使用 DeltaFS 的作业仍然可以通过文件系统执行作业间通信。我们展示了通过解耦和并行化元数据访问,与目前的并行文件系统相比,DeltaFS 极大地降低了元数据密集型工作流的作业间通信延迟。

我们的实验表明,DeltaFS 通过利用作业进程运行的节点上的资源,可以提高元数据性能。与当前的最先进技术相比,我们展示了高达98倍的元数据变更吞吐量,这个数字随着作业规模的增加而增加。DeltaFS 进一步实现了高效的作业间通信,通过显著减少客户端元数据变更的平均延迟,和客户端在此类操作上被阻塞的CPU时间,大大减少了整体工作流运行时间,最多可减少49倍和52倍。

系统概述

DeltaFS 包括一组库和守护进程,它们在共享的底层对象存储之上提供可扩展的并行文件系统元数据访问。如图2所示,DeltaFS 的主要组件包括用户作业、压缩器和命名空间注册表。运行在每个用户作业中的 DeltaFS 库代码充当 DeltaFS 元数据服务器和客户端。压缩器是用户调度的 DeltaFS 日志压实代码,用于重新组织给定子集的 DeltaFS 元数据,以便能够快速访问。命名空间注册表是长时间运行的守护程序,使用户能够高效地跟踪和发现可用的 DeltaFS 命名空间快照。所有 DeltaFS 数据和元数据都以长期存储的方式存储在共享的底层对象存储中 [13,49,78]。

在这里插入图片描述

用户作业

作业是被提交到计算节点上运行的并行程序或脚本 [45]。DeltaFS 中的作业充当其自己文件系统元数据的管理器,每个作业都通过自我定义其文件系统命名空间开始。这是通过查找并合并由之前作业发布的命名空间快照来完成的。然后,该作业实例化 DeltaFS 客户端和服务器实例以服务该命名空间。在作业结束时,它可以将其命名空间释放为一个公共快照,可被其他作业搜索和合并。

一个作业在其计算节点上实例化 DeltaFS 客户端和服务器实例。一个作业可能有许多进程(例如,并行模拟)。这些进程中的每一个都可以充当客户端,也可以充当服务器,链入到它们中的 DeltaFS 库代码能够同时具备这两种角色。并非所有的进程都需要充当服务器。

客户端和服务器之间的通信通过远程过程调用(RPC)进行 [14, 69]。在每个作业开始时通过引导机制 [28, 63] 将服务器地址发送给客户端。当这些地址需要被作业之外的代码(例如,作业所有者的监控工具)知道时,可以发布在外部的协调服务 [16, 34, 41] 上以供公共查询。

当一组相关的作业形成一个工作流并连续运行时(例如,模拟+数据处理+数据分析),可以使用单个 DeltaFS 实例(由作业实例化的所有 DeltaFS 客户端和服务器的集合)来为整个工作流提供服务,以提高性能。这样在工作流内部无需重复发布和搜索文件系统命名空间快照,并且无需反复从空的文件系统元数据缓存启动。为实现这一点,工作流管理器(或作业脚本)在计算节点上生成 DeltaFS 服务器作为独立的进程(不嵌入在作业进程中)。这些独立服务器的存活时间可以超过工作流中的每个单独步骤的存活时间,并且可以被这些步骤重复使用,以实现高效的元数据访问。当工作流的最后一步完成时,工作流管理器关闭服务器。

在作业中,应用程序代码通过 DeltaFS 库调用与 DeltaFS 进行交互。DeltaFS 处理所有的元数据变更,例如创建新文件、设置权限和删除目录。数据操作被重定向到底层对象存储以进行可伸缩的处理。对于新创建的文件,通过透明地将其条带化到多个数据对象来进行单个文件内的并行数据操作。当写入文件时,其某些属性(如文件大小和上次访问时间)相对于 DeltaFS 的属性副本可能会发生变化。DeltaFS 利用其元数据路径在文件关闭时捕获这些更改。

为了获得更高的元数据性能,DeltaFS 通过积极分割命名空间以实现快速读取,使用客户端日志快速吸收大量写入,并将元数据打包在大型日志对象(SSTable)中,存储到共享底层对象存储,以实现高效的存储访问。

命名空间注册表

注册表是所有已发布的 DeltaFS 命名空间快照的保管者。每个注册表可以被看作是一个简单的键值(KV)表,将快照名称(K)映射到存储在共享底层对象存储中的快照清单对象的指针(V)。

如图3所示,每个 DeltaFS 命名空间快照由存储为 SSTables 的元数据变更日志组成。清单是插入到快照中以充当其根索引的特殊元数据对象,它包含快照的所有成员日志(SSTables)的名称以及每个日志的键范围。DeltaFS 元数据读取路径代码使用此信息来定位快照数据,并加速对它的查询。

在这里插入图片描述

在 DeltaFS 中,不相关的作业无需进行通信。相关的作业可以使用 DeltaFS 进行有效的顺序数据共享,前面的作业将其命名空间发布为快照,后续作业在以后的某个时间点查找快照。要将命名空间发布为快照,作业将其内存中的状态刷新到存储中,写入清单,然后将清单的对象名称和快照的名称发送到注册表。要读取快照,作业向注册表发送快照的名称,以获取快照清单对象的名称,然后读取清单对象并将其用于对快照的查询。

在 DeltaFS 中,作业提供命名空间快照名称,DeltaFS 执行唯一性检查。类似的,DeltaFS 作业必须知道快照的名称才能在注册表中查找。为了获取文件名,DeltaFS 允许作业根据前缀字符串列出快照(快照名称按有序字符串进行索引)。为了在快照列表之外进行查询,DeltaFS 注册表与副索引配对,其中快照按照名称以外的属性进行索引(例如,所有者 ID、创建时间、快照内的文件名),如图 3 所示。现代数据库技术可以实现这一点,并允许进行类似 SQL 的查询。

注册表守护程序运行在计算集群中的专用服务器节点上。一个集群可以有一个或多个注册表,使用多个注册表时,每个注册表管理快照 Key 的一个分区。注册表的专用服务器不会位于常规文件系统元数据变更的关键路径上,即使对于元数据密集型的工作负载,注册表的性能对于 DeltaFS 的整体元数据性能也不太关键。对于像快照发布这样的写操作,我们预计注册表的繁忙程度不会超过作业调度队列。为了给快照查询和用户在登录节点上调用 DeltaFS 命令(例如 DeltaFS-snap-list 和 DeltaFS-snap-info)等操作提供低延迟的交互式读访问,DeltaFS 注册表可以使用常用技术进行扩展,如更大的内存、复制和增加注册表的数量(将key划分的更细)。

压缩器(Compaction Runners)

压缩器是由用户(即不是由 DeltaFS 启动)动态启动的并行日志压缩作业,运行在计算节点上。用于对一个或多个先前作业生成的元数据突变日志(SSTables)进行合并和重新分区,形成一个紧凑的、针对读取进行优化的文件系统命名空间视图,以便后续作业进行高效的查询。能够根据需要在大量客户端计算核心上显式调度压缩是 DeltaFS 与当今并行文件系统不同之处之一。在现有系统中,全局文件系统元数据由专用服务器节点上的系统进程维护,适用于所有作业,导致服务器在元数据密集工作负载下经常无法跟上客户端的速度。为了运行并行压缩,用户提交一个特殊的 DeltaFS 程序(DeltaFS-compaction-runner)到作业调度队列,并等待它在计算节点上启动。

无全局真相

DeltaFS 不向用户提供全局文件系统命名空间。它将每个作业生成的元数据变更,记录为共享底层对象存储中的不可变日志,随后的作业独立使用这些日志构建自己的文件系统命名空间。DeltaFS 不对日志强制实施全局排序,也不要求合并所有的日志。使作业能够自定义其命名空间的一致性,避免了在大型计算集群中不必要的同步。每个作业占用较小的文件系统元数据,有助于提高整体元数据性能。

日志结构文件系统

在 DeltaFS 中,文件系统元数据信息被持久化为日志。元数据写入操作,如 mkdir 和 chmod,通过将新的日志条目写入存储来实现更改。元数据读取操作,如 lstat,通过搜索和读取存储中的相关日志条目来获取文件信息。链接到每个作业进程中的 DeltaFS 库代码了解日志格式,由一个作业编写的日志可以被所有作业理解,从而实现跨作业的通信。

DeltaFS 作业不假设全局文件系统命名空间,而是通过定义一个私有于该作业的基本命名空间来开始。在最简单的情况下,作业从空的基本命名空间开始,并以记录了作业在该基本命名空间上执行的所有文件系统元数据变更的日志结束。在需要访问前一个作业的数据输出时,作业在实例化其基本命名空间时使用前一个作业生成的日志,这允许作业在其私有文件系统命名空间视图中,包含前一个作业创建的所有文件和目录。随着作业的执行,它以新的日志条目的形式记录所有的元数据变更,并可以在作业结束时将它们发布出去。发布的日志条目可以由后续的作业用于它们的命名空间实例化,实现了高效的作业间数据传播。

当作业生成的日志条目发布时,这些发布的日志条目被称为变更集,它代表了作业在其基本命名空间上执行的所有文件系统元数据变更的总和(跨所有其进程)。在日志发布时作业命名空间的状态,即后续作业将继承的状态,被称为快照。每个 DeltaFS 作业可以看作是一个大的日志追加操作:它将一个变更集(一组文件系统元数据变更)附加到一个快照上,并生成一个新的快照,如图 4 所示。同时,每个 DeltaFS 快照实际上可以看作是一个根据变更集组成的有向无环图(DAG)。DAG 的根是作业在生成新的快照时追加的变更集。我们将这个特殊的变更集称为快照的根变更集,其清单不仅代表根变更集本身,还代表它所包含的整个快照(整个变更集 DAG)。

在这里插入图片描述

多继承和名称解析

当 DeltaFS 作业实例化其基础时,它可能使用多个输入快照。为了在作业内实现一致性,作业为其所有输入快照指定了优先级排序,使得优先级较高的快照的记录优先。图 5 显示了一个示例,其中作业 A、B、C 和 D 分别以 0、1 或多个先前作业的快照作为输入,附加一个新变更集,并生成一个新快照作为输出。作业 A 以 null 作为输入,生成变更集 a,并生成快照 A。作业 B 以作业 A 的输出快照作为输入,附加变更集 b,并生成快照 B。作业 C 以作业 A 的输出快照作为输入,附加变更集 c,并生成快照 C。作业 D 以作业 B 和作业 C 的输出快照作为输入,附加变更集 d,并生成快照 D。虽然作业 B 和 C 都在其各自的快照中创建了 “/p/y”,但由于 D 中 B 的优先级高于 C,D 将看到由 B 中创建的 “/p/y”,而不是 C 中创建的 “/p/y”。

在这里插入图片描述

自定义客户端文件系统命名空间视图也可以在 UnionFS [81] 和 OverlayFS [1] 等系统中找到。DeltaFS 与它们的不同之处在于,在计算节点上根据需要动态调用的并行整理机制,它允许有效地实现复杂的客户端命名空间视图的快速读取。同时,DeltaFS 的日志结构的元数据格式,能够有效地记录客户端元数据变化,而不受写时复制和其它叠加文件系统技术的限制。作为并行文件系统,DeltaFS 能够将工作负载分布到分布式作业进程中以实现扩展,而本地叠加文件系统的性能在本地机器的容量范围内基本上是有限的。

复杂性

尽管 DeltaFS 作业的集合可能会生成复杂的 DAG 输出快照,但用户在初始化新作业时只需指定和排序直接依赖项(即直接输入快照),可以通过 DeltaFS 命令行参数完成。间接依赖项在作业启动时由 DeltaFS 自动解析和排序,类似于 Linux 对共享库的动态加载。DeltaFS 通过读取和跟踪与每个发布的变更集相关联的清单对象来解析依赖项。

需要指定输入快照和命名输出快照的需求,并不改变人们运行作业的方式,即使使用全局命名空间,用户在启动作业时也需要知道并指定作业的输入和输出路径。此外,全局命名空间很少是真正全局的:通常将存储划分为多个文件系统(例如 scratch、NFS home),导致存在许多独立的命名空间。尽管最近的工作利用数据库技术创建了一个横跨多个文件系统的大一统文件索引 [44],DeltaFS 可以与类似的文件索引配对,其中所有已发布的作业快照都被索引,使用户能够更轻松地定位其文件。我们还设想在 DeltaFS 之上构建一个高级软件堆栈(例如 DeltaFS-Orchestra),该堆栈能够自动执行每个作业的命名空间实例化以及跨作业的数据传播和压缩,从而使 DeltaFS 更易于使用。

之前作业的日志管理

DeltaFS 作业将元数据变更记录为存储上的日志。为了实现高性能,DeltaFS 将每个文件系统元数据变更都被记录为 LSM 树 [53] 中的表的键值对。树数据被持久化为命名的 SSTables[27],由每个作业变更集中的清单对象索引。后台日志整理改善了日志存储以实现快速读取,并处理垃圾回收。

日志格式

DeltaFS 为每个文件系统元数据变更记录一个键值对。键存储涉及变更的文件的名称,值存储变更后文件的元数据信息(即 inode)。每个键中有一个特殊的删除位,用于指示记录的变更是否删除。每个键都有一个序列号吗,具有更高序列号的键会取代较低序列号的键,使新的变更覆盖旧的变更。所有键都被插入到使用高性能 DeltaFS 修改的 LevelDB 实现的 LSM-Tree [53] 的每个作业表中。

如图6所示,我们使用父目录 ID 和文件基本名称来表示文件名。使用父目录 ID 作为键前缀(而不是它们的完整路径名),使 DeltaFS 避免在用户重命名文件的父目录时更新文件的键 [15, 82]。我们存储每个文件的元数据信息,包括文件 ID、文件类型、用于层次访问控制的文件权限、小文件的文件数据 [60]。DeltaFS 键是有序的,允许高效地进行文件系统元数据查找和目录扫描 [47, 58]。

在这里插入图片描述

存储日志管理

DeltaFS 使用 LSM 树 [53] 来管理每个作业变更集内的文件系统元数据变更。如图7所示。为变更集初始化 LSM 树时,作业首先在底层对象存储中创建一个清单对象,记录有关变更集的高级信息,包括变更集名称以及所有作业输入快照的根变更集的名称。接下来,在作业的进程中分配一个内存缓冲区空间,用于缓冲作业运行时生成的元数据变更,这些变更被格式化为 KV 对。每当内存写入缓冲区已满时,缓冲区中的所有 KV 对将被按序写入 SSTable [27] 进行存储。然后,在清单中记录 SSTable 的名称以及表的键范围,以供后续查询使用。为防止数据丢失,为作业进程的内存写入缓冲区故障恢复创建一个预写式日志,将 KV 对插入内存缓冲区之前,首先将其记录在预写式日志中。清单、预写式日志以及清单中列出的 SSTable 组成了变更集的整个状态。

在这里插入图片描述

更改集在不再使用时可以被删除。用户通过调用特殊的 DeltaFS 程序(DeltaFS-changeset-delete),使用更改集的名称作为参数来删除更改集。为了防止在其他更改集仍依赖它时删除更改集,DeltaFS 使每个更改集都保持对自身和每个依赖项的引用。当用户删除更改集时,它对自身的引用将被删除。当没有其他更改集对其有引用时,该集合的所有成员对象将被删除,包括清单、预写日志和所有 SSTable。当删除更改集时,其对其他更改集的引用都将被删除。当删除更改集时,DeltaFS 会从注册表中注销相应的快照。对于大文件,它们的数据对象也是引用计数的。当所有引用该数据对象的SSTable和预写日志都被删除时,数据对象将被删除。DeltaFS 提供了一个实用的程序(DeltaFS-changeset-clean),用户可以定期运行以删除不被引用的更改集。

日志压缩

当作业运行时,DeltaFS 会在其内存写缓冲区已满时写入 SSTable 以持久保存更改。这些 SSTable 中的条目可能是作业内存中的 LRU 替换候选项,并且可以通过查询存储中的 SSTable 重新加载。SSTable 是从最新到最旧的顺序进行查询的。随着 SSTable 数量的增加,找到记录的成本随之而增加。为了提高读取性能,DeltaFS 运行压缩以合并排序重叠的 SSTable,并减少共享键的 SSTable 数量。随着 SSTable 的合并,将生成新的 SSTable 并删除旧的 SSTable,随后删除不再被任何 SSTable 引用的数据对象。

图 8 显示了一个示例,其中 SSTable 2 和 3 被压缩成 SSTable 4。在压缩之前,查找键 /c 将需要搜索两个 SSTables。首先搜索 SSTable 3,因为其键范围 [/a-/e] 与键 /c 重叠。由于 SSTable 3 没有该键,接下来搜索 SSTable 2(在这里将找到该键)。压缩后,可以通过单个 SSTable 查找键 /c,从而提高读取性能。当合并表时,相同文件名前缀的记录会被合并,只将最高序列号的记录复制到新表中。在合并表后,新表的信息被记录在清单中,并丢弃对旧表的引用,旧表与其对文件数据对象的引用一起从底层存储中删除,从而使它们也能够进行垃圾回收。

在这里插入图片描述

动态服务实例化

DeltaFS 文件系统没有专用的元数据服务器。相反,作业在作业的进程中动态实例化 DeltaFS 客户端和服务器实例,以提供私有于该作业的并行文件系统元数据访问。DeltaFS 积极地在作业的服务器之间分割命名空间,以实现可扩展的读取性能,并使用客户端日志记录快速吸收突发写入。

每个作业的元数据处理

在作业内部,客户端通过向服务器发送 RPC 执行元数据操作。写操作通过使用构成作业变更集的 LSM-Tree,将元数据变更记录到存储中。读操作首先查询作业自己的变更集,如果在作业的变更集中找不到所需的元数据,则使用用户定义的优先级顺序查询依赖的变更集。服务器在作业执行过程中异步执行日志压缩。

当一个作业实例化多个DeltaFS服务器时,每个服务器管理作业私有文件系统命名空间视图的一个分区。DeltaFS使用从GIGA+ [55, 60] 派生的命名空间分区方案,其中每个新创建的目录被随机分配给一个服务器,并在其增长过程中逐渐分区到更多的服务器。每个服务器的元数据变更被记录到它们自己独立的 LSM-Tree 作业变更集中。每个 LSM-Tree 表示一个分区,并由专用的清单对象索引。第0个分区的清单对象另外充当整个变更集的清单,并被注册表在它们的映射表中引用。

客户端日志记录

DeltaFS 在并行作业中的不同客户端和服务器相互同步,确保一个进程创建的文件立即对该作业中的所有进程可见。对于工作负载(例如,N-N检查点)的文件允许每个进程的写入[12, 13],DeltaFS 允许客户端推迟整个作业范围的同步,并直接将元数据变更记录到每个客户端的 LSM-Tree 中,以实现超高的元数据写入性能。客户端可以对其私有 LSM-Tree 执行后台日志压缩,以提高读性能。当客户端创建的文件是只写且在作业完成后才会被读取时,DeltaFS 客户端可以选择进一步推迟其日志压缩,并随后使用一个并行的日志压缩程序将所有作业客户端的 LSM-Tree 合并和重新分区,以单个大批次进行合并。

命名空间整理

当一个作业在每个进程的日志中记录其变更以获得超高写性能时,与这些变更无关的读请求仍然可以通过作业的 DeltaFS 服务器进行服务,根据作业命名空间的分区进行。当作业的计算核心不足以处理手头的工作负载时,它可以分配一个单独的更大的计算节点集来运行 DeltaFS 服务器,利用这些节点上的计算核心和内存来扩展读取,并实现对存储中作业元数据的低延迟访问。这些单独分配的 DeltaFS 服务器可以由工作负载、项目、活动 [45] 中的多个作业重复使用。活动管理者可以请求持久分配一组计算节点,以便在较长时间内运行 DeltaFS 服务器。我们称之为只读、特定于作业、能长时间运行的 DeltaFS 命名空间管理器。这些管理器进程可用的计算资源量不是由集群管理员决定的,而是由作业、项目或活动的所有者决定,以实现可扩展的文件系统元数据读取性能。

容错、老化和顺序数据共享

为了避免计算节点故障,在执行文件系统元数据变更时,DeltaFS 执行预写式日志记录。所有 DeltaFS 的预写日志、文件数据和文件系统元数据,都存储在共享的底层对象存储中,以便在作业故障时从不同的计算节点集合进行故障恢复。预写式日志每5秒刷新一次(此周期可配置),并在调用 fsync 时刷新。

所有文件系统都会老化。DeltaFS 通过显式的跨作业压缩,以及不将所有文件耦合到单个命名空间中,以提高并行性和缓存性能,能够更平稳地老化。在注册表中拥有数百万个快照是可以接受的,现代硬件上的最新 KV 存储通常可以每秒执行数百万次操作(op/s)。通过 DeltaFS,快照的总数将比文件的总数小几个数量级(即使文件可能积累许多元数据变更日志条目,快照始终是每个作业的)。与当今的并行文件系统相比,这显著减少了中央元数据服务器(或 DeltaFS 中的快照注册表)处理的键的总数。

在 DeltaFS 中,如果作业 X 使用一个快照并在重写了文件,同时作业 Y 使用相同的快照时,作业 Y 将看到旧的文件数据。这是因为 DeltaFS 允许不同的快照中存在文件的多个版本,而支持写时复制的对象存储将有效地实现这一点。如果作业 Y 想要看到作业 X 的更改,作业 Y 可以等待作业 X 发布其更改,然后使用作业 X 产生的快照。这被称为顺序数据共享,DeltaFS 也支持这种模式。

跨作业的并行日志压缩

所有日志结构文件系统都需要压缩来实现良好的读性能 [58, 59, 62]。而当今的并行文件系统将压缩限制在专用的元数据服务器上,DeltaFS 允许用户在计算节点上动态启动压缩,这可以利用潜在的大量计算核心来加速压实操作。同时,由于用户只在已知会被后续读取的作业变更集上调度压缩,可以将每次压缩的数据占用最小化,进一步减少压缩延迟。

与每个作业内的日志压缩不同,跨作业的日志压缩是由用户单独调用的。用户启动特殊的并行日志压缩程序,该程序将一组相关的作业变更集在单个批次中合并和重新分区。用户启动跨作业压缩有几种原因:为高效的查询展开复杂的作业变更集层次结构;对作业变更集中的大量 SSTable 进行并行排序,以实现快速查找;现有的变更集或变更集层次包含的分区太少,导致在后续作业进程之间无法实现负载平衡。

DeltaFS 使用可扩展的并行归并排序管道进行跨作业的日志压缩。每个管道充当输入 SSTable 的子集的映射器,同时作为负责目标变更集的分区的约简器。图9显示了一个示例,其中由变更集 a、b、c 的 DAG 组成的快照 C,其中 c 是根,被并行压缩以形成快照 D。在并行压缩之前,从快照 C 读取键可能需要搜索变更集 a、b、c 的分区。压缩后,每个键查找仅需要搜索变更集 d 的一个分区,显著减少了查询开销。变更集a、b、c 最初由生成它们的作业进行了分区,压缩后变更集 d 扩展为具有8个分区。具有8个进程的作业可以将分区分配给它的每个进程的服务器,完全平衡它们的读操作。

在这里插入图片描述

实验

我们用 C++ 实现了 DeltaFS 的原型。使用了模块化设计,使得 DeltaFS 可以分层在不同的对象存储后端之上。

实验评估了 DeltaFS 在单个应用程序作业和多个作业共享单个计算集群时的性能。测试了作业间相关,并使用文件系统进行顺序数据共享的情况,以及作业不相关且互不读取文件的情况。

我们将 DeltaFS 与当前最先进的方法进行比较:IndexFS[60] 用于可扩展的并行元数据,PLFS[12] 基于客户端的元数据日志记录。我们还比较了一种特殊的 IndexFS 模式,该模式允许客户端记录元数据变更,以便稍后进行批量插入。

单个应用程序作业

环境:使用卡内基梅隆大学的并行数据实验室的 Susitna 集群进行这些测试。每个 Susitna 计算节点有四个16核 AMD Opteron 6272 2.1GHz CPU、128 GB 内存、一个 40GbE NIC 和 一个 1GbE NIC。共分配了十个节点,八个作为客户端节点(512个 CPU 核心),两个作为专用元数据服务器(用于 IndexFS)。我们使用 40GbE 网络进行文件系统操作,使用 1GbE 网络访问共享的底层 RADOS 存储。

DeltaFS 吞吐量高。

【后面说 DeltaFS 使用的计算资源是 IndexFS 的2倍,蓝色和粉色线比较才是公平的】

在这里插入图片描述

先写后读的实验,DeltaFS 增加了元数据并行压缩的步骤,相当于重新整理了一下元数据分布,性能更高。

在这里插入图片描述

多个应用程序作业

环境:在 CMU 的 PDL Narwhal 集群进行测试。每个 Narwhal 计算节点有4个双核 AMD Opteron 2210 1.8GHz CPU、16GB 内存和两个 1GbE NIC。我们使用一个 NIC 进行文件系统操作,另一个用于访问共享的底层 RADOS。最多分配了128个节点来运行工作流作业。

DeltaFS 运行流程,多次从之前快照开始,写入新文件并生成新快照。

在这里插入图片描述

DeltaFS 性能更高,相同计算资源时还是 DeltaFS 性能更高。

测试了元数据服务器的计算资源使用情况,DeltaFS 是 IndexFS 的2倍。但作者说因为 IndexFS 性能不高, 作业需要等待,于是浪费了客户端的资源,图12b虚线。

在这里插入图片描述

总结

针对 HPC 应用的全局元数据管理开销过高,提出无全局同步的元数据设计方法。作者提出几个优化点:使用客户端日志记录和快照的方法,避免全局同步;每个作业根据需要使用部分命名空间,减少同步范围;将元数据服务端运行到作业计算节点,便于灵活扩展;通过用户启动的并行压缩,将 SSTable 合并,加快后续读取性能。

开源代码:https://github.com/zhengqmark/deltafs

局限性:实验有点少。本文方法可能增加了用户使用的复杂度,使用多个快照存在版本冲突时需要用户指定优先级,需要用户自己操作并行合并来增加后续读取的性能。

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妙BOOK言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值