关于分布式:从两个模型带你了解DAOS-分布式异步对象存储

57次阅读

共计 8499 个字符,预计需要花费 22 分钟才能阅读完成。

摘要: 分布式异步对象存储 (DAOS) 是一个开源的对象存储系统,专为大规模分布式非易失性内存 (NVM, Non-Volatile Memory) 设计,利用了 SCM(Storage-Class Memory) 和 NVMe(Non-Volatile Memory express) 等的下一代 NVM 技术。

本文分享自华为云社区《DAOS 分布式异步对象存储》,原文作者:debugzhang。

分布式异步对象存储 (DAOS) 是一个开源的对象存储系统,专为大规模分布式非易失性内存 (NVM, Non-Volatile Memory) 设计,利用了 SCM(Storage-Class Memory) 和 NVMe(Non-Volatile Memory express) 等的下一代 NVM 技术。

DAOS 是一种横向扩大的对象存储,能够为高性能计算利用提供高带宽、低提早和高 IOPS 的存储容器,并反对联合仿真、数据分析和机器学习的下一代以数据为核心的工作流程。

与次要针对旋转介质设计的传统存储堆栈不同,DAOS 针对全新 NVM 技术进行了从新构建,可在用户空间中端对端地运行,并能齐全绕开操作系统,是一套轻量级的零碎。

DAOS 提供了一种为拜访高细粒度数据提供原生反对的 I/O 模型,而不是传统的基于高提早和块存储设计的 I/O 模型,从而开释下一代存储技术的性能。

与传统的缓冲区不同,DAOS 是一个独立的高性能容错存储层,它不依赖其它层来治理元数据并提供数据恢复能力。DAOS 服务器将其元数据保留在长久内存中,而将批量数据间接保留在 NVMe 固态盘中。

DAOS 个性

DAOS 依附 OFI(OpenFabric Interface) 绕过操作系统,将 DAOS 操作交付给 DAOS 存储服务器,充分利用架构中的任何近程间接内存拜访 (RDMA, Remote Direct Memory Access) 性能,进行低提早、高音讯速率的用户空间通信,并将数据存储在长久内存和 NVMe 固态盘中。

DAOS 的键值存储接口提供了对立的存储模型,通过迁徙 I/O 中间件库实现对 DAOS API 的原生反对后,就能利用 DAOS 丰盛的 API 和先进性能,例如 HDF5、MPI-IO 和 Apache Arrow。

DAOS 还提供 POSIX 的仿真。POSIX 不再是新数据模型的根底,而是像其余 I/O 中间件一样,POSIX 接口将构建为 DAOS 后端 API 顶部的库。

DAOS 的 I/O 操作会被记录并存储到 SCM 保护到长久索引中,每次 I/O 都用一个特定工夫戳标记,并与数据集的特定版本关联。外部不执行读 - 批改 - 写 (read-modify-write) 操作,写入操作是无损的,对对齐不敏感。在读取申请时,DAOS 服务器遍历长久索引,创立聚合 RDMA 描述符,从而间接在应用程序提供的缓冲区中重建所申请的版本的数据。

SCM 间接映射到 DAOS 服务地址空间的内存,DAOS 服务通过间接加载 / 存储来治理长久索引。依据不同 I/O 的个性,DAOS 服务能够决定将 I/O 存储在 SCM 或 NVMe 中:

  • 对提早敏感的 I /O(如应用程序元数据和字节粒度数据)通常存储在 SCM 中;
  • 检查点和批量数据存储在 NVMe 中。

这种办法容许 DAOS 将数据流式传输到 NVMe 中,并在 SCM 中保护外部元数据索引,为批量数据提供原始 NVMe 带宽。长久内存开发工具包 PMDK 治理对 SCM 的事务性拜访,存储性能开发工具包 SPDK 对 NVMe 设施进行用户空间 I/O 操作。

DAOS 能够提供:

  • 超高细粒度、低提早和真正零拷贝的 I/O
  • 非阻塞型数据和元数据操作,以反对 I/O 和计算重叠
  • 先进的数据搁置,以解决故障域
  • 由软件治理冗余,可通过在线重建,反对复制和擦除代码
  • 端到端 (E2E) 数据完整性
  • 可扩大的分布式事务,提供牢靠的数据一致性和主动复原性能
  • 数据集快照性能
  • 平安框架,用于治理存储池的访问控制
  • 软件定义存储管理,用于调配、配置、批改和监控存储池
  • 通过 DAOS 数据模型和 API,为 I/O 中间件库(例如 HDF5、MPI-IO 和 POSIX)提供原生反对。利用无需移植代码,即可间接应用 DAOS API
  • Apache Spark 集成
  • 应用公布 / 订阅 API,实现原生生产者 / 消费者工作流程
  • 数据索引和查问性能
  • 存储内计算,以缩小存储和计算节点之间的数据挪动
  • 容灾工具
  • 与 Lustre 并行文件系统无缝集成,并能扩大到其余并行文件系统,从而为跨多个存储层的数据拜访提供对立的命名空间
  • 数据搬运器,用于在 DAOS 池之间迁徙数据集,将数据集从并行文件系统迁徙到 DAOS,反之亦然

DAOS 组件

一个数据中心可能有数十万个计算节点,通过一个可伸缩的高性能构造相互连接,其中所有节点或称为存储节点的节点子集都能够间接拜访 NVM 存储。

DAOS 装置波及几个能够集中或分布式的组件。

DAOS 零碎和存储节点

DAOS 零碎由一个零碎名标识,它由一组连贯到同一构造的 DAOS 存储节点组成。DAOS 存储节点为每个节点运行一个 DAOS 服务实例,该实例为每个物理套接字启动一个 DAOS I/O 引擎过程。这些 DAOS 服务的信息被记录到零碎映射中,该映射为每个 I/O 引擎过程调配一个惟一的整数秩。两个不同的 DAOS 零碎由两组不相交的 DAOS 服务器组成,它们之间无奈相互配合。

DAOS 服务

DAOS 服务是一个多租户守护过程,运行在每个存储节点的 Linux 实例上(物理节点、虚拟机或容器)。服务的 I/O 引擎子过程通过网络导出本地连接的 SCM 和 NVM 存储。服务监听一个治理端口(由 IP 地址和 TCP 端口号寻址),以及一个或多个构造端点(由网络 URI 寻址)。

DAOS 服务通过 /etc/DAOS 中的 YAML 文件进行配置,包含其 I/O 引擎子过程的配置。服务的启动能够与不同的守护过程治理或编排框架集成(systemd 脚本、Kubernetes 服务、或相似 pdsh 和 srun 的并行启动程序)。

I/ O 引擎

在 DAOS I/O 引擎中,存储动态地逾越多个 Target 分区,加强并发能力。为了防止竞争,每个 Target 都有其公有存储、本人的服务线程池以及专用的网络上下文,这些上下文能够间接通过构造寻址,而不依赖于托管在同一存储节点上的其余 Target。

SCM 模块通常以 AppDirect interleaved 模式配置。因而,它们作为每个套接字(在 fsdax 模式)的单个 PMEM 命名空间出现给操作系统。当配置每个 I/O 引擎的 N 个 Target 时,每个 Target 都应用该套接字 fsdax 的 SCM 容量的 frac{1}{N}_N_1​,与其它 Target 独立。每个 Target 还应用连贯到此套接字的 NVMe 驱动器容量的一小部分。

Target

Target 没有针对存储介质故障实现任何外部数据保护机制。因而,一个 Target 就是一个单点故障,同时也是故障单元。动静状态与每个 Target 相关联:其状态能够是“up and running”,也能够是“down and not available”。

Target 是性能的单位。与 Target 关联的硬件组件(如后端存储介质、CPU 外围和网络)的能力和容量无限。

DAOS I/O 引擎实例导出的 Target 数是可配置的,取决于底层硬件(I/O 引擎实例的 SCM 模块数和 NVMe SSD 数)。I/O 引擎的 Target 数的最佳配置是该 I/O 引擎服务的 NVMe 驱动器数的整数倍。

存储 API、利用程序接口和工具

应用程序、用户和管理员能够通过两个不同的客户端 API 与 DAOS 零碎交互。

治理 API 提供了治理 DAOS 零碎的接口。它旨在与不同供应商的存储管理或开源编排框架集成。dmg 命令行工具是在 DAOS 的治理 API 上构建的。

DAOS 库 libdaos 实现了 DAOS 存储模型,次要提供给心愿在 DAOS 零碎中存储数据集的应用程序和 I/O 中间件的开发人员。用户罕用的 daos 命令等的也构建在 API 之上,容许用户通过命令行治理数据集。

应用程序能够通过本机 DAOS API、I/O 中间件库(如 POSIX 仿真、MPI-IO、HDF5)或已与本机 DAOS 存储模型集成的 Spark 或 TensorFlow 等框架间接拜访存储在 DAOS 中的数据集。

代理

DAOS 代理是驻留在客户端节点上的守护过程,通过与 DAOS 库交互验证应用程序过程。它是一个可信赖的实体,反对应用证书对 DAOS 客户端进行签名。DAOS 代理反对不同的身份验证框架,并应用 Unix 域套接字与客户端库通信。

存储模型

DAOS Pool 是散布在 Target 汇合上的存储资源预留。调配给每个 Target 上的 Pool 的理论空间称为 Pool Shard。

调配给 Pool 的总空间在创立时确定,前期能够通过调整所有 Pool Shard 的大小(在每个 Target 专用的存储容量限度内)或逾越更多 Target(增加更多 Pool Shard)来随工夫扩大。

Pool 提供了存储虚拟化,是资源调配和隔离的单元。DAOS Pool 不能跨多个零碎。

一个 Pool 能够承载多个称为 DAOS Container 的事务对象存储。每个 Container 都是一个公有的对象地址空间,能够对其进行事务性批改,并且独立于存储在同一 Pool 中的其余 Container。Container 是快照和数据管理的单元。属于 Container 的 DAOS 对象能够散布在以后 Pool 的任何一个 Target 上以进步性能和恢复能力,并且能够通过不同的 API 拜访,从而高效地示意结构化、半结构化和非结构化数据。

下表显示了每个 DAOS 概念的指标可伸缩性级别:

DAOS Pool

Pool 由惟一的 Pool UUID 标识,并在称为 Pool 映射的长久版本控制列表中保护 Target 成员身份。成员资格是确定的和统一的,成员资格的变更是按程序编号的。Pool 映射不仅记录沉闷 Target 的列表,还以树的模式蕴含存储拓扑,用于标识共享公共硬件组件的 Target。例如,树的第一级能够示意共享同一主板的 Target,第二级能够示意共享同一机架的所有主板,最初第三级能够示意同一机房中的所有机架。

该框架无效地示意了层次化的容错域,而后应用这些容错域来防止将冗余数据搁置在产生相干故障的 Target 上。在任何时候,都能够将新 Target 增加到 Pool 映射中,并且能够排除失败的 Target。此外,Pool 映射是齐全版本化的,这无效地为映射的每次批改调配了惟一的序列,特地是对于失败节点的删除。

Pool Shard 是永恒内存的预留,能够抉择与特定 Target 上 NVMe 事后调配的空间相结合。它有一个固定的容量,满了就不能运行。能够随时查问以后空间应用状况,并报告 Pool Shard 中存储的任何数据类型所应用的总字节数。

一旦 Target 失败并从 Pool 映射中排除,Pool 中的数据冗余将主动在线复原。这种自愈过程称为重建。重建进度定期记录在永恒内存中存储的 Pool 中的非凡日志中,以解决级联故障。增加新 Target 时,数据会主动迁徙到新增加的 Target,以便在所有成员之间平均分配占用的空间。这个过程称为空间再均衡,应用专用的持久性日志来反对中断和重启。

Pool 是散布在不同存储节点上的一组 Target,在这些节点上散布数据和元数据以实现程度可伸缩性,并应用复制或纠删码 (erasure code) 确保持久性和可用性。

创立 Pool 时,必须定义一组零碎属性以配置 Pool 反对的不同性能。此外,用户还能够定义将长久存储的属性。

Pool 只能由通过身份验证和受权的应用程序拜访。DAOS 反对多种平安框架,例如 NFSv4 访问控制列表或基于第三方的身份验证 (Kerberos)。连贯到 Pool 时强制执行安全性查看。胜利连贯到 Pool 后,将向应用程序过程返回连贯上下文。

如前文所述,Pool 存储许多不同品种的持久性元数据,如 Pool 映射、身份验证和受权信息、用户属性、个性和重建日志。这些元数据十分要害,须要最高级别的恢复能力。因而,Pool 的元数据被复制到几个来自不同高级容错域的节点上。对于具备数十万个存储节点的十分大的配置来说,这些节点中只有很小的一部分(大概几十个)运行 Pool 元数据服务。在存储节点数量无限的状况下,DAOS 能够依赖一致性算法来达成统一,在呈现故障时保障一致性,防止脑裂。

要拜访 Pool,用户过程应该连贯到 Pool 并通过安全检查。一旦受权,Pool 就能够与任何或所有对等应用程序过程(相似 openg() POSIX 扩大)共享(通过 local2global() 和 global2local() 操作)连贯。这种个体连贯机制有助于在数据中心上运行大规模分布式作业时防止元数据申请风暴。当收回连贯申请的原始过程与 Pool 断开连接时,Pool 连贯将被登记。

DAOS Container

Container 代表 Pool 中的对象地址空间,由 Container UUID 标识。

下图显示了用户(I/O 中间件、特定畛域的数据格式、大数据或 AI 框架等)如何应用 Container 来存储相干数据集:

与 Pool 一样,Container 能够存储用户属性。Container 在创立时必须传递一组属性,以配置不同的性能,例如校验和。

要拜访 Container,应用程序必须首先连贯到 Pool,而后关上 Container。如果应用程序被受权拜访 Container,则返回 Container 句柄,它的性能包含受权应用程序中的任何过程拜访 Container 及其内容。关上过程能够与所有对等过程共享此句柄。它们的性能在 Container 敞开时被撤销。

Container 中的对象可能具备不同的模式,用于解决数据分布和 Target 上的冗余,定义对象模式所需的一些参数包含动静或动态条带化、复制或纠删码。Object 类定义了一组对象的公共模式属性,每个 Object 类都被调配一个惟一的标识符,并在 Pool 级别与给定的模式相关联。一个新的 Object 类能够在任何时候用一个可配置的模式来定义,这个模式在创立之后是不可变的(或者至多在属于这个类的所有对象都被销毁之前)。

为了不便起见,在创立 Pool 时,默认状况下会预约义几个最罕用的 Object 类:

如下所示,Container 中的每个对象都由一个惟一的 128 位对象地址标识。对象地址的高 32 位保留给 DAOS 来编码外部元数据,比方 Object 类。剩下的 96 位由用户治理,在 Container 中应该是惟一的。只有保障唯一性,栈的下层就能够应用这些位来编码它们的元数据。DAOS API 为每个 Container 提供了 64 位可伸缩对象 ID 分配器。应用程序要存储的对象 ID 是残缺的 128 位地址,该地址仅供一次性应用,并且只能与单个对象模式相关联。

<---------------------------------- 128 bits ---------------------------------->
--------------------------------------------------------------------------------
|DAOS Internal Bits|                Unique User Bits                           |
--------------------------------------------------------------------------------
<---- 32 bits ----><------------------------- 96 bits ------------------------->

Container 是事务和版本控制的根本单元。所有的对象操作都被 DAOS 库隐式地标记为一个称为 epoch 的工夫戳。DAOS 事务 API 容许组合多个对象更新到单个原子事务中,并基于 epoch 程序进行多版本并发管制。所有版本更新都能够定期聚合,以回收重叠写入所占用的空间,并升高元数据复杂性。快照是一个永恒援用,能够搁置在特定的 epoch 上以避免聚合。

Container 元数据(快照列表、关上的句柄、对象类、用户属性、属性和其余)存储在持久性内存中,并由专用 Container 元数据服务保护,该服务应用与父元数据 Pool 服务雷同的复制引擎或本人的引擎,这在创立 Container 时是可配置的。

与 Pool 一样,对 Container 的拜访由 Container 句柄管制。要获取无效的句柄,应用程序过程必须关上 Container 并通过安全检查。而后,能够通过 Container 的 local2global() 和 global2local() 操作与其余对等应用程序过程共享此句柄。

DAOS Object

为了防止传统存储系统常见的扩大问题和开销,DAOS 无意将对象简化,不提供类型和架构之外的默认对象元数据。这意味着零碎不保护工夫、大小、所有者、权限,甚至不跟踪开启者。

为了实现高可用性和程度伸缩性,DAOS 提供了许多对象模式(复制 / 纠删码、动态 / 动静条带化等)。模式框架是灵便的,并且易于扩大,以容许未来应用新的自定义模式类型。模式布局是在对象标识符和 Pool 映射关上的对象上通过算法生成的。通过在网络传输和存储期间应用校验和爱护对象数据,确保了端到端的完整性。

能够通过不同的 API 拜访 DAOS 对象:

  • Multi-level key-array API 是具备局部性特色的本机对象接口。密钥分为散发密钥 (dkey) 和属性密钥 (akey)。dkey 和 akey 都能够是可变长度的类型(字符串、整数或其它简单的数据结构)。同一 dkey 下的所有条目都保障在同一 Target 上并置。与 akey 关联的值能够是不能局部批改的单个可变长度值,也能够是固定长度值的数组。akeys 和 dkey 都反对枚举。
  • Key-value API 提供了一个简略的键和可变长度值接口。它反对传统的 put、get、remove 和 list 操作。
  • Array API 实现了一个由固定大小的元素组成的一维数组,该数组的寻址形式是 64 位偏移寻址。DAOS 数组反对任意范畴的读、写和 punch 操作。

事务模型

DAOS API 反对分布式事务,容许将针对属于同一 Container 的对象的任何更新操作组合到单个 ACID 事务中。分布式一致性是通过基于多版本工夫戳排序的无锁乐观并发管制机制提供的。DAOS 事务是可串行化的,能够在特定的根底上获取局部须要的数据集。

DAOS 版本控制机制容许创立长久的 Container 快照,该快照提供 Container 的实时散布一致性视图,该视图可用于构建生产者 - 消费者管道。

Epoch 和工夫戳

每个 DAOS I/O 操作都有一个称为 epoch 的工夫戳。epoch 是一个 64 位整数,它集成了逻辑和物理时钟(详见 HLC paper)。DAOS API 提供了辅助函数,用于将 epoch 转换为传统的 POSIX 工夫(即 struct timespec,详见 clock_gettime(3))。

Container 快照

如下图所示,Container 的内容能够随时快照。

DAOS 快照十分轻量级,并且应用与创立快照的工夫相关联的 epoch 进行标记。一旦创立胜利,快照将始终放弃可读性,直到它被显式销毁。在特定快照未被销毁前,Container 的内容能够回滚到该快照。

Container 快照性能反对本机生产者 / 消费者管道:

一旦胜利写入数据集的统一版本,生产者 (Producer) 将生成一个快照。使用者 (Consumer) 的应用程序能够订阅 Container 快照事件,以便在生产者提交更新时能够解决新的更新。

快照的不变性保障了使用者能够看到统一的数据,即便生产者持续进行新的更新。生产者和消费者实际上都在 Container 的不同版本上操作,不须要任何串行化操作。一旦生产者生成了数据集的新版本,使用者就能够查问两个快照之间的差别,并且只解决增量批改。

分布式事务

与 POSIX 不同,DAOS API 不强制执行最坏状况下的并发管制机制来解决抵触的 I/O 操作。相同,各个 I/O 操作被标记为不同的 epoch,并依照 epoch 的程序利用,而不论执行程序如何。这个基准模型为不产生抵触的 I/O 工作负载的数据模型和应用程序提供了最大的可伸缩性和最高的性能。典型的例子是 MPI-IO 汇合操作、POSIX 文件读 / 写操作和 HDF5 数据集读 / 写操作。

对于须要将抵触串行化的局部数据模型,DAOS 提供了基于多版本并发管制的分布式可串行化事务。当不同的用户过程要笼罩与 dkey/akey 关联的值时,通常须要该事务。例如 DAOS 上的 SQL 数据库,或者由非统一的客户端并发拜访的统一的 POSIX 命名空间。

在同一操作的上下文中提交的所有 I/O 操作(包含读取)将应用雷同的 epoch。DAOS 事务机制自动检测传统的读 / 写、写 / 读和写 / 写抵触,并停止其中一个抵触事务(事务在 -DER_RESTART 参数下提交失败)。而后,用户 / 应用程序必须重新启动失败的事务。

在目前的实现中,事务 API 具备以下限度,这些限度将在将来的 DAOS 版本中解决:

  • 不反对 Array API
  • 通过同一上下文环境执行的对象获取 / 列表和键值获取 / 列表操作所进行的事务对象更新和键值放入操作不可见。

点击关注,第一工夫理解华为云陈腐技术~

正文完
 0