从零开发分布式文件系统(四):一道经典面试题,深度对比 CephFS 与 3FS 的元数据架构优劣
一共8千字,让领导看绝对不看,完全不符合一页纸汇报原则
需要再次精简,
然后回到 查找/mnt/icfs/dir01/file.txt ,如何落到具体MDS节点
插播一个广告,#曙光诚聘分布式存储# 工作 地点天津找人了
需要可以内推
看你项目经历有实现过文件系统,
请描述查找/mnt/icfs/dir01/file.txt 过程?
我不清楚部分:
•
我只是普通工程师,每天接触的安装部署,测试,然后调用接口工作,
•
根本不清楚文件磁盘io过程,之前从网络看过,不属于自己知识,自己也描述不上来,不清楚,内核更不懂
•
同事很多工作,处理大量问题,百分之一比不过,根本处理了
•
想到这里 ,我只能回答 不清楚,然后面试结束。
•
我就是我遇到最大问题,别人一句话,让自己陷入头脑的战争 可怕
我清楚部分是:(这个很重要,越具体越好,精确到每个参数)
为了测试功能,我搬运过机器,部署过机器集群
具体机型:
•
系统架构:多个节点组成一个集群,一个集群划分不同模块 支持不同协议客户端,元数据节点,数据存储节点,监控协调节点,虽然相同模块但是后台实现完全不一样
•
支持扩展到1万个节点,EB级别,必然是去中心化的设计
•
机柜:2U,4U 代表设备高度,在机架上 占用多个格子, 设备越高 放的磁盘越多,一个设备 60个,100个HDD盘
•
CPU型号:lscpu Intel® Xeon® Gold 6342 Processor 24内
•
网络接类型:至少4个网卡 ,ethtool 命令 千兆 万兆带宽,InfiniBand IB
•
网络配置:/etc/sysconfig/network-scripts/ifcfg-eth0
•
交换机,IB交换机,不是路由器
•
访问接口:通过NFS等协议,挂载文件系统
物理视图 2U
部署配置:
组件 | 节点类型 | 数量 | 核心配置 | 存储配置 |
---|---|---|---|---|
数据存储节点 | OSD (HDD) | 60个HDD | 每块硬盘直接对应1个OSD服务60个进程 | 数据池 |
元数据存储节点 | OSD (NVMe) | 2 | 2块1.8TB NVMe盘,各分4区 共创建8个OSD | 元数据池 |
元数据服务 | MDS | 4 | 一个节点至少4-8个 | Ceph Metadata Server (MDS) |
客户端节点 | Client | 3 | 无需本地存储,通过网络访问Ceph集群 |
•
CRUSH 是 Ceph 用于数据分布的算法,它决定了如何将数据对象映射到 OSD 上。CRUSH 根据集群拓扑,去中心化的,导致扁平化存储,无目录树结果
•
Ceph Metadata Server (MDS)保证文件目录结构,多节点存储
我做过操作:
vdbench 创建文件,批量手工touch /mnt/icfs/dir01/file.txt 文件,
然后存储整个集群当中,神奇
我定位操作: 假如创建失败了,是那个服务出现问题MDS,不能每个节点,每个服务查询 太多了,清楚知道,该服务在那个节点看日志
回答重点:
•
用户态执行 cat /mnt/icfs/dir01/file.txt 命令 客户端怎么处理
•
客户端发送对应那个MDS查询文件 获取inode信息
•
客户端根据indoe信息查询文件
文件系统是怎么通过路径来知道文件所在的磁盘位置?
回答:从客户端发起请求到 定位具体数据在那个元数据节点, 不回答 文件io具体处理过程
回答重点:
•
用户态执行 cat /mnt/icfs/dir01/file.txt 命令 客户端怎么处理
•
客户端发送对应那个MDS查询文件 获取inode信息
•
客户端根据indoe信息查询文件
如下面三个图 无论后端是
•
hello demo服务
•
Ceph存储服务
•
3FS存储服务
对客户端来说 操作系统提供这样接口
•
FUSE:从内核到用户态的文件系统
•
用户空间实现文件系统 Filesystem in Userspace,调用自己写程序,fuse经过内核的中转站。
s3fs allows Linux, macOS, and FreeBSD to mount an S3 bucket via FUSE(Filesystem in Userspace). s3fs makes you operate files and directories in S3 bucket like a local file system,
一个用户态文件系统,挂载点为 /tmp/fuse
用户二进制程序文件为 ./hello
;
当执行 ls -l /tmp/fuse
命令的时候,
流程如下:
1. IO 请求先进内核,经 vfs 传递给内核 FUSE 文件系统模块;
2. 内核 FUSE 模块把请求发给到用户态,由 ./hello
程序接收并且处理。处理完成之后,响应原路返回
基于fuse实现一个分布式文件系统,后端存储可以其他系统
ceph
也是操作系统自带,数据,元数据存储一个节点上
•
客户端直接发送当前节点,
•
当前节点 从内存查询元数据,如果内存不存在 从磁盘查找
例如 /hello/file1
•
根目录 元数据 从磁盘查找1次
•
hello目录元数据 从磁盘查找1次
•
如果多级目录 查找多次
请描述查找/mnt/icfs/dir01/file.txt 过程?
3FS
•
文件系统遵循目录递归遍历方式查找,每个目录遍历存储哪些文件直接kv查询
(GFS除外,它存储大文件,海量小文件根本不采取这个方式,类似 前缀压缩路径方式存储)
•
客户端发送到任意元数据节点,为什么
3FS文件系统
•
文件元数据存储到KV中 包括 文件目录项 和数据分布
•
3FS 文件元数据 无状态的,任意节点都查询。
•
文件目录关系 通过kv命名区分,记住存储kv数据库中。
•
3FS 文件元数据 无状态的,重启很简单。
举例:类似表结构存储
来源:https://github.com/manuel71sj/deepseek-ai_3FS/blob/main/docs/design_notes.md
文件的 Inode 和 Dentry结构
键值模型映射
键格式 | 值内容 | 用途 |
---|---|---|
DENT:{parent_inode}:{name} | child_inode | 目录项查询 |
INOD:{inode} | {size, mode, blocks...} | 文件属性获取 |
CHUNK:{inode}:{offset} | chunk_id | 数据块定位 |
3FS 使用 FoundationDB 作为其元数据的分布式存储系统。 FoundationDB 提供键值存储接口,并支持可序列化快照隔离 (SSI) 事务。
3FS 将所有元数据以键值对的形式存储在 FoundationDB 中。
元服务采用无状态架构,允许管理员无缝升级或重启服务,无需中断,从而显著增强了可维护性。
当客户端遇到请求失败或超时时,它们可以自动故障转移到其他可用服务。
元操作利用 FoundationDB 的事务:
•
用于元数据查询的只读事务:fstat、lookup、listdir 等。
•
用于元数据更新的读写事务:创建、链接、取消链接、重命名等。
对比:典型案例 tikv的 kv存储数据 和Redis kv存储
一个文件系统通过表存储
CREATETABLE categories (
category_id INT PRIMARY KEY,
parent_id INTNULL,
category_name TEXTNOTNULL,
FOREIGNKEY (parent_id) REFERENCES categories(category_id)
);
通过递归方式查询一个完整文件路径,直接去数据库查询可以了,简单方便。
这就是基本原理,请看看其他系统是不是按照这个思路设计的
请描述查找/mnt/icfs/dir01/file.txt 过程?
文件系统元数据不是直接存储到kv中
取舍
•
对象层:走去中心化(CRUSH),解决了“数十亿对象”的扩展性问题。
•
文件系统层:走中心化(MDS),因为文件系统操作(ls、rename、mkdir)需要全局一致的目录树,没法用纯算法算出来。客户端无法直接文件计算落在那个MDS
1
2010年:Ceph开始引入RADOS(可扩展自组织分布式对象存储)作为其核心存储技术,并发布了Ceph的第一个稳定版本。
2
2012年:Ceph在Linux内核中引入了RADOS Block Device(RBD)模块,从而支持块存储。这是Ceph变得更加多样化并用于虚拟化和云存储的重要一步。
3
2013年:Ceph的文件系统组件CephFS引入,使其成为一个全面的存储解决方案,包括对象存储、块存储和文件存储。
Ceph核心是RADOS, 根据 Ceph: A Scalable, High-Performance Distributed File System 描述
RADOS 设计目标是存储文件中的数据对象方式存储(块存储), 对象和对象直接是扁平化结构,没有没有文件系统概念(刚开始不是为文件系设计的),
Ceph OSD Daemons store data as objects in a flat namespace.
This means that
objects are not stored in a hierarchy of directories.
RADOS对象
Ceph的 文件系统元数据必须 MDS 管理,不然无法形成一棵树
特性 | Ceph (CephFS) | 3FS (Fire-Flyer File System) |
---|---|---|
核心设计 | 目录即对象 | 全局有序KV,前缀范围查询 |
存储后端 | RADOS 对象存储 | FoundationDB |
Inode键 | {Inode号}.{分片号}(如 1099511627776.00000000) | "INOD" + <Inode编号>(小端编码,如 INOD\x02\x00...) |
目录项键 | 存储在目录对象的OMap中,Key为条目名 | "DENT" + <父目录Inode编号> + <条目名>(如 DENT123dir01) |
目录结构 | 一个目录对应一个或多个RADOS对象,通过分片管理大量条目 | 无独立目录对象,同一目录下所有条目因键前缀相同而自然连续 |
关键优势 | 与Ceph生态深度集成,利用RADOS的成熟特性 | 强一致性事务,元数据服务无状态,易于水平扩展 |
查找过程
1
起点:连接根目录
客户端首先会连接到一个已知的MDS。
这个MDS可能恰好是根目录 /
的“权威MDS”,
2
逐级遍历路径
查找过程会沿着路径 /mnt/icfs/dir01/file.txt
逐级进行:
•
接收到客户端请求的MDS(我们称为接收MDS)首先会检查第一级目录 mnt
的权威MDS是谁。
•
如果 mnt
目录的权威就是自己,接收MDS会直接查询本地的元数据缓存。
•
如果 mnt
目录的权威是另一个MDS(比如MDS-2),接收MDS会将这部分查找请求转发给MDS-2。
•
MDS-2 作为 mnt
目录的权威,会解析其下的 icfs
目录项。
•
同样地,它会判断 icfs
目录的权威MDS是谁。
•
这个过程会一直重复,直到找到最终文件 file.txt
的inode信息。
3
返回结果
•
一旦找到 file.txt
对应的inode,这个信息会沿着MDS转发链原路返回最终送达客户端。
•
客户端获得inode后,就可以直接与OSD(对象存储守护进程)交互,读写文件数据
说明:ceph MDS虽然是单线程的,减少锁交互,但是性能并不高,维护很复杂
分布式锁
mds状态
ceph 并没有统一结构存储 记录 元数据 与MDS分配关系。
而是每个MDS 维护各种边界。
每次重启 时候 不断与 其他MDS交互 获取完整目录树
目录导入 导出导出概念 作为事物 ,各自记录记录 各自日志 。
•
目录可能非常大(比如百万文件),单个 MDS 扛不住。
•
所以 CephFS 把目录拆成多个 frag (片段),不同 frag 可以交给不同 MDS 管理。
目录内容通过目录片段进行分布,可以看到具体的获取方式
目录片段对象命名格式为{dir_ino:x}.00000000
,其中dir_ino
是目录的inode号。
查看名为vdb.1_1.dir(目录下有100万个文件)的目录的inode号为1099511627788,转换为16进制为1000000000C
[root@node2 cephfs]# rados -p cephfs-metadata ls
根目录的inode信息,存放在1.00000000.inode对象当中。
All file data in CephFS is stored as RADOS objects.
CephFS clients can directly
access RADOS to operate on file data.
MDS only handles metadata operations.
文件数据以<inode number>.<object index>
的格式存储为RADOS对象。
•
把文件才做 变成kv操作,
•
然后保证kv操作一致性
元操作利用 FoundationDB 的事务:
•
用于元数据查询的只读事务:fstat、lookup、listdir 等。
•
用于元数据更新的读写事务:创建、链接、取消链接、重命名等。
太复杂了,实现功能太多了,远离他
看一个看
启动过程
CephFS 为了高性能和扩展性,没有用统一的中央数据库来记录元数据与 MDS 的映射。它依赖两点机制:
•
动态子树分区:目录树被切成多个子树,每个子树只由一个 MDS 管理。MDS 会监控访问热度,负载不均时可把子树迁移给其他 MDS。
•
MDS 边界维护:每个活跃 MDS 知道自己负责的子树范围,也大致了解其他 MDS 的边界,从而避免单点瓶颈。
MDS 启动或重启时,需要与其他 MDS 协同,确定目录树分区和职责:
1
加载基础元数据:从 metadata pool 取出根目录等必要信息。
2
加入集群并同步:与 Monitors 和其他 MDS 交换信息,确认自己接管的子树,或进入 Standby 等待。
这就是为什么重启时 MDS 要不断交互,以保证弹性和高可用。
目录子树迁移是 分布式事务,保证一致性:
•
事务操作:目标 MDS 先写“导入中”,源 MDS 再写“导出”,最后目标写“导入完成”。
•
日志独立记录:源、目标及相关 MDS 都会写日志。这样即使故障,也能恢复到一致状态。
•
https://www.ieisystem.com/global/file/2024-08-07/17230245620812c975afc90a667f436001912c4457a16533.pdf
1️⃣ 如果有更多疑问,联系小王,一起交流,进步
2️⃣ 关注公众号:后端开发成长指南(回复"面经"获取)获取过去我全部面试录音和面试复盘。