首页 > 代码库 > GlusterFS源码解析 —— GlusterFS 结构体系分析
GlusterFS源码解析 —— GlusterFS 结构体系分析
简述
经过这几天对Glusterfs的分析, 对其体系结构已经有了初步的理解。 值得庆贺的一点就是 Glusterfs 的整个体系结构非常清晰, 高度模块化的设计使得我们对他的理解和扩展变得比较容易。1. 给出几个从网络上收集的结构图, 用以帮助我们来从整理上认识其体系结构。
2. 以 Glusterfs 的一个客户端配置文件入手, 来理解配置文件的同时也进一步来理解其体系结构。
3. Glusterfs 系统中, 系统的主体是一颗 translator 的树结构,我们来分析整个translator树结构的建立过程(以上面给出的客户端的配置文件为例, 来建立这棵树)
4. 以一个 "write" 操作为例, 来理解glusterfs的整个处理流程
以上就是本文的一个大致分析思路。
对体系结构的具体分析
一、给出几个从网络上收集的结构图, 来帮助我们来认识其体系结构。
图一
这是来自 glusterfs 的官方结构图, 从这个图中, 我们可以得到如下的信息:
1.
glusterfs 没有 MeteData 模块, 没有MeteData的设计模式, 使得系统的复杂度降低, 也避免了MeteData成为整个系统性能瓶颈的问题, 当然, 这种体系结构仅仅适合于基于以文件为对象的存储体系, 对于像 GoogleFS,Lustre 等基于磁盘块,inode的存储系统是不能没有MeteData的。
1.1 有MeteData系统的优势和不足:
类似于 Google, Lustre等, MeteData是其题写结构中不可缺少的部分, 因为他们是基于磁盘块,inode的存储系统。
优点: 系统性能很好,他们将文件进行了一定的分割,并且以块的方式直接存储在磁盘上,减少了类似于 VFS的处理流程, 所以他们对于高性能的数据处理是很有优势的。
缺点: 正是因为引入了 MeteData, 使得系统的复杂度增加, 并且并发能力受到很大的限制(因为所有的处理首先要通过MeteData来定位数据的分布),增对于这个问题, 业界也出现了对MeteData的集群, 这可以缓解其并发瓶颈的问题。
1.2 没有MeteData系统的优势和不足:
Glusterfs就是这一类系统
其优势是:系统复杂度降低, 扩展容易,并且是在用户层实现,容易部署和维护,并且没有MeteData的瓶颈限制, 所以其并发性能较上面的系统有优势。
但其不足也是很明显的: 这种类型的系统只能是以文件为存储对象,所以他的处理性能会比MeteData系统差。
1.3
基于我们的实际应用,结合 Glusterfs 的优势和不足, 综合起来,Glusterfs对于我们的应用还是一个不错的选择, 况且他在业界的实际使用和被关注度也越来越多, 这也是以后集群存储的一个发展方向, 也更加适合于民间的实际使用。
2.
client 和 服务器之间可以通过 RDMA 来进行数据通讯。
3.
InfiniBand 将是我们需要重点考虑和采用的方案, 他可以有效提高数据的传输效率。
图二
这个图是上面图一的细化, 从中我们可以知道:1. client and server 的设计是高度模块化的
2. client 的复杂度比 server 要大, 客户端需要考虑的问题很多, 比如 Read Ahead, I/O Cache, Stripe, Unify, Replicate(AFR) 等。
3. 所以,我们以后的重点是在Client端。
图三
图三是整个 glusterfs 数据流的一个概要图:1. 首先是在客户端, 用户通过glusterfs的mount point 来读写数据, 对于用户来说, 集群系统的存在对用户是完全透明的, 用户感觉不到是操作本地系统还是远端的集群系统。
2. 用户的这个操作被递交给 本地linux系统的VFS来处理。
3. VFS 将数据递交给FUSE 内核文件系统:在启动 glusterfs 客户端以前, 需要想系统注册一个实际的文件系统FUSE,如上图所示,该文件系统与ext3在同一个层次上面, ext3 是对实际的磁盘进行处理, 而 fuse 文件系统则是将数据通过 /dev/fuse 这个设备文件递交给了glusterfs client端。所以, 我们可以将 fuse 文件系统理解为一个代理。
4. 数据被 fuse 递交给 Glusterfs client 后, client 对数据进行一些指定的处理(所谓的指定,是按照client 配置文件据来进行的一系列处理, 我们在启动glusterfs client 时 需 要 指 定 这 个 文 件 , 其 默 认 位 置 :/etc/glusterfs/client.vol)。
5. 在glusterfs client的处理末端, 通过网络将数据递交给 Glusterfs Server,
并且将数据写入到服务器所控制的存储设备上。
这样, 整个数据流的处理就完成了。
二、以 Glusterfs 的一个客户端配置文件入手, 来理解配置文件的同时也进一步来理解其体系结构。
配置文件如下:
************************************************************* ### Add client feature and attach to remote subvolume ## client 1 volume client1 type protocol/client option transport-type tcp/client option remote-host 10.0.0.2 # IP address of the remote brick option remote-port 6996 # default server port is 6996 option remote-subvolume brick # name of the remote volume end-volume ## client 2 volume client2 type protocol/client option transport-type tcp/client option remote-host 10.0.0.3 option remote-port 6996 option remote-subvolume brick end-volume ## client 3 volume namespacenode type protocol/client option transport-type tcp option remote-host 10.0.0.4 option remote-port 6996 option remote-subvolume brick end-volume ## Add unify feature volume bricks type cluster/unify subvolumes client1 client2 option scheduler rr option namespace namespacenode end-volume## Add readahead feature volume readahead type performance/read-ahead option page-size 1MB # unit in bytes option page-count 2 # cache per file = (page-count x page-size) subvolumes bricks end-volume ##Add io-cache feature volume ioc type performance/io-cache subvolumes readahead option page-size 1MB # 128KB is default option cache-size 64MB # 32MB is default option force-revalidate-timeout 5 # 1second is default end-volume
我们可以给出上面配置文件对应的一个逻辑图, 如下图:
glusterfs –l /tmp/glusterfs.log –f /etc/glusterfs/client.vol /mnt/gluster
命令说明: -l /tmp/glusterfs.log : 指出log 信息文件
-f /etc/glusterfs/client.vol 给出客户端对应的卷配置文件
/mnt/glusterfs : 客户端的mount point
1. 在系统启动的时候, 首先从命令行知道客户端的配置文件是 client.vol 文件
volume client type protocol/client option transport-type tcp/client option remote-host 10.0.0.3 option remote-port 6996 option remote-subvolume brick end-volume也就是 volume …. End-volume信息, 每一个这样的信息会被生成一个新的树节点(xlator_t), 挂接到以 FUSE 为根节点的树上, 每一个xlator_t节点有自己的属性定义(就是上面的 option 字段定义的(key, value)值)和大量的函数指针定义。 我们也不难发现, 实质上配置文件从开始到最后, 是先定义这棵树的叶子节点, 然后一层一层向树根方向定义的。
每个xlator_t 结构
定义了大量的函数指针, 这些函数指针大致可以分为三类:a) 普通的数据处理函数指针(用于正常的数据处理)
b) 回调函数指针,用于处理结果的返回。
c) 管理类函数指针从源代码中可以看到, FUSE对这三类指针的定义为空,因为 FUSE是树根节点,所以没有定义这些处理函数。
以一个 "write" 操作为例, 来理解整个过程的流程:
下面我们以在客户端一个写操作为例, 来打通整个流程,例如在 /mnt/glusterfs(glusterfs 客户端 的mount point)中 写一个文件为例:STACK_WIND (frame, writev_cbk, child, child->fops->writev, fd, vector, count, off);
该宏的定义如下:
/* make a call */ #define STACK_WIND(frame, rfn, obj, fn, params ...) do { call_frame_t *_new = NULL; _new = CALLOC (1, sizeof (call_frame_t)); ERR_ABORT (_new); typeof(fn##_cbk) tmp_cbk = rfn; _new->root = frame->root; _new->next = frame->root->frames.next; _new->prev = &frame->root->frames; if (frame->root->frames.next) \ frame->root->frames.next->prev = _new; frame->root->frames.next = _new; _new->this = obj; _new->ret = (ret_fn_t) tmp_cbk; _new->parent = frame; _new->cookie = _new; LOCK_INIT (&_new->lock); frame->ref_count++; fn (_new, obj, params); } while (0)
3. 这样, 每一个xlator_t 节点都会按照上面的方式将写数据递交给他的子节点来处理, 直到到达了树的叶子节点。
/* return from function */ #define STACK_UNWIND(frame, params ...) do { ret_fn_t fn = frame->ret; call_frame_t *_parent = frame->parent; _parent->ref_count--; fn (_parent, frame->cookie, _parent->this, params); } while (0)
这样, 处理的结果会一直被返回给 fuse_xlators, 然后通过 FUSE(kernel)返回给用户。
通过上面的分析, 我相信大家对 Glusterfs 的整体框架和内部的结构和数据流有了一个大致的了解, 有了上面这些知识的指导, 然后在结合源代码, 对Glusterfs 的理解就会更加透彻。 剩下的任务,就是针对各个 Translator 的研究分析了。
—— —— 以上内容整理自互联网
GlusterFS源码解析 —— GlusterFS 结构体系分析