DAOS系统架构-Pool

daos: 2.6.0

1. 概述

存储池是一组target的集合,这些target是分布在不同存储节点上。数据和元数据被分布在这些target上以实现水平可扩展,同时对数据和元数据采用副本和纠删码容错机制来确保持久性和可用性。

   

2. 存储池服务

存储池服务(pool_svc)主要用于存储存储池的元数据,并提供用于查询和更新存储池配置的API接口。存储池的元数据被组织成key-value的存储结构(KVS),然后在某些服务器上做副本。其中某些服务器是由Raft共识算法选举出的。客户端请求只能由leader服务处理,所以非leader服务需要将客户端请求重定向给leader服务。pool_svc是从rsvc模块中派生出来的。

2.1. 存储池元数据布局

pool_meta_layout

从上图可以看到,存储池元数据布局重要包含2个层次。第一个层次(蓝色)是和存储池相关的,主要包含pool map、安全属性(如 UID、GID 和模式)、与空间管理和自我修复相关的信息。第二个层次(绿色)是和应用相关的,主要包含用户定义的属性,同样也是KVS结构。其次就是关于存储池连接的信息,由存储池句柄表示,存储池句柄的UUID是由客户端生成的。

   

3. 存储池操作

3.1. 存储池/存储池服务的创建

存储池的创建完全是由DAOS管理服务驱动的,因为它需要特殊权限才能执行与存储分配和容错域查询相关的步骤。格式化所有的targets之后,DAOS管理模块会调用ds_pool_svc_dist_create函数将控制权传递给存储池模块。在这个函数中,会在某些存储节点上初始化存储池服务副本。接着存储池模块会向存储池的leader服务(负责创建service数据库)发送一个POOL_CREATE请求,然后target列表和容灾域信息会被转化成初始版本的pool map,并与其他初始化元数据一起存储在存储池服务中。

3.2. 存储池的连接

为了与存储池建立连接,客户端需要调用daos_pool_connect函数向存储池服务发送POOL_CONNECT请求,该函数会用到存储池UUID、连接信息(比如group name和service ranks列表)和连接标志这信息。存储池服务根据使用的安全模型对客户端请求进行身份认证,并将请求的能力授权给存储池句柄的UUID。在继续之前,存储池map会被发送给客户端。如果在这个过程中出现错误,服务器可以要求客户端将存储池map丢弃。

然后,存储池服务会检查已存在的存储池句柄,具体处理逻辑如下:

  • 如果已经存在具有相同UUID的存储池句柄,则表示存储池连接已经建立过了,不需要执行任何其他动作。
  • 如果存在另外一个不同的存储池句柄,并满足以下条件之一:要么当前请求的句柄具有独占访问权限,要么已存在的句柄具有独占访问权限,则连接请求会被拒绝,并返回“忙碌”状态码。​

如果一切顺利,存储池服务会向存储池中所有的target发送一个带有存储池句柄UUID的集体POOL_TGT_CONNECT请求。target服务会创建并缓存本地存储池objects,并打开本地VOS存储池以供访问。

一组对等(peer)的应用进程可以共享同一个存储池连接句柄。

要关闭存储池连接,客户端需要调用daos_pool_disconnect函数向存储池服务发送POOL_DISCONNECT请求,然后存储池服务会像存储池中所有的target发送POOL_TGT_DISCONNECT请求。这些步骤会销毁与连接相关联的所有转台,包括所有的容器句柄。共享该连接的其他客户端进程最好在调用disconnect方法之前销毁本地的存储池句柄副本。因为disconnect方法可以取消所有与该连接相关的客户端进程的连接。如果一组客户端进程在有机会调用disconnect方法之前就提前终止了(比如Ctrl+Z)。一旦存储池服务从运行时环境中获取到该事件,那么他们的存储池连接最终会会被逐出。