书接上回:
原文排班更佳:https://mp.weixin.qq.com/s/QdhOqdcIhuVStjfB3QgP5A
从零实现分布式文件系统(二) 如何在不升级硬件的前提下,小文件并发读写性能提升十倍
C++周刊系统设篇 目标:
知识地图:
一页 ppt 汇报:
参考:陈道碧_DDN 持续支持 Lustre 社区发展
SFA200NVX2E机型
关键数据一致性验证
参数 | SFA200NVX2E(原始值) | SFA400NVX2E(升级验证) | 逻辑关系 |
---|---|---|---|
单NVMe SSD带宽 | 2 GB/s (读) ×24盘 | PCIe 5.0单盘≈14 GB/s | ✅ 合理 |
总读带宽 | 48 GB/s | ≥80 GB/s | ✅ 翻倍提升 |
网卡限制 vs 需求带宽 | 25 GB/s << 48 GB/s | 50 GB/s ≥ 80 GB/s* | SFA400需多链路聚合 |
注:SFA400NVX2E 的80GB/s带宽需依赖多网卡负载均衡(如4×200Gb EDR = 100GB/s理论值)。
为什么Lustre文件系统 性能随着 服务器增加不断扩展,
客户端的增加而增长?这个不符合常理,
例如单机下无能无限增加线程个数?
Client 节点
+----------------------+
| Lustre Client 驱动 |
+----------------------+
│
┌───────┴─────────┐
│ │
元数据面 数据面
│ │
+--------+ +--------+
| MDS | | OSS | ← 两类 Lustre 进程
+--------+ +--------+
│ │
+--------+ +--------+
| MDT | | OST | ← 磁盘卷(Targets)
+--------+ +--------+
组件 | 功能与说明 |
---|---|
Client | 提供用户访问接口,支持 POSIX 文件语义,与 OSS/MDS 通信 |
LNet | 网络通信层,支持高吞吐与 RDMA,连接所有 Lustre 架构节点 |
MGS + MGT | 系统配置中心,负责节点启动和配置同步 |
MDS + MDT | 管理文件系统命名空间和元数据,只在打开等元操作时被访问 |
OSS + OST | 存储实际文件数据,处理高并发 I/O,并可扩展横向容量与性能 |
层面 | 管理者(Server) | 存储目标(Target) | 数量关系 | 是否独立进程 |
---|---|---|---|---|
元数据 | MDS 进程 | MDT 磁盘卷 | 通常 1:1,可通过 DNE 扩展到 1:N | MDS 是进程,MDT 是磁盘卷 |
数据 | OSS 进程 | OST 磁盘卷 | 通常 1:N,典型一台 OSS 挂 4-16 个 OST | OSS 是进程,OST 是磁盘卷 |
Lustre 的数据读写路径由 Object Storage Server (OSS) 和 Object Storage Target (OST) 共同完成。
角色 | 类型 | 部署形态 | 功能 |
---|---|---|---|
OSS | 进程 | 运行在服务器上 | 接收客户端 I/O 请求,将其映射到 OST |
OST | 磁盘卷(target) | 通常是挂载在 OSS 上的一块文件系统 | 存储实际的数据对象 |
lustre
核心模块的一部分,负责协议处理。并发优化undefined每个 OST 独立处理 I/O,客户端可并行访问多个 OST,因此 Lustre 能横向扩展读写性能。
2. MDS + MDT:元数据面
元数据操作由 Metadata Server (MDS) 和 Metadata Target (MDT) 完成。
角色 | 类型 | 部署形态 | 功能 |
---|---|---|---|
MDS | 进程 | 运行在元数据服务器上 | 处理目录操作、文件名、inode、权限等 |
MDT | 磁盘卷(target) | 挂载在 MDS 上的元数据存储卷 | 存储 inode、dentry、ACL 等元数据信息 |
直观理解:HPC 实例
例如 DDN EXAScaler(DDN 商业化 Lustre):
如果客户端也有足够多计算节点,整个系统总吞吐量可以接近线性扩展
Lustre 性能随服务器和客户端数增加而扩展,原因在于:
为什么 Lustre 性能能随服务器与客户端线性扩展,而 Ceph 不一定
困惑:
你觉得 Ceph 一个文件被切成多个对象,这些对象分散在不同的 PG,不同的 OSD 上,所以理论上不是应该可以并行读写吗?
答案是:可以并行,但并行度和 Lustre 的架构比起来有本质差异,并不是“自动无限扩展”,原因主要在于 条带化 vs. 对象分布策略。
1. Ceph:文件 → RADOS 对象 → PG → OSD
文件大小 / 对象大小
例子
假设你有一个 1TB 的大文件:
因此,如果应用不显式多线程并行读写,性能不会线性扩展。
2. Lustre:文件 → 条带化 → OST → OSS
Lustre 的核心是 条带化(striping):
例子
同样是 1TB 文件:
3. Ceph vs Lustre 的关键区别
对比点 | Ceph | Lustre |
---|---|---|
数据分布 | 文件 → 对象 → PG → OSD | 文件 → 条带 → OST |
单对象并行 | 不支持,一个对象只落一个 OSD | 支持,单文件的条带跨多个 OST |
并行度 | = 文件对象数 / 应用线程数 | = 条带数 × OSS 数量 |
客户端自动并行 | 不会,应用需显式多线程 | Lustre 客户端自动并行 |
典型应用 | 大量小对象存储、云存储、虚拟化盘 | HPC、大文件高吞吐 |
总结一句话:
Ceph 的并行度是“对象级”的,而 Lustre 的并行度是“条带级”的undefined如果应用本身是顺序访问,Ceph 并行度低,而 Lustre 即使单线程也能自动并行调度。 “Ceph 一个文件多个对象,多个对象落在不同 PG 组里,这不是并行吗?”
关键点在于 Ceph 的对象切分 和 条带化(striping) 是两回事,但它们又能叠加在一起。
我们一步一步拆开来看,并举例对比 不开启 striping 和 开启 striping 的差异。
1. Ceph 默认的对象切分(Object Splitting)
在 Ceph 中,每个 RADOS 存储池(pool)会有一个 对象大小上限(通常是 4MB 或 8MB,默认 4MB)。
当你写入一个大文件,比如 1GB,Ceph 会自动把它切分成多个 对象(Object):
🔹 效果:
2. 开启条带化(Striping)
条带化是 在对象内部再切片,目的是让单个大对象的内容跨 OSD 分布,从而进一步提升并行读写性能。
它由 librados 和 CephFS / RBD 提供,核心配置有两个参数:
2.1 举例:不开启 striping
假设:
📌 写 4MB 对象时,只能走 单 OSD 单线程,无并行。
并行度 = 对象数量,与 对象大小强相关。
开启 striping**
假设:
📌 优势:
3. 为什么条带化有用
如果文件足够大,且对象大小设置得小(比如 4MB),不开启 striping 也能获得不错的并行度,因为会有很多对象。
但如果场景是:
这时不开启条带化,单对象性能会被单 OSD 限制,开启 striping 后则能并行。
特性 | 不开启 striping | 开启 striping |
---|---|---|
大文件切分 | 按 对象大小切 | 先按对象切,再对象内部切条带 |
单对象落点 | 单个对象只在 1 个 OSD | 单对象内部跨 多个 OSD |
并行度 | ≈ 对象数量 | ≈ 对象数量 × 条带数 |
适用场景 | 小文件多、默认场景 | 大文件少、追求单文件高带宽 |
5回答你的疑问
“Ceph 一个文件多个对象,多个对象落在不同 PG → 这不是并行吗?”
是并行,但并行度受限于对象数量。
如果:
场景 | 是否条带化 | 单对象大小 | 并行度 | 单文件读写速度 |
---|---|---|---|---|
默认 | 否 | 4MB | 1 OSD | ~1× OSD 带宽 |
条带化 | 是 | 1MB | 8 OSD | ~8× OSD 带宽 |
所以,条带化的意义是:
机型 | 类型 | 厂商 | 文件系统 | 单节点聚合带宽 | 元数据OPS(估算) | 关键配置 |
---|---|---|---|---|---|---|
ESS 3500 | 全闪 | IBM | GPFS | 读:80 GB/s 写:52 GB/s | ≥1.5M | 双控双路,24×NVMe SSD |
ESS 3500 | 混闪 | IBM | GPFS | 读:43.2 GB/s 写:29.7 GB/s | 80K–120K | 1×ESS 3500 + 4×4U102磁盘柜 |
来源:https://www.ibm.com/cn-zh/products/storage-scale-system
规格 | Storage Scale System 3500 | Storage Scale System 6000 |
---|---|---|
尺寸 | 2U | 4U |
支持驱动器 | 24 × 30.72 TB TLC NVMe | 24 × 61.44 TB QLC + 24 × 30.72 TB TLC NVMe 或 48 × 30.72 TB TLC NVMe 或 48 × 38.4 TB FCM |
最大原始容量 | 737.28 TB | 2,211.84 TB(混合 QLC + TLC) |
最大吞吐量 | 126 GB/s | 330 GB/s |
扩展 | 多达 4 个直连 JBOD | 多达 9 个直连 JBOD |
数据传输接口 | 12 GB SAS | 24 GB SAS |
简单理解:
架构核心思想:并行化一切可以并行的操作,尽可能消除数据从应用到磁盘之间的等待。
节点 | 小白比喻 | 功能 |
---|---|---|
计算节点 | 工人 | 处理客户端请求,执行逻辑 |
IO节点 | 仓库管理员 | 读写文件和元数据 |
存储节点(Disk/NSD) | 仓库 | 存放数据块 |
管理节点 | 厂长/调度员 | 管理集群、分配任务、控制一致性 |
分工明确 → 避免冲突 → 并发更高
比喻:订单表(元数据)+ 货物(数据),大家同时查表取货 → 整体效率高
机制 | 功能 |
---|---|
分布式磁盘访问 | 所有节点直接访问存储块,利用磁盘带宽 |
并行数据 IO | 多个 IO 节点同时读写,提高吞吐量 |
一致性控制(Token) | 多节点操作同一文件时保证一致性 |
去中心化管理 | 任意节点都能管理集群,消除中央瓶颈 |
GPFS 管理文件元数据(如文件名、inode号)的核心思想是:将目录变成一个高效的“字典”,而不是一个“名单”。无论目录里有一个文件还是一百万个文件,它都能让你用接近恒定的速度找到目标。
目录 Inode:元数据的“总目录”
在 GPFS 中,每个目录本身也是一个特殊的文件(sparse file)。这个文件里存储的不是普通数据,而是该目录下所有文件和子目录的条目(entries)。
目录变大怎么办?—— “扩展附录”
当一个目录下的文件超过128个,4KB的“目录页”不够写了怎么办?
GPFS 的做法是:分配额外的存储块(Block)来存放多出来的条目,并在目录 inode 中通过间接指针(Indirect) 来指向这些块。
这些被分配出来的块,专门用于存放元数据,因此被称为 子元数据块(Sub Metablock)。每个 Sub Metablock 的大小是 8KB。
现在,目录的条目可能分散在多个 Sub Metablock 中。如何在上百万个条目中快速找到一个文件,而不用逐个扫描?GPFS 的答案是:可扩展哈希(Extendible Hashing)。
工作原理如下:
myfile.txt
)时,GPFS 会先计算文件名的哈希值(一个数字指纹)。最精妙之处在于“可扩展”(动态扩容):
通过这种设计,GPFS 的元数据管理实现了:
机制 | 实现方式 | 带来的优势 |
---|---|---|
结构化存储 | 目录作为稀疏文件,使用 inode + Indirect块 + Sub Metablock | 元数据存储清晰、可扩展 |
高速查找 | 可扩展哈希算法 | 查找速度恒定,不受目录大小影响(百万文件与千文件速度相当) |
动态扩容 | 按需分配 Sub Metablock,哈希地址位动态扩展 | 扩容平滑,性能无抖动 |
因此,GPFS 能够轻松应对超大规模、海量文件的场景(如AI训练、气象分析、基因测序),
这正是其作为顶级企业级文件系统的核心竞争力之一。
换句话说,目录扩容只是“让指针表更大”,而实际存储的数据不动
假设全局深度 d=2
,目录有 4 个指针:
00 -> 桶 A
01 -> 桶 B
10 -> 桶 B
11 -> 桶 C
k = 2
(等于全局深度 d)000 -> 桶 A
001 -> 桶 A
010 -> 桶 B (之前指针复制)
011 -> 桶 B (之前指针复制)
100 -> 桶 B
101 -> 桶 B
110 -> 桶 C
111 -> 桶 C
关键点:只有满的桶的数据才会移动,其余桶不受影响
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。