NFS Ganesha 分层架构图
Ganesha 是一个基于模块的程序,每个模块都负责各自的任务和目标。开发团队在写代码之前就对每个模块进行了精心的设计,保证了后期扩展的便捷性。比如缓存管理模块只负责管理缓存,任何在缓存管理模块上做出的更改不能影响其他模块。这么做大大减少了每个模块间的耦合。每个模块可以独立交给不同开发人员来进行开发、验证和测试。
NFSs-Ganesha 通过FSAL(文件系统抽象层)将一个后端存储抽象成一个统一的API,提供给Ganesha服务端,然后通过NFS协议将其挂载到客户端。在客户端上对挂出来的空间进行操作。
(1)Memory Manager(内存管理): 负责Ganesha的内存管理。
内存管理是开发Ganesha时比较大的问题,因为大多数Ganesha架构中的所有模块都必须执行动态内存分配。 例如,管理NFS请求的线程可能需要分配用于存储所请求结果的缓冲器。 如果使用常规的LibC malloc / free调用,则存在内存碎片的风险,因为某些模块将分配大的缓冲区,而其他模块将使用较小的缓冲区。 这可能导致程序使用的部分内存被交换到磁盘,性能会迅速下降的情况。
因此Ganesha有一个自己的内存管理器,来给各个线程分配需要的内存。内存管理器使用了Buddy Malloc algorithm,和内核使用的内存分配是一样的。内存分配器中调用了madvise来管束Linux内存管理器不要移动相关页。其会向Linux申请一大块内存来保持高性能表现。
Ganesha给每一个线程分配了单独的资源,这样也要求每个线程自己处理垃圾回收,并且定期重新组合它的资源。同时”dispatcher thread”提供了一些机制来防止太多线程在同一时间执行垃圾回收;在缓存层中垃圾回收被分成好几个步骤,每个步骤由单独代理处理。
(2)RPCSEC_GSS:负责使用RPCSEC_GSS的数据传输,通常使用krb5, SPKM3或LIPKEY来管理安全。
(3)NFS协议模块:负责NFS消息结构的管理
(4)Metadata(Inode)Cache: 负责元数据缓存管理
Ganesha使用了大片内存用于建立元数据和数据缓存。metadata cache存放在Cache Inode Layer(MDCache Layer)层 。每个实例对应一个命名空间中的实例(文件,符号链接,目录)。这些Cache Inode Layer中的实例对应一个FSAL中的对象,把从FSAL中读取到的对象结构映射在内存中。Cache Inode Layer将元数据与对应FSAL对象handle放入哈希表中,用来关联条目。
实例的属性会在一定的时间(可定义)后过期,过期后该实例将会在内存中删除。每个线程有一个LRU(Least Recently Used) 列表,每个缓存实例只能存在于1个线程的LRU中,如果某个线程获得了某个实例,将会要求原线程在LRU列表中释放对应条目。
每个线程需要自己负责垃圾回收,当垃圾回收开始时,线程将从LRU列表上最旧的条目开始执行。 然后使用特定的垃圾策略来决定是否保存或清除条目。由于元数据缓存应该非常大(高达数百万条目),因此占满分配内存的90%(高位)之前不会发生垃圾回收。Ganesha尽可能多得将FSAL对象放入缓存的‘树型拓扑’中,其中节点代表目录,叶子可代表文件和符号链接;叶子的垃圾回收要早于节点,当节点中没有叶子时才会做垃圾回收。
(5)File Content Cache:负责数据缓存管理
File Content Cache数据缓存并不是独立于与Inode Cache,一个对象的元数据缓存和数据缓存会一一对应(数据缓存是元数据缓存的‘子缓存’),从而避免了缓存不统一的情况。文件内容会被缓存至本地文件系统的专用目录中,一个数据缓存实例会对应2个文件:索引文件和数据文件。数据文件等同于被缓存的文件。索引文件中包含了元数据信息,其中包含了对重要的FSAL handle。索引文件主要用于重建数据缓存,当服务器端崩溃后没有干净地清掉缓存时,FSAL handle会读取索引文件中的信息来重建元数据缓存,并将其指向数据文件,用以重建数据缓存实例。
当缓存不足时,worker thread(见2、大型多线程守护程序)会查看LRU列表中很久未被打开的实例,然后开始做元数据缓存回收。当元数据缓存回收开始时,数据缓存的垃圾回收也会同时进行:在回收文件缓存实例时,元数据缓存会问询数据缓存是否认识该文件实例,如果不认识则代表该数据缓存已经无效,则元数据回收正常进行,并完成实例缓存回收;如果认识,对应的文件缓存以及数据缓存均会被回收,随后对应的元数据缓存也会被回收。这样保证了一个数据缓存有效的实例不会被回收。
(6)File System Abstraction Layer(FSAL):
非常重要的模块,通过一个接口来完成对命名空间的访问,所访问的对象随后会放置在inode cache和file content cache中。
FSAL本身给Inode Cache和File Content Cache提供了通用接口,收到请求后会调用具体的FSAL(FSAL_SNMP, FSAL_RGW等)。FSAL中的对象对应一个FSAL handle。由于FSAL的语义设计与NFSv4很相似,因此开发和可以自己编写新的FSAL API来适配Ganesha。Ganesha软件包还提供了FSAL源代码模板。
(7)Hash Tables:提供了基于红黑树的哈希表,这个模块在Ganesha里用到很多
关联寻找功能在Ganesha被大量使用,比如我们想通过对象的父节点和名称来寻找对象元数据等类似行为是很经常的,因此为了保证Ganesha整体的高性能,关联寻找功能必须非常高效。
为了达到这个目的,开发团队采用了红黑树,它会在add/update操作后自动冲平衡。由于单棵红黑树会引发进程调用冲突(多个进程同时add/update,引发同时重平衡),如果加读写锁在红黑树上,又会引发性能瓶颈。因此开发团队设计了红黑树数组来解决了这个问题,降低了两个线程同时访问一个红黑树的概率,从而避免了访问冲突。
线程分为以下不同类型:
网络文件系统实现的核心是使用了RPC机制,即:远程过程调用协议。RPC是一种编程技术,也是协议。
如果在同一个主机上,两个进程之间可以直接通信(即进程间通信),但是当两个进程位于C/S模型上时,则需要借助另外一个应用程序(RPC),两个进程不需要考虑自己是否在网络上通信(全权由RPC处理)
RPC建立在Socket(套接字)之上,一台主机上运行的主程序,可以调用另一台主机上准备好的子程序,就像本地调用子程序一样,不需要知道底层网络实现的细节。
RPC调用的时候一般有两种方式:
NFS本身不是服务,是一种文件系统(network file system)。期望本机的某一个文件系统(如:共享处去一个目录/var/shared目录),可以被网络内别的主机访问到,并且可以进行操作。当然,首先客户端必须首先挂载服务器共享的目录(mount)。
Ganesha是一个全新的程序,可能对比kernel版本的NFSv4,Ganesha的性能有所欠缺,但是基于user-space的方法会带来更多有意思的功能。
NFS Ganesha workflow
以open()为例来,如上图所示。首先用户或者应用程序开始调用文件操作,经过系统调用 sys_open(),到达虚拟文件系统层 vfs_open(),然后交给 NFS 文件系统nfs_open()来处理。NFS 文件系统无法操作存储介质,它调用 NFS 客户端函数nfs3_proc_open() 进行通信,把文件操作转发到NFS Ganesha服务器。
Ganesha中监听客户端请求的是Dispatcher这个进程:其中的nfs_rpc_get_funcdesc()函数通过调用svc_getargs()来读取xprt(rpc通信句柄)中的数据,从而得到用户的具体请求,然后将这些信息注入到reqdata这个变量中。随后Dispatcher这个线程会把用户请求-reqdata插入到请求队列中,等待处理。
Ganesha会选择一个最空闲的worker thread来处理请求:通过调用nfs_rpc_dequeue_req()将一个请求从等待队列中取出,随后调用nfs_rpc_execute()函数处理请求。Ganesha内部自建了一个请求/回复缓存,nfs_dupreq_start()函数会在哈希表中寻找是否有一样的请求,如果找到,则寻找到对应回复,然后调用svc_sendreply()将回复发送给客户端,从而完成一个请求的处理。
如果Ganesha没有在哈希表中找到一样的请求,nfs_dupreq_start()这个函数会在缓存中新建一个请求,随后调用service_function(),也就是nfs_open()。FSAL(filesystem abstract layer)收到nfs_open()调用请求后,会调用fsal_open2()函数。由于我们已经在初始化阶段,在ganesha.conf指定了FSAL为RGW,并且在FSAL/FSAL_RGW/handle.c文件下我们已经重定向了FSAL的操作函数,因此fsal_open2()实际会调用rgw_fsal_open2(),通过使用librgw来进行具体操作。请求完成后,回复会插入到对应哈希表中,与请求建立映射,随后回复通过svc_sendreply()发送给客户端。由此完成了sys_open()这个函数的调用。
VFS FSAL 可以使用任何文件提供给操作系统的 Posix 接口。唯一的要求是文件系统能够生成和使用"file handles"。VFS FSAL 还支持 Linux中EXOFS文件系统的pNFS 布局 、还支持linux和FreeBSD的 PanFS (Panasas 专有) 文件系统的pNFS 布局。它是由export定义的选项启用。
参考:
http://blog.umcloud.com/nfs-ganesha/
https://blog.csdn.net/fsx2550553488/article/details/79699519