今年存储顶会(FAST ’21)的best paper题为High Velocity Kernel File Systems with Bento,提出了Bento这一可以用Rust写内核态文件系统的开发框架。
论文亮点
亮点1:Rust语言,更少的bug
以Rust语言进行开发更安全,论文作者为了证明这点,统计了2014年到2018年3个比较新的内核模块在Rust所擅长的三个方面(内存、并发和错误处理)所修复的bug分布:
Rust可以在编译阶段就避免上述大部分的bug,因此可以让新的内核文件系统更稳定。
亮点2:更快的开发速度
存储硬件设备发展是很快的,比如持久性内存、更高速的NVMe SSD或者特定用途的SSD(如KVSSD、smartSSD)等,当今的内核FS迭代开发速度是远远跟不上新硬件的速度的;云服务厂商往往会对FS产生各种新的需求,比如有对FS信息追踪等需求,普通的系统跟踪工具不够用,需要对文件系统进行扩展开发,而文件系统处于内核层次,开发效率较低。
本文主要就是为了解决内核文件系统开发速度的问题,文章题目中的High Velocity也是指的开发速度更快,而非性能更高。作者的假设服务的是一些比较急的内核开发者,而不是FUSE、eBPF这样可能不信任的开发者。之所以开发快,是因为BentoFS框架开发的文件系统,也可以编译为FUSE daemon运行于用户态,而用户态程序更方便调试和测试,能够加快开发速度。
亮点3:一套代码多种环境部署
除了上述作者所强调的开发速度和Rust语言安全性,个人认为同一套程序可以同时在User和Kernel编译还有另一个好处:就是用户可以选择把这个文件系统部署在用户态还是内核态,可以根据不同场景,比如对性能的不同需求、对系统权限的掌控程度等灵活选择不同部署方式。
这种支持将代码运行于更方便调试的运行环境的做法,笔者在另一篇paper LeapIO[2]中也见到过,论文说 LeadIO既可以运行到smartNIC上,也可以运行在一个模拟smartNIC的host上的虚拟机中,这就方便了调试和部署。
另外,众所周知,在bypass内核的大势下,很多内核栈现在都会有用户态的代替品,比如用户态网络栈DPDK、存储栈SPDK等;再以虚拟化为例,同样存在vhost-user-net和vhost-kernel-net的实现……
Bento架构
论文作者也开源了代码 [3],我在下图中对论文的图1进行了扩展,加入了用户态部署的虚线路径。
组件介绍:
-
BentoFS(C,基于kernel FUSE driver):作者基于现有的FUSE driver,实现了C语言的BentoFS driver,BentoFS driver会管理基于bento的文件系统的挂载和热升级;
-
libBentoFS(Rust):用于将Rust的bento文件系统的FUSE-lowlevel接口暴露给C语言的BentoFS driver,因此文件系统编译时需要链接这个库;如上图我补充的用户态路径部分,论文作者也调用fuse-rs库开发了libBentoFS的用户态对应版本,我起名叫libBentoFS-user,来保证同一套代码可以很方便地编译成一个FUSE daemon。
-
libBentoKS(Rust):基于Bento框架的文件系统是需要用Rust写的,但是内核服务却都是用C语言写的,因此,作者将很多内核服务(比如锁、内存分配、日志系统JBD2等Rust看来unsafe的内核服务都封装成了safe的Rust接口),因此文件系统编译时也需要链接libBentoKS这个库;论文作者同样实现了用户态的对应封装,我在上图中起名叫libBentoKS-user。
-
热升级模块:热升级的思路是基于读写锁,升级请求会拿写锁,普通文件操作请求会拿读锁,所以升级请求拿到锁时一定保证其他inflight文件请求处理结束了;论文作者的实现中,用户态的编译不支持热升级。
读后思考
Bento是对FUSE性能的优化
用户态文件系统算是最近研究的一个热点,但是人们用户态文件系统的需求其实分文两个截然不同的方向:
- 方向1——性能:不论网络还是存储,近几年都流行bypass内核来提升性能,尤其近年兴起的用于服务器的持久性内存条(persistent memory, pmem, nvm)有很高的性能,内核/用户态的切换已经成为pmem文件系统的性能瓶颈,所以很多人研究基于lib的或者lib和kernel混合的pmem文件系统。
- 方向2——敏捷:是人们想开发新的文件系统时,经常不想把一个新开发的、频繁更改的文件系统编译为内核模块:这一方面是因为内核相对用户程序更要求稳定,另一方面是因为内核代码通常不容易合入社区,后续的更改也更加麻烦、合入周期长。因此就有了FUSE这类文件系统,将文件系统实现为一个用户态daemon,内核已有的FUSE driver会把文件请求转发到指定的FUSE用户态daemon,文件系统的逻辑就可以都实现在daemon中了。
这两个方向虽然都称为用户态文件系统,但所追求的正好是比较冲突的,一般性能比较好的形式,都不容易开发迭代和部署。比如方向1的”libFS“需要和应用一起编译或者以LD_PRELOAD的形式进行链接,和应用绑定更紧,不适合维护和升级;次之,传统的基于Linux VFS的内核文件系统则在性能和敏捷程度居中;FUSE则需要更多次内核-用户切换和更多cache层次控制,性能更差。
Bento是站在方向2的角度,希望在方便开发新文件系统的同时,达到和普通内核文件系统的性能,论文的思路和测试结果也标明基于bento的文件系统可以达到类似内核ext4的性能。
真正代替FUSE还需要很多扩展
不过,很多FUSE文件系统依赖很多高层次用户态库,而论文原型的libBentoKS只支持比较基本的内核服务封装。比如存储方面,libBentoKS只封装了块设备读写接口,但很多FUSE文件系统是会再去访问本地ext4等其他文件系统,因此libBentoKS需要封装内核文件系统接口才可以满足这种需求;另外网络方面,libBentoKS只封装了基本的内核socket接口,没有封装类似NFS常用的RPC通信接口,所以若需要开发的文件系统涉及的网络功能比较复杂,还是需要用Rust对网路功能进行大量开发,或者需要在libBentoKS中封装RPC等更高层次的网络接口。
[1] Miller, Samantha, et al. "High Velocity Kernel File Systems with Bento." 19th USENIX Conference on File and Storage Technologies (FAST 21). 2021.
[2] Li, Huaicheng, et al. "Leapio: Efficient and portable virtual nvme storage on arm socs." Proceedings of the Twenty-Fifth International Conference on Architectural Support for Programming Languages and Operating Systems. 2020.
[3] https://gitlab.cs.washington.edu/sm237/bento