女主宣言
今天小编为大家分享用户空间文件系统FUSE,文章从FUSE的架构,分析了各个部分的原理,并结合小编自身的使用,对FUSE进行了建议性的优化,希望能对大家有所帮助。
PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!
1
简介
1.1 环境
本文所有的分析和操作都在下面的环境中完成:
类别 | 版本 |
---|---|
操作系统 | CentOS Linux release 7.6.1810 (Core) |
内核版本 | 3.10.0-862.2.3.el7.x86_64 |
libfuse版本 | libcurl-7.29.0-57 |
1.2 FUSE
Linux内核从2.6.14开始支持用户空间文件系统,即FUSE(Filesystem in Userspace),与之对应的是内核文件系统,区别在于,FUSE除了能够使用普通用户进行挂载外,文件系统的元数据和数据操作也都是由用户空间的进程来实现,并且能够使用内核文件系统的接口进行访问;FUSE的引入极大的方便了文件系统的开发和调试,相对于复杂的内核文件系统,无需编写任何内核代码,无需重新编译内核,维护上也由此变得简单,因此开源的文件系统都会使用FUSE来支持POSIX协议,比如CephFS、GlusterFS、ZFS、sshfs、mailfs等。除了类Unix系统外,windows下的FUSE实现叫Dokan,提供的接口和FUSE相同,这使得开发跨平台文件系统变得简单。为了方便文件系统的开发,除了libfuse提供的C,C++接口,社区也有相应的库支持JAVA、Go、Python等编程语言的绑定。使用FUSE也并非没有缺点,其在用户空间和内核空间的多次交换造成的性能问题一直为人所诟病。综上所述,FUSE主要有以下特性:
能够使用普通用户进行挂载;
文件系统运行于用户空间;
方便开发、调试、安装和维护;
多平台支持;
用户空间接口的多编程语言支持;
性能比内核文件系统差;
2
架构
为了能够使用和内核文件系统相同的接口,以及方便用户空间文件系统的开发和维护,FUSE在内核空间和用户空间都具有相应的实现,主要由三个部分组成:
内核模块(fuse.ko):和VFS进行交互,它和普通的文件系统模块一致,只是不会处理实际的文件系统调用,而是将其进行封装为特定格式的fuse请求后发送给用户空间进程,等待用户空间进程处理完成并返回,接收处理返回结果转换为内核文件系统格式后再传递给VFS。
用户空间库(libfuse.\*):负责和内核模块进行通信,接收来自内核模块的请求并将结果写回内核模块。
挂载工具(fusermount):实现普通用户对文件系统挂载和卸载。
如上图所示,当应用程序在挂载点进行操作的时,IO路径分为以下几步:
应用程序在挂载点进行系统调用;
系统调用进入VFS并最终由FUSE内核模块进行处理;
FUSE内核模块将系统调用进行封装后发送给用户空间进程;
用户空间进程将请求进行处理完成后发送给FUSE内核模块;
FUSE内核模块解析请求返回并由VFS返回给应用程序;
以上可以看出,在这个IO过程中,会存在四次的用户态和内核态的切换,在具有高吞吐、高并发、低延迟需求的应用中,这样的开销是无法忍受的,这也是FUSE相对于内核文件系统存在性能问题的原因所在;
3
内核模块
3.1 内核模块加载
使用FUSE需要内核的支持,可以使用insmod或modprobe命令进行内核模块的加载:
# modprobe fuse# modinfo fusefilename: /lib/modules/3.10.0-862.2.3.el7.x86_64/kernel/fs/fuse/fuse.ko.xzalias: devname:fusealias: char-major-10-229alias: fs-fuseblkalias: fs-fuselicense: GPLdescription: Filesystem in Userspaceauthor: Miklos Szeredi alias: fs-fusectlretpoline: Yrhelversion: 7.5...
fuse内核模块初始化(fuse/inode.c: fuse_init())主要有以下四个过程过程:
fuse_fs_init:创建fuse_inode高速缓存,并注册类型为fuse的文件系统
# cat /proc/filesystems |