背景
CFS 是百度智能云文件存储,是一个大规模分布式文件系统。EuroSys'23 CFS论文主要介绍了该系统的元数据核心设计,对长期困扰文件系统元数据领域的Posix兼容性和高扩展性(特别是写扩展性)难以兼顾的问题进行了解答。
为了帮助读者更了解该系统的创新过程,百度存储团队发表了一篇文章《如何将千亿文件放进一个文件系统,EuroSys'23 CFS 论文背后的故事》,从文件系统的概念和需要解决的关键问题说起,非常详细地介绍了设计理念、演进过程。
我们在阅读论文和文章解析的过程中受益匪浅,CFS 跟 Curve 文件系统在设计上有一些理念是相同的,也有很多地方值得 Curve 借鉴、学习。本文的目的是从 CFS 的设计理念出发,对 Curve 做一次回顾,查漏补缺。
关键点解析
元数据服务的架构
//元数据服务的第三阶段:分离式架构,文中提到:分离式架构同样没有解决写扩展性的问题,写延时的表现甚至比耦合式架构更差:
- 事务在架构里的实质作用其实也是一种分布式锁,并没有解决其它分布式锁机制的缺陷,当一个写操作需要多节点参与时,无论是吞吐还是延时的表现都会比较差。
- 分离式架构处理请求时,需要先经过元数据代理层,再到数据库层,比耦合式架构的处理路径要更⻓,因此天然在性能上,特别是延时指标上更具劣势。读请求可以通过客户端直接读数据库层的方法来进行优化,但写请求就没有办法这么处理了。
这一点,之前我们有测试过使用 TiKV 作为元数据引擎,对比 Curve 文件系统原生的引擎,同样发现,使用分布式 KV 在标准测试 mdtest 下的性能并不好,是 Curve 文件系统原生引擎性能的一半。文章在[2.5 对分布式锁性能影响的定量分析中]提到,在没有锁冲突的情况下,锁在整个操作中的耗时占比也达到了 50%+。
NameSpace1.0
namespace1.0其中的一个设计要点是将文件的属性从元数据服务中剥离出来,和文件数据一起放到数据服务器中进行处理。
基于这一理念,元数据的结构如下图所示:
元数据操作需要用到的数据库的能力可以概括为:按照 secondary key 查找指定项,按照 parent\_id list,子项和 parent\_id 的事务操作。Curve 文件系统, 所有信息可以认为都是存储在分布式 KV 上(Curve 文件系统使用 Raft+Rocksdb 作为元数据)的持久化引擎,虽然没有使用数据库作为引擎,但 Curve 文件系统通过一定的放置策略加速上述提到的几个能力,以提高元数据性能:每个数据分片负责一定范围的 inodeid, 所有的 dentry 存放在 parent\_inodeid 所在的分片上。
下面我们来对比下 CFS 和 Curve 文件系统在 lookup 和 readdir 两个读操作:
- lookup /A/B
- Namespace1.0 查找路径:先在中查找 [rootinodeid + filenameA] 的项,获取/A的inodeid;再使用 [/A的inodeid + filenameB] 获取 /A/B 的inode。涉及到两次查表操作。
- Curve 文件系统查找路径:先通过 [rootinodeid + filenameA] 去 rootinodeid 所在的分片上,获取/A的 dentry,解析出 inodeid;再使用[/A的inodeid + filenameB]去 /A所在的 inode 上获取 /A/B的 dentry,解析出对应的 inodeid。同样也是涉及两次 rpc 操作。
- readdir /A
- 在 Namespace1.0 中查找路径:先查找 [rootinodeid + filenameA] 的项,获取 /A的 inodeid,再通过 db 操作,list parentid 为 /A的 inodeid 的所有项。需要经过 db 两次查询操作。
- Curve 文件系统查找路径:通过 [rootinodeid + filenameA] 去 rootinodeid 所在的分片上,获取/A的 dentry,解析出 inodeid;再去[/A的inodeid]所在的分片获取 parentid 为/A的 inodeid 的所有项。同样涉及到两次 rpc 操作。
关于写操作,对比 mknode 和 rename 两个写操作:
- mknode
- Namespace1.0 的操作路径:在 filestore 中写入文件属性的相关信息;将文件的 dentry 信息{parent\_id, name, ...} 插入 TafDB 并修改 parentid的 关联信息,这一步通过 TafDB 的分布式事务能力完成。涉及到两次 rpc 操作。
- Curve 文件系统操作路径:选择一个分片写入文件属性相关信息;将文件 的dentry 信息插入到 parent\_id 所在的分片中,并修改 parent\_id 的 nlink 等属性信息,这一步通过本地的 RocksDB 的事务接口完成。涉及两次 rpc 操作。
- rename
- Namespace1.0 可以直接通过 TafDB 的分布式事务接口完成。
- Curve 文件系统,由于 rename 涉及到删除源文件的 dentry, 在新的 parent\_id 下创建新的 dentry,涉及到多个不同分片上的操作,为此设计了额外的事务处理逻辑。
Namspace2.0
最大的一个优化点在于将分布式锁去除,使用原子变量的操作来替代。能实现这一操作的前提条件是:将冲突缩小到单个分片的范围。(这就是文中说的回到耦合架构,因为DB需要通过key来感知哪些数据需要放在相同的分片中)。这对于rename以外的所有操作都成立。
上一小节说明了 Curve 文件系统的 dentry、inode 放置策略,这个设计也正好符合文中提到的抽象模型:影响元数据服务扩展性的根源是更新父目录属性时产生的冲突,这是关联变更的一部分。这里提到的父目录的属性,指的就是 inode 相关的属性。
但是在工程实践上,Curve 文件系统,对于同一个分片上的请求,是做不到像数据库这样使用同步原语解决。比如,对于 create dentry 的操作,在底层需要执行的操作是:
- 操作1:创建 dentry,在 rocksdb 中插入一条记录
- 操作2:修改父目录的 nlink,并修改 mtime,将新记录插入到 rocksdb 中
在并发情况下,这两个操作是无法通过同步原语的方式解决的,目前只能做到串行操作。这是影响性能非常关键的一点。对于这一点,从上层看从减少父目录的更新次数可以做请求的合并。长期看,提高 partition 上多类操作的并发度是非常必要的,比如一个很常见的 AI 场景,数据集的批量拷贝性能会大大受限。
沿用的NameSpace1.0的设计,关联元数据的存储放在DB中执行,文件属性的存储放在KV中。
这样做的好处是把负载分摊到了两个系统中。另外提到的一点是,如果单个目录下的文件数量很多,
DB的分裂可以保证该记录独占一个分片,最大能有单机处理能力,认为这个处理能力已经够强了。
在单个目录下文件数量过多的场景,Curve 文件系统做不到让它续展一个分片,因为当前分片上负责的 inode 范围是固定的。可以通过针对目录子项过大的情况,让新的 inode 不在创建的方式做兜底,后续也许可以考虑通过增加虚拟目录节点的方式来做迁移。
关于rename,很重要的一点是:根据我们的线上统计,99% 的 rename 都发生在同一个目录内文件间,这种 case 涉及到的变更都在一个 TafDB 分片内,可以采用前文提及的方法优化。
因此,我们将 rename 分为 Fast Path 和 Normal Path 两种。
Curve 文件系统,对 rename 做了两个版本的优化,都是使用的 2PC 事务,第一个版本 rename 在同一个文件系统上是全局排队的,第二个版本 rename 在同一个文件系统上源和目的不同可以并发。并没有考虑到从业务场景做一些优化。在看到上述统计信息的时候,很快就关联到在业务使用中很多时候都是从 rename A.tmp A 这类在同一目录下,为了避免一致性使用临时文件再做 rename 的场景。这也是 Curve 文件系统可以借鉴的 rename 优化途径。另外,我们发现 percolator 这样的事务模型在文件系统这样的场景下略显<笨重>,后续我们考虑使用事务管理器的方式来为一些操作提供原子性保障。
在工程优化上不仅考虑通用优化手段,也结合业务特征进行优化是 Curve 文件系统需要持续改进的部分。
总结
CFS 为性能做了大量设计和工程实践上的优化,我们通过分段解析,也看到了 Curve 文件系统很多可以优化的点,后续会持续跟进,也欢迎感兴趣的小伙伴的加入。如果上述的理解和描述有疏漏或者错误的地方、或者有一些新的想法,都欢迎在 Curve 社区指正和交流。
------ END. ------
🔥 开发者活动:
🔥 用户案例:
Curve 文件存储在 Elasticsearch 冷热数据存储中的应用实践
扬州万方:基于申威平台的 Curve 块存储在高性能和超融合场景下的实践
🔥 技术解析:
Curve v2.7 发布:支持 Hadoop SDK,助力大数据存储降本提效
关于 Curve
Curve 是一款高性能、易运维、云原生的开源分布式存储系统。可应用于主流的云原生基础设施平台:对接 OpenStack 平台为云主机提供高性能块存储服务;对接 Kubernetes 为其提供 RWO、RWX 等类型的持久化存储卷;对接 PolarFS 作为云原生数据库的高性能存储底座,完美支持云原生数据库的存算分离架构。
Curve 亦可作为云存储中间件使用 S3 兼容的对象存储作为数据存储引擎,为公有云用户提供高性价比的共享文件存储。**
- GitHub:https://github.com/opencurve/curve
- 官网:https://opencurve.io/
- 用户论坛:https://ask.opencurve.io/
- 微信群:搜索群助手微信号 OpenCurve\_bot
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。