CephFS I/O 路径深入解析:客户端直连 RADOS 的数据读写机制与能力协商
2026/9/21 19:22:10 网站建设 项目流程
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

CephFS(Ceph File System)将文件数据与元数据彻底分离:所有文件数据都以 RADOS 对象的形式存储于存储集群,而目录、文件名、权限等元数据由 MDS(Metadata Server)负责维护。本文以 cephfs-io-path.rst 为核心,系统讲解 CephFS 的数据 I/O 路径——客户端如何通过"能力(capability)"协商获得文件读写权、如何直接绕过 MDS 访问 RADOS 完成数据读写、数据对象如何按<inode号>.<对象索引>分条命名,以及用户态(libcephfs + librados)与内核态(ceph.ko + libceph.ko)两条客户端路径的异同。读完本文,你将掌握 CephFS 数据平面与元数据平面分离的设计精髓,理解读缓存(cache)与写缓冲(buffer)能力的语义,并能从源码级理解文件布局参数(stripe unit / stripe count / object size)如何决定对象的切分方式。

一、总览:元数据与数据分离的 I/O 架构

CephFS 的核心设计原则是:文件数据全部存放在 RADOS 对象中,客户端可以直接访问 RADOS 读写文件数据,MDS 只处理元数据操作。这一设计使得数据路径上没有 MDS 这个中间环节,从而避免了元数据服务器成为数据吞吐的瓶颈。

doc/cephfs/cephfs-io-path.rst中给出的架构图清晰地展示了这条两条路径:

+---------------------+ | Application | +---------------------+ | V +---------------------+ Data I/Os +--------------------+ | CephFS Library | ---------> | LibRados | +---------------------+ +--------------------+ | | | Metadata Operations | Objects Read/Write V V +---------------------+ +--------------------+ | MDSs | -=-------> | OSDs | +---------------------+ +--------------------+ +----------------------+ +---------------------+ | CephFS kernel client | Data I/Os | Ceph kernel library | | (ceph.ko) | --------> | (libceph.ko) | +----------------------+ +---------------------+ | | | Metadata Operations | Objects Read/Write v v +---------------------+ +--------------------+ | MDSs | -=-------> | OSDs | +---------------------+ +--------------------+

图中上、下两半分别对应 CephFS 的两种客户端实现:

  • 用户态客户端:应用 → CephFS Library(libcephfs)→ LibRados → OSDs;元数据操作走 CephFS Library → MDSs。
  • 内核态客户端:应用 → CephFS kernel client(ceph.ko)→ Ceph kernel library(libceph.ko)→ OSDs;元数据操作走 ceph.ko → MDSs。

两条路径的数据 I/O 都直接发生在客户端与 OSD 之间,MDS 只负责元数据(目录层次、inode 分配、能力协商、锁管理等)。这也是 CephFS 能够在大量客户端并发读写时保持扩展性的根本原因——数据平面是水平扩展的(OSD 集群),元数据平面由 MDS 集群承载,二者互不干扰。

二、能力(Capability)协商:读/写文件前的第一道关卡

在 CephFS 中,读写一个文件的前提是客户端拥有对应 inode 的 'file read/write' 能力(capability)。能力机制是 CephFS 保证多客户端缓存一致性的核心协议,其实现遍布 MDS 与客户端两侧:

  • MDS 侧:src/mds/Capability.h/src/mds/Capability.cc定义能力对象,src/mds/Locker.cc负责能力的发放、收回与锁协调;
  • 客户端侧:src/client/Client.cc维护客户端视图中的能力集合,并在 open 文件、需要扩展能力时向 MDS 发起请求。

2.1 能力不足时怎么办:cap message

当客户端没有所需的文件读写能力时,它不会直接去访问 RADOS,而是先向 MDS 发送一个cap message,告诉 MDS 自己想要什么。MDS 在条件允许时会向客户端发放(issue)能力。只有拿到 'file read/write' 能力之后,客户端才被允许直接访问 RADOS 读写文件数据。

这一协商流程保证了:任何时刻客户端对某 inode 的读写权限都由 MDS 统一裁决,多个客户端之间的缓存一致性(例如一个客户端要独占写、其他客户端必须 flush 并丢弃缓存)都由 MDS 通过能力回收与再发放来维护。

2.2 能力位的源码定义

能力的底层定义位于 src/include/ceph_fs.h,每种通用能力位(generic bits)都通过左移叠加到对应的能力域(auth、link、xattr、file)上:

#define CEPH_CAP_GSHARED 1 /* client can reads */ #define CEPH_CAP_GEXCL 2 /* client can read and update */ #define CEPH_CAP_GCACHE 4 /* (file) client can cache reads */ #define CEPH_CAP_GRD 8 /* (file) client can read */ #define CEPH_CAP_GWR 16 /* (file) client can write */ #define CEPH_CAP_GBUFFER 32 /* (file) client can buffer writes */ #define CEPH_CAP_GWREXTEND 64 /* (file) client can extend EOF */

对应到文件域(file realm)的能力位定义如下:

#define CEPH_CAP_FILE_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_CACHE (CEPH_CAP_GCACHE << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_RD (CEPH_CAP_GRD << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_WR (CEPH_CAP_GWR << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE)

这些位进一步组合成客户端常用到的能力集合(同一文件的相邻代码段):

  • CEPH_CAP_ANY_SHARED:任意域的 shared 能力(多个客户端可以同时持有,代表"我可以读");
  • CEPH_CAP_ANY_EXCL:任意域的 excl 能力(代表"我可以独占读写并更新");
  • CEPH_CAP_ANY_FILE_RD = CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE | ...:文件读能力全集;
  • CEPH_CAP_ANY_FILE_WR = CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | ...:文件写能力全集;
  • CEPH_CAP_ANY:所有能力全集。

注意区分CEPH_CAP_FILE_RD(可以读 RADOS 对象)与CEPH_CAP_FILE_CACHE(可以把读到的数据缓存到本地,后续读直接命中缓存)是两回事;CEPH_CAP_FILE_WR(可以写 RADOS 对象)与CEPH_CAP_FILE_BUFFER(可以把写操作缓冲在本地缓存,稍后异步 flush)也是两回事。这正是原文档强调的能力语义。

2.3 单客户端场景:cache 与 buffer 能力

原文档特别指出:如果文件只被一个客户端打开,MDS 还会向这个唯一的客户端发放 'file cache/buffer' 能力。二者的含义是:

  • file cache 能力:文件读可以由客户端缓存满足(读命中本地缓存即可返回,无需每次都访问 OSD);
  • file buffer 能力:文件写可以被缓冲在客户端缓存中(写操作先在本地缓存聚合,再由客户端按对象异步刷写到 RADOS)。

在多客户端场景下,由于缓存一致性难以保证,MDS 不会轻易发放 cache/buffer 能力;而在单客户端(或 MDS 判定可以安全共享)的场景下,cache/buffer 能力让客户端获得类似本地文件系统的读写性能,同时依旧保持数据最终落在 RADOS 对象上的持久性。这也是 CephFS 在单客户端工作负载(如单机挂载运行数据库)下表现出色的重要原因之一。

三、数据分条(Data Striping):<inode号>.<对象索引>的对象命名与布局

客户端获得文件读写能力后,便直接访问 RADOS 进行数据读写。文件数据以<inode number>.<object index>的形式存储为 RADOS 对象。也就是说,每个 CephFS 文件对应一系列 RADOS 对象,对象名由文件的 inode 号与对象序号拼接而成。

关于数据分条的完整背景,原文档指引读者参考 Architecture 文档的 Data Striping 一节。该节阐述了分条的必要性与原理:

  • 存储设备存在吞吐量上限,因此存储系统通常把连续的数据分条(striping)到多个设备上以提高吞吐与性能(类似 RAID 0);
  • Ceph 的分条能够同时获得 RAID 0 的吞吐、n 路镜像的可靠性以及更快的恢复速度;
  • 注意:Ceph 存储集群中的对象本身是不分条的,分条逻辑由各客户端负责——CephFS、RBD、RGW 都会把各自数据分条到多个存储集群对象上;直接通过 librados 写数据的客户端必须自行完成分条与并行 I/O 才能获得这些收益。

最简单的分条形式是 stripe count = 1:客户端把一个文件的 stripe unit 顺序写入对象,直到对象达到最大容量,再创建下一个对象继续写入。对于大文件、大对象,客户端把 stripe unit 并行写入对象集合中的多个对象时,写入性能提升显著——因为不同对象经 CRUSH 映射到不同的 placement group 与不同的 OSD,写操作可以并行发生、叠加多块盘的吞吐。

3.1 文件布局(file layout)的源码结构

决定一个文件如何切分为对象的参数统称为"文件布局(file layout)",其内核协议结构定义在 src/include/ceph_fs.h:

__le32 fl_stripe_unit; /* stripe unit, in bytes. must be multiple ... */ __le32 fl_stripe_count; /* over this many objects */ __le32 fl_object_size; /* until objects are this big, then move to ... */ __le32 fl_object_stripe_unit; /* UNUSED. for per-object parity, if any */

三个核心参数的含义:

参数含义说明
stripe_unit分条单元(字节)写入每个对象的数据块大小,必须是某个对齐单位的倍数
stripe_count分条对象数在一个对象集合(object set)内轮转多少个对象
object_size对象大小(字节)对象达到该大小后,开始使用下一批对象

当 stripe_count > 1 时,客户端按 stripe_unit 大小把文件逻辑区间轮流映射到 stripe_count 个对象上,形成对象集合;stripe_count 个对象写满 object_size 后,再开启下一个对象集合,对象索引继续递增。最终文件在 RADOS 中的对象序列正是<inode>.<n><inode>.<n+1><inode>.<n+2>……

3.2 布局的查看与设置

CephFS 布局可以按目录继承式地设置。常用操作:

# 查看文件/目录的布局 getfattr -n ceph.file.layout /mnt/cephfs/somefile # 为目录设置布局(新文件将继承该布局) setfattr -n ceph.file.layout.stripe_unit -v 1048576 /mnt/cephfs/bigdir setfattr -n ceph.file.layout.stripe_count -v 4 /mnt/cephfs/bigdir setfattr -n ceph.file.layout.object_size -v 4194304 /mnt/cephfs/bigdir # 或用 ceph fs 命令查看文件系统默认布局 ceph fs get cephfs

在 cephfs-journal-tool.rst 中可以见到一个真实的布局 JSON 示例:

"layout": { "stripe_unit": 4194304, "stripe_count": 1, "object_size": 4194304 }

这是一个典型的 4 MiB 对象、单对象分条布局。更完整的布局机制(继承规则、pool 选择、约束条件)参见 file-layouts.rst;而布局与权限的结合点——只有拥有p标志(layout-modification)的客户端才能修改布局,参见 client-auth.rst。

3.3 分条与副本的关系

一个容易混淆的点是:分条与对象副本是相互独立的。CRUSH 算法负责把对象副本分布到多个 OSD 上(例如 size=3 的三副本),而分条决定一个文件切分成多少个逻辑对象。因此,一个文件既可能被分条成多个对象(跨盘并行),每个对象又拥有多份副本(可靠性),二者叠加而不冲突。

四、两条客户端实现路径的纵深对比

原文档用同一幅图描绘了两条数据通路,二者的数据平面本质相同,但实现位置不同:

维度用户态客户端(libcephfs)内核态客户端(ceph.ko)
数据 I/O 库librados(用户态)libceph.ko(内核态)
元数据协议libcephfs 通过 Messenger 与 MDS 通信ceph.ko 通过内核消息与 MDS 通信
能力管理src/client/Client.cc中的 Cap 跟踪内核ceph文件系统驱动的 capability 结构
适用场景需要灵活性的应用、ceph-fuse 挂载高吞吐的内核 VFS 挂载(mount -t ceph)

无论哪条路径,"文件数据 = RADOS 对象、数据直连 OSD、元数据走 MDS"的架构都不变。MDS 侧对两种客户端一视同仁地执行能力协商与锁管理(src/mds/Locker.cc),因为能力协议是线缆级(wire protocol)的公共协议,而不是某个客户端的私有实现。

五、总结与延伸阅读

CephFS 的 I/O 路径可以概括为一条主线:能力协商(cap message → MDS 发放能力)→ 客户端直连 RADOS → 按文件布局把数据分条为<inode>.<对象索引>对象 → 并行读写 OSD。MDS 全程只参与元数据与能力仲裁,不参与数据搬运;单客户端场景下 cache/buffer 能力还能让客户端获得本地缓存读与写缓冲的性能收益。

如果希望继续深入,推荐按以下顺序阅读仓库中的相关材料:

  1. doc/cephfs/cephfs-io-path.rst:本文核心依据;
  2. doc/architecture/ceph-protocol.rst:数据分条的原理与图示;
  3. doc/cephfs/file-layouts.rst:布局参数的完整语义与继承规则;
  4. src/include/ceph_fs.h:能力位与文件布局结构的协议定义;
  5. src/mds/Locker.cc 与 src/mds/Capability.h:MDS 侧能力发放与锁协调的实现;
  6. src/client/Client.cc:用户态客户端侧能力跟踪与数据读写逻辑。
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

相关推荐

上一篇:革命性嵌入式开发工具Kaluma:让JavaScript运行在Raspberry Pi Pico上的完整指南
下一篇:告别因子冗余:gs-quant多因子模型正交化全攻略

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询