首页 > 代码库 > 合并并且排序指针数组和二维数组里面存放的字符串用函数调用的格式
合并并且排序指针数组和二维数组里面存放的字符串用函数调用的格式
简述
经过这几天对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 的研究分析了。
—— —— 以上内容整理自互联网
合并并且排序指针数组和二维数组里面存放的字符串用函数调用的格式