DAOS 分布式异步对象存储|Container

举报
debugzhang 发表于 2021/04/14 18:42:30 2021/04/14
【摘要】 Container 表示 Pool 中的对象地址空间,并由 UUID 标识。Container 是事务和版本控制的基本单元。所有的对象操作都被 DAOS 库隐式地标记为一个称为 epoch 的时间戳。DAOS 事务 API 允许组合多个对象更新到单个原子事务中,并基于 epoch 顺序进行多版本并发控制。所有版本更新都可以定期聚合,以回收重叠写入所占用的空间,并降低元数据复杂性。

Container 表示 Pool 中的对象地址空间,并由 UUID 标识。要访问 Container,应用程序必须首先连接到 Pool,然后创建或打开 Container。如果应用程序被授权访问 Container,它将获得 Container 句柄。这包括授权应用程序中的任何进程访问 Container 及其内容的功能。这一进程可以与其它的对等进程共享此句柄。它们的功能在关闭 Container 时被取消。(请参考 存储模型 DAOS Container 一节)。

元数据设计

Container Service (cont_svc) 存储 Container 的元数据,并提供一个 API 来查询和更新状态以及管理 Container 的生命周期。

Container 的元数据被组织为键值存储 (key-value stores, KVS) 的层次结构,这些键值会复制到多个服务器上,而这些服务器由 Raft 一致性协议支持。

客户端请求只能由 Leader 提供服务,而 Follower 的副本只响应一个指向当前 Leader 的提示,以便客户端重试。

cont_svc 派生自一个通用的复制服务模块 rsvc(请参考 Replicated Services: Architecture),它的实现便于客户端搜索当前的 Leader。

Container Service Layout

第一级 KVS root 有两个子节点:

  1. Containers KVS:保存 Container Properties KVS 列表,KVS 由用户在创建新 Container 时提供的 UUID 索引。
  2. Container Handles KVS:用于存储由各种应用程序打开的 Container 句柄的数据,并由客户端在打开 Container 时生成的句柄 UUID 索引。与 Container 句柄相关联的元数据包括其功能(例如只读或读写)及其每个句柄的 epoch 状态。当 Container 关闭时,相应的条目将从此存储中删除。

Container Properties KVS 用于存储每个 Container 的元数据,这些元数据由许多可变和不可变的标量值属性以及其他 KVS 组成,如上图所示。

用户可以创建、删除和检索持久快照列表,这些快照本质上是不会被聚合的 epoch。快照在显式销毁之前保持可读性,Container 也可以回滚到特定快照。(请参阅 存储模型 DAOS Container 一节和 事务模型 Container 快照一节)。

用户还可以为 Container 定义自定义属性,这些 Container 本质上是 name-value 键值对:

  • name 是以空字符结尾的字符串;
  • value 是任意字节序列。

Container Service 允许客户端一次检索和更新多个属性,并列出存储属性的名称。

Target Service

Target Service 将 DAOS Container 的全局对象地址空间映射到 Target 的 VOS Pool (vpool) 中 VOS Container 的本地对象地址空间,并代表 Container VOS 调用 VOS 方法(请参阅 VOS Concepts)。它在 Container 对象上缓存每个线程的信息,并在易失性内存中打开句柄以便随时访问。

Target 故障

给定数十万个 Target,epoch 协议必须允许在存在 Target 故障的情况下正常工作。由于 Pool Service 和 Container Service 均具有高可用性,因此问题主要与 Target Service 有关。

该解决方案基于这样的假设:丢失某些 Target 不一定会导致任何应用程序数据丢失,因为 DAOS-SR 层可能会创建足够的冗余来对应用程序隐藏故障。此外,应用程序甚至可能希望忽略特定的数据丢失(此时 DAOS-SR 层无法隐藏),因为它有足够的应用程序级冗余来应对,或者根本不关心。

当写入、刷新或丢弃操作失败时,DAOS-SR 层计算是否有足够的冗余来继续 epoch。如果故障可以隐藏,并且假设 Pool 映射中尚未禁用所讨论的 Target(例如,RAS notification),则 DAOS-SR 层必须在提交 epoch 之前禁用 Target。对于 epoch 协议,生成的 Pool 映射更新有效地记录了 Target 可能在 epoch 中存储一组未定义的写操作的事实,所以应该尽量避免这种情况。这也适用于希望忽略 DAOS-SR 层无法隐藏的类似故障的应用程序。

Object ID 分配器

OID 分配器是一个例行帮助服务,它允许用户在 Container 中分配一组唯一的 64 位无符号整数。这对无法以可伸缩的方式轻松分配唯一的 DAOS Container ID 的应用程序或中间件很有帮助。

在 Container Properties KVS 中跟踪分配的最大 ID,以便将来访问该 Container。此服务不保证分配的 ID 是连续的,并且在 Container 关闭时可能会丢弃多个 ID 范围。

分配器是使用服务器端的 Incast Varialbe (IV) 实现的,该变量跟踪 IV 树根节点上 Container 使用的最大的 Object ID。客户端可以从运行 Container Target Service 的任何服务器(即 IV 树中的任何节点)请求新的分配。当一个新的请求到达时,服务器首先检查本地是否有可供分配的 ID。如果没有,它会将请求转发给父级(在这种情况下,请求更大范围的 OID)。父级执行相同的检查并不断转发到其父级,直到满足请求或我们到达 IV 根节点,根节点将更新 Container 元数据中记录所分配的最大 OID 的 Incast Varialbe。在每个树级别,可请求的 OID 数量都会增加,以便更快地满足未来的 OID 分配请求。

Container 操作

客户端通过使用 Pool 句柄和 UUID 向 Container Service 发送 CONT_CREATE 请求来创建新的 Container。客户端必须首先建立 Pool 连接才能获得 Pool 句柄。请求还可以包含要在新创建的 Container 上设置的属性列表。作为响应,Container Service 使用 UUID 作为键创建相应的 Container Properties KVS。创建 Container 不需要 Target Service 的参与。

客户端现在可以通过提供打开的 Pool 句柄和 Container 的 UUID 以及打开标志(例如只读或读写)来打开 Container。客户端库向 Container Service 发送一个带有本地生成的 UUID 的 CONT_OPEN 请求,然后使用 IV (Incast Varialbe) 将句柄异步广播到 Pool 中所有启用的 Target。成功完成后,它将在 Container Handles KVS 中创建一个新条目。

客户端可以通过向 Container Service 发送 CONT_CLOSE 请求来关闭不再需要的 Container 句柄,该请求作为一个集中式的 CONT_TGT_CLOSE 向所有启用的 Target 广播,以便关闭 Container 句柄。然后从 Container Handles KVS 中删除相应的条目,并放弃对句柄执行未提交的更新。

当客户端向 Container Service 发送 CONT_DESTROY 请求使其清除所有元数据时,Container 将被销毁。类似地,Target 共同接收来自 Container Service 的 CONT_TGT_DESTROY 请求,并删除与该 Container 相关联的所有数据,包括该 Container 中的所有 Object。如果当前 Container 有打开的句柄,客户端可以选择强制销毁该 Container。

Epoch 协议

epoch 协议实现了事务模型中描述的 epoch 模型。Container Service 管理 Container 的 epoch(作为 Container 元数据的一部分维持确定的 epoch 状态),而 Target Service 对全局 epoch 状态缺乏了解。因此,epoch 的提交、丢弃和聚合过程都由 Container Service 驱动。

在每个 Target 上,Target Service 会迅速将传入的写操作存储到匹配的 VOS Container 中。如果 Container 句柄丢弃了一个 epoch,VOS 将帮助丢弃与该 Container 句柄关联的所有写操作。

当写操作成功时,在相等或更高的 epoch 中,冲突操作立即可见。VOS 将拒绝具有相同 epoch 的冲突写入操作,除非它与同一 Container 句柄关联,并且内容与已执行的内容相同。

在提交一个 epoch 之前,应用程序必须确保 Target Service 已持久化此阶段足够的写操作集。应用程序可以根据它们各自采用的冗余方案丢失一些写操作。提交 Container 句柄的 epoch 会将 CONT_EPOCH_COMMIT 请求发送到相应的 Container Service,该服务只需要更新元数据。当更新变持久化后,Container Service 将以新的 epoch 状态向客户端回复。

相关信息

Emai: debugzhang@163.com

DAOS: https://github.com/daos-stack/daos

本文翻译自 https://github.com/daos-stack/daos/blob/master/src/container/README.md

【版权声明】本文为华为云社区用户翻译文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容, 举报邮箱:cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。