注意
本文档适用于 Ceph 的开发版本。
Ceph 文件系统客户端逐出
当文件系统客户端无响应或行为异常时,可能需要强制终止其对文件系统的访问。此过程称为逐出。
逐出 CephFS 客户端会阻止它进一步与 MDS 守护程序和 OSD 守护程序通信。如果客户端正在对文件系统进行缓冲 IO,则任何未刷新的数据都将丢失。
客户端可以自动逐出(如果它们未能及时与 MDS 通信),也可以手动逐出(由系统管理员操作)。
客户端逐出过程适用于所有类型的客户端,包括 FUSE 挂载、内核挂载、nfs-ganesha 网关以及任何使用 libcephfs 的进程。
自动客户端逐出
在三种情况下,客户端可能会被自动逐出。
在活动的 MDS 守护程序上,如果客户端在超过
session_autoclose(文件系统变量)秒(默认为 300 秒)内未与 MDS 通信,则它将自动被逐出。在活动的 MDS 守护程序上,如果客户端在超过
mds_cap_revoke_eviction_timeout(配置选项)秒内未响应功能吊销消息。此选项默认禁用。在 MDS 启动期间(包括故障转移时),MDS 会经历一个名为
reconnect的状态。在此状态期间,它会等待所有客户端连接到新的 MDS 守护程序。如果任何客户端未能在时间窗口内(mds_reconnect_timeout,默认为 45 秒)完成此操作,则它们将被逐出。
如果出现这些情况中的任何一种,集群日志中都会发送警告消息。
手动客户端逐出
有时,管理员可能希望手动逐出客户端。这可能发生在客户端已死亡且管理员不想等待其会话超时的情况下,或者发生在客户端行为异常且管理员无权访问客户端节点以将其卸载的情况下。
首先检查客户端列表很有用
ceph tell mds.0 client ls
[
{
"id": 4305,
"num_leases": 0,
"num_caps": 3,
"state": "open",
"replay_requests": 0,
"completed_requests": 0,
"reconnecting": false,
"inst": "client.4305 172.21.9.34:0/422650892",
"client_metadata": {
"ceph_sha1": "ae81e49d369875ac8b569ff3e3c456a31b8f3af5",
"ceph_version": "ceph version 12.0.0-1934-gae81e49 (ae81e49d369875ac8b569ff3e3c456a31b8f3af5)",
"entity_id": "0",
"hostname": "senta04",
"mount_point": "/tmp/tmpcMpF1b/mnt.0",
"pid": "29377",
"root": "/"
}
}
]
确定要逐出的客户端后,可以使用其唯一 ID 或其他各种属性来逐出它
# These all work
ceph tell mds.0 client evict id=4305
ceph tell mds.0 client evict client_metadata.=4305
高级:取消对客户端的封锁
通常,被封锁的客户端不得重新连接到服务器:必须将其卸载,然后重新挂载。
但是,在某些情况下,允许被逐出的客户端尝试重新连接可能会很有用。
因为 CephFS 使用 RADOS OSD 封锁列表来控制客户端逐出,所以可以通过从封锁列表中删除 CephFS 客户端来允许它们重新连接
$ ceph osd blocklist ls
listed 1 entries
127.0.0.1:0/3710147553 2018-03-19 11:32:24.716146
$ ceph osd blocklist rm 127.0.0.1:0/3710147553
un-blocklisting 127.0.0.1:0/3710147553
如果其他客户端访问了被封锁客户端正在进行缓冲 IO 的文件,这样做可能会危及数据完整性。也不能保证会产生一个功能齐全的客户端——在逐出后恢复一个完全健康的客户端的最佳方法是卸载客户端并进行新的挂载。
如果您正尝试以这种方式重新连接客户端,您可能还会发现将 FUSE 客户端中的 client_reconnect_stale 设置为 true 会很有用,以提示客户端尝试重新连接。
高级:配置封锁
如果您由于客户端主机速度慢或网络不可靠而频繁遇到客户端逐出,并且无法修复底层问题,那么您可能希望要求 MDS 不那么严格。
可以通过简单地删除慢速客户端的 MDS 会话来响应它们,但允许它们重新打开会话并允许它们继续与 OSD 通信。要启用此模式,请在 MDS 节点上将 mds_session_blocklist_on_timeout 设置为 false。
对于手动逐出的等效行为,请将 mds_session_blocklist_on_evict 设置为 false。
请注意,如果禁用封锁,则逐出客户端将仅对您发送命令的 MDS 产生影响。在具有多个活动 MDS 守护程序的系统上,您需要向每个活动的守护程序发送逐出命令。当启用封锁时(默认设置),向单个 MDS 发送逐出命令就足够了,因为封锁列表会将其传播给其他 MDS。
背景:封锁和 OSD 纪元屏障
客户端被封锁后,必须确保其他客户端和 MDS 守护程序在尝试访问被封锁客户端可能正在访问的任何数据对象之前,都具有最新的 OSDMap(包括封锁列表条目)。
这是通过内部“osdmap 纪元屏障”机制来确保的。
屏障的目的是确保当我们发出任何可能允许接触相同 RADOS 对象的功能时,我们发出功能的目标客户端必须具有足够新的 OSD 映射,以免与已取消的操作(来自 ENOSPC)或被封锁的客户端(来自逐出)发生竞争。
更具体地说,设置纪元屏障的情况是
客户端逐出(客户端被封锁,其他客户端必须等待封锁后的纪元才能接触相同的对象)。
客户端中的 OSD 映射满标志处理(客户端可能会取消来自满之前的纪元的一些 OSD 操作,因此其他客户端必须等到满纪元或之后才能接触相同的对象)。
MDS 启动,因为我们不会持久化屏障纪元,因此必须假设重启后始终需要最新的 OSD 映射。
请注意,为了简单起见,这是一个全局值。我们可以在每个 inode 的基础上维护它。但我们没有这样做,因为
会更复杂。
它会为每个 inode 多使用 4 字节内存。
效率不会高出太多,因为几乎总是每个人都拥有最新的 OSD 映射。而且,在大多数情况下,每个人都会轻松通过这个屏障,而不是等待。
这个屏障在非常罕见的情况下才会发生,因此每 inode 粒度的任何好处都很少会被看到。
纪元屏障会与所有功能消息一起传输,并指示消息接收方在看到此 OSD 纪元之前避免向 OSD 发送更多 RADOS 操作。这主要适用于客户端(直接向文件进行数据写入),但也适用于 MDS,因为文件大小探测和文件删除等操作是直接从 MDS 完成的。