RADOS 快照
当我们开始考虑如何将 RADOS 快照功能暴露给 librados 用户时,出现了一些有趣的问题。对象存储暴露了一个相当底层的接口来控制何时克隆对象(即,通过 btrfs copy-on-write ioctls 何时拍摄对象快照)。Ceph 的基本设计是,客户端在每个写操作中提供一个“SnapContext”,指示给定对象的逻辑快照存在哪些。如果 OSD 存储的版本早于 SnapContext 中的最新快照,则在应用写入之前会创建一个克隆。Ceph MDS 的责任是跟踪哪些快照适用于哪些对象(请记住,Ceph 允许您快照任何子目录),并执行所有同步以确保已挂载的客户端拥有最新的 SnapContext。
在创建原始对象存储接口时,如何最好地暴露此底层功能?一种选择是暴露一些允许用户创建、操作和可能存储 SnapContext 的函数,并手动指定每个写入的上下文(或要读取的快照 ID)。这暴露了 Ceph 使用的相同功能,但基本上将所有同步和存储问题都交给了 librados 用户。如何让多个访问 RADOS 存储的进程保持同步(即,就哪些快照存在达成一致)以获得人们想要的行为?
我们的解决方案是在 RADOS 中引入一些基本的快照会计。我们允许通过 RADOS 本身创建每个池的快照,并将该快照信息包含在 OSDMap 中(用于同步 OSD 和客户端活动全局数据结构)。如果客户端执行写入并且未手动指定 SnapContext(如 Ceph 所做),则将从 OSDMap 中的池快照信息生成适当的上下文。
快照创建是通过监视器完成的,可以通过 librados API 调用或管理员命令(如“ceph osd pool mksnap poolname snapname”)完成。这将更新 OSDMap 以包含该池的新快照,并且该映射将在整个集群中传播。
int rados_snap_create(rados_pool_t pool, const char *snapname);
int rados_snap_remove(rados_pool_t pool, const char *snapname);
int rados_snap_list(rados_pool_t pool, rados_snapid_t *snaps, int maxlen);
int rados_snap_get_name(raods_pool_t pool, rados_snapid_t id, char *name, int maxlen);
要读取现有的快照,将打开一个新的 RADOS 池上下文,并选择特定的快照 ID(可以通过 rados_snap_list 上面获得)。
rados_pool_t snapped_pool;
rados_open_pool(“data”, &snapped_pool);
rados_set_snap(snapped_pool, 2);
随后通过 snapped_pool 处理程序进行的读取将返回 snapid 2 的数据,并且任何写入尝试都将返回 -EROFS(只读文件系统)。通过其他 rados_pool_t 处理程序进行的读取和写入不受影响。默认情况下,任何新打开的池处理程序都将“定位”到“head”——对象池的当前可写版本。
映射传播很快,但不是同步的:一个客户端创建快照,然后另一个客户端执行不保留新快照中的某些数据的写入,这是有可能的。因此,我们不会完全解决同步问题,为您创建一个全局的“瞬间”时间点快照。在大型分布式环境中,许多客户端和许多服务器并行运行,这是一个任何系统都面临的挑战。
但是,从创建快照的客户端的角度来看,该快照相对于 rados_snap_create 之前和之后执行的 IO 而言是有序的。RADOS 已经针对 OSDMap 更新进行了一些同步,以确保读取器、写入器和 OSD 在执行 IO 时都同意放置组的当前状态。在快照创建之后发起的任何 IO 都将使用新的 OSDMap 版本进行标记,并且任何 OSD 都会确保在执行该 IO 之前,它具有相同或更新版本的映射。其他客户端除非 librados 用户采取措施协调客户端,以便它们都在获得更新的 OSDMap(描述新的快照)之后才执行新的 IO,否则将看不到清晰的排序。
如果需求量大,我们仍然可以暴露一个 API 来操作原始 SnapContext,供希望为不同的对象使用不同快照计划的高级用户使用。在这种情况下,他们将负责管理所有客户端同步,因为该快照信息不会通过 OSDMap 传播。
对于任何想要完美的集群范围内的、时间点快照而无需任何客户端协调的人来说……很抱歉。使用文件系统快照的经验表明,适当的同步永远是存储系统本身无法解决的问题,因为系统所有层都存在缓存。NFS 客户端写回缓存使基于服务器的快照(例如,NetApp 文件服务器)不完美。本地文件系统中的快照利用一些内核机制来暂时停止所有 IO,同时创建快照,但即使应用程序可能也没有操作系统看到的磁盘上的文件处于一致状态。始终需要与应用程序协调才能获得完全“正确”的解决方案,因此我们不会试图基于对“正确”的错误认识来解决整个问题。
