RGW NFS/ganesha 源码分析

0x1 RGW NFS Open 流程

 客户端:open->vfs_open->nfs_open() > nfs3_proc_open()    
 gansha server: 
     Dispatcher: decode xprt
                nfs_rpc_get_funcdesc()->SVC_GETARGS(xprt)->reqdata -> nfs_rpc_enqueue_req()
     Worker: dequeue xprt
                 nfs_rpc_dequeue_req()-> req_data -> nfs_rpc_execute-> nfs_dupreq_start()> rbtree -> syc_sendreplay
     fsal: rgw plugin
                 fasl_open()-> rgw_fasl_open2()->rgw_open() 
  ceph: rgw server

0x 2 Ganesha 核心模块:
– MemoryManager 负责Ganesha的内存管理
– RPC SES_GSS 负责使用RPCSEC_GSS的数据传输,通常使用krb5,SPKM3或LIPKEY来管理
– NFS NFS协议,主要是消息结构模块
– Metadata(Inode) Cache: 元数据缓存
– File Content Cache: 负责数据缓存,主要是小数据。
– FSAL (File system Abstraction Layer, 抽象的访问对象)
– Hash Tables rbtree group。

内存管理:
LibC malloc / free调用,内存是采用calloc分配的。

 static inline void *
gsh_calloc__(size_t n, size_t s,
             const char *file, int line, const char *function)
{
        void *p = calloc(n, s);

        if (p == NULL) {
                LogMallocFailure(file, line, function, "gsh_calloc");
                abort();
        }

        return p;
}

#define gsh_calloc(n, s) gsh_calloc__(n, s, __FILE__, __LINE__, __func__

哈希表:
redblack tree
主要守护进程
– dispatcher thread: 用于监听和分发传入的NFS、MOUNT请求。它会选择处于最空闲的worker线程然后将请求添加到这个worker线程的待处理列表中。这个线程会保留最近10分钟内的请求答复,如果在10分钟内收到相同指令(存在哈希表并用RPC Xid4值寻址),则会返回以前的请求回复。
– worker thread: Ganesha中的核心线程,也是使用最多的线程。worker线程等待dispatcher的调度,收到请求后先对其进行解码,然后通过调用inode cache API和file content API来完成请求操作。
缓存:
Cache Inode Layer将元数据与对应FSAL对象handle放入哈希表中,用来关联条目。初版的Ganesha采用’write through’缓存策略来做元数据缓存。实例的属性会在一定的时间(可定义)后过期,过期后该实例将会在内存中删除。每个线程有一个LRU(Least Recently Used) 列表,每个缓存实例只能存在于1个线程的LRU中,如果某个线程获得了某个实例,将会要求原线程在LRU列表中释放对应条目。

每个线程需要自己负责垃圾回收,当垃圾回收开始时,线程将从LRU列表上最旧的条目开始执行。 然后使用特定的垃圾策略来决定是否保存或清除条目。由于元数据缓存应该非常大(高达数百万条目),因此占满分配内存的90%(高位)之前不会发生垃圾回收。Ganesha尽可能多得将FSAL对象放入缓存的‘树型拓扑’中,其中节点代表目录,叶子可代表文件和符号链接;叶子的垃圾回收要早于节点,当节点中没有叶子时才会做垃圾回收。

File Content Cache数据缓存并不是独立于与Inode Cache,一个对象的元数据缓存和数据缓存会一一对应(数据缓存是元数据缓存的‘子缓存’),从而避免了缓存不统一的情况。文件内容会被缓存至本地文件系统的专用目录中,一个数据缓存实例会对应2个文件:索引文件和数据文件。数据文件等同于被缓存的文件。索引文件中包含了元数据信息,其中包含了对重要的FSAL handle。索引文件主要用于重建数据缓存,当服务器端崩溃后没有干净地清掉缓存时,FSAL handle会读取索引文件中的信息来重建元数据缓存,并将其指向数据文件,用以重建数据缓存实例。

当缓存不足时,worker thread会查看LRU列表中很久未被打开的实例,然后开始做元数据缓存回收。当元数据缓存回收开始时,数据缓存的垃圾回收也会同时进行:在回收文件缓存实例时,元数据缓存会问询数据缓存是否认识该文件实例,如果不认识则代表该数据缓存已经无效,则元数据回收正常进行,并完成实例缓存回收;如果认识,对应的文件缓存以及数据缓存均会被回收,随后对应的元数据缓存也会被回收。这样保证了一个数据缓存有效的实例不会被回收。

这种方式很符合Ganesha的架构设计:worker线程可以同时管理元数据缓存和数据缓存,两者一直保持一致

0x3 RGW-NFS release notes:
New NFS-Ganesha FSALexporting RGW Namespace. Runs a full
Ceph RGW under an NFS-Ganesha process. Cache coherent peer
of all gateways in the cluster.
Goals:
Add RGW/S3 as an adjunct namespace on existing POSIX
clients
Support S3 Legacy “Prefix and Delimiter” Namespace
Convention
Only supports ‘/’ delimiter currently
Build foundation for more interesting workflows, e.g.
pNFS direct placement of sharded objects (future)
consistent caching (future)
0x4 参照:
http://blog.umcloud.com/nfs-ganesha/

发表评论

您的电子邮箱地址不会被公开。