注意
本文档适用于 Ceph 的开发版本。
与 POSIX 的区别
CephFS 的目标是尽可能遵守 POSIX 语义。例如,与许多其他常见的网络文件系统(如 NFS)相比,CephFS 在客户端之间保持强大的缓存一致性。目标是使通过文件系统通信的进程在不同主机上时的行为与在同一主机上时的行为相同。
然而,由于各种原因,CephFS 在某些方面与严格的 POSIX 语义有所不同:
如果客户端正在写入文件并失败,其写入不一定是原子性的。也就是说,客户端可能在以 O_SYNC 方式打开的文件上调用 write(2) 并使用 8 MB 缓冲区,然后崩溃,而写入可能只部分应用。(几乎所有文件系统,甚至是本地文件系统,都存在这种行为。)
在共享同步写入者的情况下,跨越对象边界的写入不一定是原子性的。这意味着你可能有写入者 A 写入“aa|aa”,写入者 B 同时写入“bb|bb”(其中 | 是对象边界),而最终结果可能是“aa|bb”,而不是正确的“aa|aa”或“bb|bb”。
稀疏文件无法正确传播到 stat(2) st_blocks 字段。因为 CephFS 不会显式跟踪文件的哪些部分已分配/写入,所以 st_blocks 字段始终由文件大小除以块大小来填充。这将导致 du(1) 等工具高估消耗的空间。(由 CephFS 维护的递归大小字段在其计数中也包含文件“空洞”。)
当文件通过 mmap(2) 映射到多个主机上的内存时,写入不会一致地传播到其他客户端的缓存。也就是说,如果一个页面缓存在主机 A 上,然后在主机 B 上更新,主机 A 的页面不会被一致地失效。(共享可写 mmap 似乎非常罕见——我们尚未听到关于此行为的任何投诉,并且正确实现缓存一致性非常复杂。)
CephFS 客户端会呈现一个隐藏的
.snap目录,用于访问、创建、删除和重命名快照。尽管虚拟目录在 readdir(2) 中被排除在外,但任何尝试使用相同名称创建文件或目录的进程都会收到错误代码。这个隐藏目录的名称可以在挂载时通过-o snapdirname=.somethingelse(Linux)或配置选项client_snapdir(libcephfs、ceph-fuse)更改。CephFS 目前不维护
atime字段。大多数应用程序不关心这一点,但这会影响一些备份和数据分层应用程序,这些应用程序可以将未使用的G数据移动到辅助存储系统。对于某些用例,你也许可以解决此问题,因为 CephFS 支持通过setattr操作设置atime。
观点
人们经常谈论“POSIX 合规性”,但实际上大多数文件系统实现并不严格遵守规范,包括 ext4 和 XFS 等本地 Linux 文件系统。例如,出于性能原因,放松了读取的原子性要求:从正在写入的文件中读取的进程可能会看到撕裂的结果。
同样,当多个客户端与相同的文件或目录交互时,NFS 具有极弱的一致性语义,转而采用“接近打开”的语义。在网络附加存储的世界中,大多数环境使用 NFS,服务器的文件系统是否“完全 POSIX”可能并不相关,客户端应用程序是否会注意到取决于数据是否在客户端之间共享。NFS 也可能“撕裂”并发写入者的结果,因为客户端数据可能直到文件关闭时才刷新到服务器(更一般地说,写入的时移会比 CephFS 大得多,导致结果更不可预测)。
无论如何,这些都与 POSIX 足够相似,并且应用程序在大多数情况下仍然可以工作。许多其他存储系统(例如 HDFS)声称“类似于 POSIX”,但通过放弃对原地文件修改、截断或目录重命名等功能的支持而与标准显着不同。
总结
CephFS 比本地 Linux 内核文件系统放松得多(例如,跨越对象边界的写入可能会被撕裂)。在多客户端一致性方面,它比 NFS 严格得多,在写入原子性方面通常也比 NFS 严格得多。
换句话说,当谈到 POSIX 时,
HDFS < NFS < CephFS < {XFS, ext4}
fsync() 和错误报告
POSIX 对 fsync 报告错误后 inode 的状态有些模糊。通常,CephFS 使用客户端内核中的标准错误报告机制,因此遵循与其他文件系统相同的约定。
在现代 Linux 内核(v4.17 或更高版本)中,写入错误会向在发生错误时打开的每个文件描述符报告一次。此外,在文件描述符打开之前发生的未报告错误也会在 fsync 上返回。
有关更多信息,请参阅 PostgreSQL 关于跨操作系统 fsync() 错误报告的摘要以及 Matthew Wilcox 关于 Linux IO 错误处理的演示。