大家好,我叫彭达,我是买极端的一名公众室很高兴今天为大家介绍一下Fuse用户台文件系统在性能和可靠性上的一些进展今天的内容我们大概会分成四个部分首先我会简单介绍一下Fuse用户台文件系统然后我们会看一下Fuse文件系统的一些性能的问题然后我们会看一下Fuse FD Password这是一个上游对Fuse文件系统性的优化的一个设计和它的效果最后我们会看一下Fuse文件系统的热身机以及Fillover上的一些进展当我们说到Fuse文件系统的时候我们通常都会联想到内核文件系统那Fuse文件系统内核文件系统一般会有什么区别呢我们来看一下首先说到内核文件系统大家经常会看大家会经常会用到和听到的ESD4、XFS、BatteryFS这些然后它们的一个最重要的问题就是它们的性能很好它们相对于Fuse文件系统来说的话它们的性能是会好很多的而用户台文件系统的话我们常见的会有GlusterFS这个在互联网系统互联网公司会有一些使用然后还有ServeMFS这个是Serve大规模使用的一个Fuse文件系统还有如果大家玩去课链的话就前年吧比较火的一个IPFS其实也是一个Fuse文件系统这些Fuse文件系统相对于内核文件系统它的一个最明显的优势就是它们在安全性上可以做很多比如说可以做额外的脚验可以做安全的审计这些工作然后它们的可耗性也会有明显的提升因为在用户台它即使panic了它也不会造成整机的不可用而内核文件系统如果panic的话那一定是carnal panic整台机器都不可用了然后用户台文件系统它还有一些特点就是它的设计会相对的它的实现会相对的简单比那个文件系统实现要简单很多然后它也会因为在用户台更容易去debug也更容易去维护更容易去部署然后我们来看一下Fuse文件系统的一个high-level的架构就是这个图里面下面是用户台下面是内核台就是在所有蓝色的部分就是用户台文件系统本身的一些组件用应用通常会通过possess的机后来发往一个用户台文件系统而在内核VFS会把所有的请求转发给fuse-carnal driver而fuse-carnal driver和用户台的fuse-demon之间会通过fuse-device去通信而这一次通信就是会造成额外的数据考备和额外的三相极幻所以这也是fuse-文件系统性能下定性能相对于内核文件系统性能下降的一个最主要的底而在fuse-demon上我们通常会有不同的后端存储的实现要么去访问一个地理文件系统要么去访问一个远端的存储有的情况下也会有两者的结合就我们刚才说到了fuse-文件系统因为会有一次额外的考备和三相极幻所以我们能够看到在测试中的话fuse-文件系统的性能会相对于内核文件系统会特别是在顺序的写和随机的读写这两种上下会有非常明显的下降而内核社区其实也一直知道这些问题所以会一直有不同的思路来改进这个问题然后最近的一次改进就是来自于Angel Team的一个叫Alexio的一个歌门他提的一个fuse-fuse-fuse-fuse的一个想法这个想法其实他是针对fuse-fuse-文件系统对fuse-文件系统访问本地文件系统的一个通过fuse-文件系统去访问本地文件系统的一个优化这个UseCase在Angel上会用的非常多就是Angel会通过fuse-文件系统在用户台去做额外的审计和全线管理而在这种场景下我们可以把底层文件系统的fighting descriptor把它保存在fuse-fuse-文件系统里面这样下次在用户台去通过posex接口再去反映同样一个文件的时候可以直接在fuse-fuse-文件系统里去反映这些反映后等文件系统而不需要再绕到用户台去绕一圈但是这种操作只对于读写去做这样的优化对于open-close这样的操作这样会在用户台去实现这样的话用户台所有的全线管理和所有的审计上的操作都还是可以在用户台去做这个panchset是发生在main list上有很多人来讨论该都已经发到10轮还是12轮了这个图就简单这是一个干塞fuse-e10 Pasha的简单视野图它的工作流程就是用户台在用户台开放的会一直传导到fuse-demon上去fuse-demon从nD文件选手打开拿到nD的fuse-e10之后会把fuse-d通更 vacation tool写给fuse-device然后保存到Fuse2里同时Open请求到你返回的一个Reply里面也会带着FD对应的一个ID在Fuse kernel driver里会把这个ID和通过这个ID找到本地的FD把这个FD和即将返回给用户的FD这两者之间关联起来这样的话当用户的后面的读写请求发送到FD的时候这个在Fuse driver里能够直接找到后端文件系统的对应的FD然后再直接从内核态去做对后端文件系统做读写然后我们是在MyLab的话是很早的时候就把Penguin Set的BandPort到内部的内核了然后也在推广中然后我们在它的技术上也加了一些新的特性比如说我们给它加了一个Persis Build的Metrics Counter因为这样的Counter因为FuseFD%数它是它的性能很高了很快了但是我们在Label的话Fuse Demon通常我们会做一些Performance的一些监控但是当我们做Persis的时候这些监控就不能在所有的IO都直接通过用户态了不过我通过直接走内核态了不过用户态了这样用户态的那些监控就不可用了所以我们在内核态也做了类似的监控就我们统计的Persis FD的这些它的IOPS它的BPS以及它的延迟的分布然后所有的这些Metrics都是每秒钟会计算一次而延迟的一个目标指是可以是可以通过CCFS去配置的而因为我们使用的是一个Percipule的Metrics Counter所以整个这一套性能的监控对于整体的IO性能是没有任何影响的然后因为我们要在线上用这样一个特性而这个特性是相对比较新的我们也加了一些Forbank的策略比如我们可以对某每一对指定的Fuse Connection把它打开和关闭Fuse Connection的特性这也是通过CCFS的一个机口去做的我们可以看一下Fuse Connection的一个性能的一个测试就从这个图的左边三列我们可以看到左边三列是直接工作在本地文件本地有本地字盘上的是在本地字盘上的NASLA这个是ST4的性能承受的是Fuse AFD帕数的性能我们可以看到稍稍会低一点但是是非常接近的不像没有帕数的时候在随机在顺序写和随机读写的时候会非常的差然后我们也对Fuse AFD帕数做了一些性能的摸高我们把本地文件系统换成了把本地字盘换成了一个TEMPEFS把ST4换成了TEMPEFS工作在内存上这样的话我们也可以看到TEMPEFS的性能也是稍稍高于Fuse AFD帕数的但是也会非常接近Fuse AFD帕数在极限情况下也不会有明显的下方而没有帕数的情况下Fuse AFD的性能就会被压得很死了我们看了Fuse AFD性能之后我们也来看一下Fuse AFD的可靠性就我们通常都会持续一个观点就是Fuse AFD是会比人类和文件系统更可靠的为什么会这么认为其实一个很重要很重要的一面就是我们可以对Fuse Demons在用户态序做日升级和Fillover而内核文件系统目前是主流的文件系统是都不支持这样的特性的然后能够做日升级化Fillover的一个最重要的原因就是Fuse Devices通过Fuse Devices拿到了这些Fuse Connection AFD其实它是对应到内核力的Fuse Connection的只要我们对这个FD做保护不把它关闭掉那这样的话内核态的Fuse Connection也一直会被保留不会被关闭掉然后这是一个最常见的一个FuseFuse Demons日升级和Fillover的一个试试就是在脑袋的Fuse Demons打开了Fuse Devices拿到FD之后会把它保存到一个管理的Demon里面去而新的Fuse Demons会从这个管理Demon里把这个FD拿回来然后通过同样的FD对Fuse Devices去做读写这样的话他们两个Fuse Demons都操作的是同一个Fuse Connection而这个是一个日升级的场景而Fillover其实也是类似就Fillover只是没有中间主动管控的这个切换而是在脑子Fuse Demons突然挂掉的时候新的Fuse Demons被拉起然后从管理的Demon里面通过Unix Domesticated Send FD这样的一个接口去把Fuse Connection FD拿回来然后去做一些状态的恢复然后来对Fuse Devices去做读写而我们能够看到在这样一个设计和价格里面的话这个管理的Demon的角色就非常重要的它其实是承担了一个Fuse Connection FD保护的一个指责而这样一个Demon通常来说就是设计在高可用系统里面的一个单点而我们针对这个问题会有一些进一步的优化就是首先我们想到的就是既然这个单点那我们把它放到一有的单点里那就是Color里Color就是我们把Color作为这样一个单点然后如果Color Panic来的话那其实整体都已经不可用了那也不存在说单点失败然后造成热身机和Failover失败的这样一个问题所以我们在Color里面做给Fuse Driver做的一个通用的一个FD Storage这个FD Storage它其实它的指责和Fuse管理的Demon一样就是做FD的保护但是它是一个通用的保护机制就是你一个用户态的程序可以把任意的FD放到FD Storage里面去保护而这个FD所谓保护的FD它的Life Cycle是绑定到Fuse Connection上的一旦对应的Fuse Connection被释放了那说被保护的这些FD都会被关闭掉这个叛徙也发送到上游的Main List里面在引起了很多的讨论这个图就是我们可以看就是在我们有这样一个通用的FuseFD Storage的一个情况下我们去做热身机和Failover的一个视频图就整体的架构流程其实跟刚才那样但整体的架构就比刚才要清爽的很多因为没有额外的管理的DEMON在那里作为FD保护的一个角色了而这样一个通用的FD Store也可以提供给刚才我们提到FD Password的场景其实它用的它就是放在这整体的流程也是一样的但唯一的差别就是刚才的Fuse刚才的Fuse DEMON需要通过专门的PASSWORD的I will control去和Fuse DFS去交互去保存这样一个Local FD而在有一个通用的FD Store的情况下的话它就会用通用的接口来保存这个FD但整体的流程是一样的我们在上游和Elector的讨论中Elector也是非常赞同这样一个设计然后愿意把FD PASSWORD的设计实现放到基于这个区域去做我们刚才讲的都是一些比较high level的我们后面会更细节的去看一下Fuse内核的一些设计这个是Fuse内核的主要的数据结构的一个试试图就是在Fuse内核里面有个全局的Fuse Connection的一个列表这个列表会保存所有的Fuse Connection一个Fuse Connection其实对应的就是一个Fuse的MountSuperblock或者是Mount Point对于这而每一个Fuse的Connection其实它可以Fuse在内核里的数据结构其实非常灵活的它每一个Fuse Connection它其实可以提供给有不同的Fuse Device去指向而这些Fuse Device的意思其实是它是提供给用户态去做Fuse Device读写的而Fuse Device读写而Fuse Device本身又可以被不同的Fuse ConnectionFD去指向这样的话我们可以看到首先我们可以用不同的FD去指向同一个Fuse Device然后这样来操作同一个Fuse Connection我们也可以用不同的Fuse不同的FD指向不同的Fuse Device然后它也可以去操作同一个Fuse Connection这样其实在Fuse整体的拥护态的Fuse Demon和Fuse Connection之间的印车关系上是一个非常灵活的一个设计而另外一个我们需要关注的一个点就是在每个Fuse Connection里面它会有一个Pending Queue这个Pending Queue会保存所有的需要发送给用户态的这些Fuse请求然后在每个Fuse Device上面还有一些Processing Queue这些Processing Queue就是所有的用户态的FD从Fuse Device里面去读读到用户态正在去处理的这些请求而在Fuse Device里面还有一个Ivo Queue这个Ivo Queue就是所有的正在被读的这些Fuse请求就是正在从内核态被拷背到用户态的这些Fuse请求而基于刚才的我们刚才讲的那些讲的这个数据结构基于这样的数据结构我们其实可以对Fuse的设计做更进一步的优化比如说我们可以给Fuse给每一个Fuse的Bound Point加一个FS Tank这个Tank其实和VerticeFS的那个FS Tank是类似的用每一个Tank会唯一的去标识一个Fuse的Connection而这个仕度其实是基于现有的Fuse的Fuse的还有一个Clone的I'llCtrl去做的这个Clone I'llCtrl它的一个目标就是去让不同的让不同的FuseFD都可以工作在同一个FuseConnection上就是我们刚才我们在这说的不同的FD当我们用不同的FD指向不同的FuseDevices的时候这些FuseDevices还是可以工作在同一个FuseConnection上面去的而基于这样一个设计我们可以实现一个更紧易的一个热生机的机制就是我们增加一个新的I'llCtrl叫Attention这个Tank它做的事情是它去通过这个FS Tank去找到FuseConnection然后在这个FuseConnection就找到这个FuseConnection在FuseConnection上去创建一个新的FuseDevice同时把这个新的FuseDevice Attention给一个新的FuseFD然后在这样的话我们就可以我们其实就大致在这位置我们就有一个新的FuseDevice指向同一个FuseConnection而我们把这个FuseDevice和这个在我们做Failover和热生机的时候其实这一步的时候我们就已经可以做热生机了因为这样一个FuseDevice和这样一个和这里的FuseDevice没有任何差别它这里的琴球一旦处理完之后所有的琴所有的琴球通过这个FuseDevice去处理所以FuseConnection上的琴球通过这个FuseDevice去处理都没有任何问题而我们在在做Failover的时候就会有一个点就是在做Failover的时候当FuseDevice Panic的时候FuseConnection会把FuseConnection里面的这个Connection的这个布尔值把它追foss所以我们我们在做Failover通过这种机制做Failover的时候我们会去sit一下FuseConnection把这个把把他所有的这个Connection的这个Failover把它制为处所以制为处之后我们还需要去出手化去发送一个FuseInit的琴球发送给FuseDevice这样FuseDevice还是走最初最开始的Mount他他认为他是做的最开始的Mount然后做做了所有的在用户在做做所有的做所有的出手化同时那时候他也做对应了那个FuseInitReply的那些所有的出手化做做到这些之后我们能够实现那个效果就是通过这样一个I'llCtrl我们创建了一个新的FuseFD同时把它attanch给的一个新的创建了一个新的FuseDevice同时把它attanch给的一个新的一个新的FuseDevice而而这个新的FuseDevice可以通过这个FuseDevice继续对这个FuseConnection做所有的操作这就是我们在Fuse做生机和FuseOver上做的一个改进然后可能说到这的话大家可能会想就是FuseOver的时候当Fuse用FuseServer Panic的时候那些正在被拷贝和正在被处理的在用户态的那些事情又会怎么办呢就我们刚才提到了在FuseConnection里面会有三个Q就首先是有个PanicQ是保存的所有的遗迹需要被发送到用户态的所有的Fuse请求然后会有个LQ是所有正在被拷贝的Fuse请求还有一个ProcessingQ这个是所有的正在被用户态处理的这些请求然后我们在Fuse内核里我们给它增加了一个Ccfs的接口让Fuse内核能够在用户态Panic之后用户态会告诉Fuse内核把这LQ和ProcessingQ里面的东西全部把它又填回到PanningQ这里需要注意一下填的顺序但是这个还是这个也是其次的问题但是这里主要的设计就是把所有的请求因为这些请求其实只要没有没有被处理完它就一定要么在LQ上要么在ProcessingQ上要么在PanningQ上然后我们把所有的正在被拷贝的和正在被处理的这些请求又把它填回到PanningQ然后再用户态下次去读FuseDevice的时候它就会把这个Q里面的请求就重新处理一遍然后这样一个设计就是它的一个好处是对于止毒的温泉系统它就直接可以工作了因为止毒的温泉系统它不会有任何的非密等的操作这样的话所有的请求在用户只要在OneSpeedFuse一继续之后所有的请求都是可以被不断的去不断地去尘释的用户它也没有不会出现任何问题而对于可写的Fuse文件系统它的处理会更麻烦一点点就是在用户态Demon上面需要去对所有的非密的人的操作去把它做持久化这个操作完成了没有如果没有完成的话它需要保存它当前的状态它到底是已经对本已经造成了一些持久化的变动了还是说没有造成这些持久化的变动同时哪些请求哪些Fuse每个Fuse请求都是带了带了一个请求哪些请求是处理过的哪些请求没有处理过然后当用户当内核态发送那些处理过的请求的时候可以直接跳过去把之前的Replay发送给内核OK我们最后我们来回顾一下我们今天聊到一些内容就是首先我们我们讲了这么多我们其实最大一个观点就是内核用户台文件系统也可以是非常的健壮和性能高效的而我们怎么能够做到这些呢首先就是我们会可以用Fuse FD PASU来实现一个高性能的高性能的L其次的话我们通过通用的FD Store来让Fuse的Fuse Connect性能管理变得更简单同时我们最后我们介绍了我们在我们增加的Fuse FS Tank和请求请求请求重发的这两个机制然后让我们整个的Fuse文件系统的可靠性变得非常高了我们在我们内部基于这些东西我们在内部Fuse文件系统的现在用的量就已经是非常大在线上然后今天的内容就是这些我会实施的在线上回答回答大家的问题