注意
本文档适用于 Ceph 的开发版本。
CephFS 回收接口
简介
NFS 服务器通常不会在稳定存储上跟踪临时状态。如果 NFS 服务器重新启动,它将以没有临时状态的方式复活,并且 NFS 客户端需要在宽限期内发送请求来回收它们所持有的状态。
为了支持这种用例,libcephfs 增加了一些函数,允许停止并重新启动的客户端销毁或回收其先前实例所持有的状态。这允许客户端重新获取其先前实例持有的状态,并避免在旧会话超时之前等待很长时间才能释放先前持有的状态。
运行在 cephfs 上的 NFS 服务器一宕机,它就会与其 MDS 会话超时进行竞争。如果 Ceph 会话在 NFS 宽限期开始之前超时,则另一个客户端可能会获取冲突的状态。此机制还允许我们增加这些客户端的超时时间,以确保服务器有足够长的时间窗口重新启动。
设置 UUID
为了正确地重置或回收旧会话,我们需要一种方法来识别旧会话。这通过使用 ceph_set_uuid() 在会话上设置一个唯一的、不透明的值来实现。uuid 值可以是任何字符串,并且客户端将其视为不透明。
设置 uuid 只能在新会话上进行,在挂载之前。执行回收时,当前会话将继承旧会话的 uuid。
开始回收
在对生成的 struct ceph_mount_info 调用 ceph_create 和 ceph_init 之后,客户端应该发出 ceph_start_reclaim,传入客户端先前实例的 uuid 和任何标志。
- CEPH_RECLAIM_RESET
此标志指示我们不打算对由给定 uuid 指示的旧会话进行任何类型的回收,并且应该将其丢弃。先前客户端持有的任何状态都应立即释放。
完成回收
Ceph 客户端完成所有回收操作后,客户端应发出 ceph_finish_reclaim 以指示回收现已完成。
设置会话超时(可选)
当客户端死亡并重新启动,并且我们需要保留其状态时,我们实际上是在与会话过期时钟赛跑。在这种情况下,我们通常希望更长的超时时间,因为我们期望最终手动终止旧会话。
示例 1:重置旧会话
此示例仅终止由其先前实例持有的 MDS 会话。NFS 服务器可以开始宽限期,然后要求 MDS 拆除旧会话。这允许客户端立即开始回收。
(注:为清晰起见,省略了错误处理)
struct ceph_mount_info *cmount;
const char *uuid = "foobarbaz";
/* Set up a new cephfs session, but don't mount it yet. */
rc = ceph_create(&cmount);
rc = ceph_init(&cmount);
/*
* Set the timeout to 5 minutes to lengthen the window of time for
* the server to restart, should it crash.
*/
ceph_set_session_timeout(cmount, 300);
/*
* Start reclaim vs. session with old uuid. Before calling this,
* all NFS servers that could acquire conflicting state _must_ be
* enforcing their grace period locally.
*/
rc = ceph_start_reclaim(cmount, uuid, CEPH_RECLAIM_RESET);
/* Declare reclaim complete */
rc = ceph_finish_reclaim(cmount);
/* Set uuid held by new session */
ceph_set_uuid(cmount, nodeid);
/*
* Now mount up the file system and do normal open/lock operations to
* satisfy reclaim requests.
*/
ceph_mount(cmount, rootpath);
...