glusterfs 主要有以下几个组件
- gluster 命令行。
- glusterd 管理进程。
- glusterfsd 服务进程。
- glusterfs 客户端 fuse 进程。
glusterfs
是靠 translator
做分层设计的,类似于可插拔的模块的概念,对应的结构体是 xlator_t
,因为是 C 写的,一些面向的对象的写法也是通过 xlator
实现的,可以理解 xlator
是类,具体的实现是对象。比如 protocol/client
是最后的 xlator
从客户端发送到网络,对应的 storage/posix
是服务端接受的最后一层交给服务器上的文件系统。每个 xlator
都会编译成一个单独的 .so 文件。通过指定配置文件可以把不同的 xlator
进行组装,加载 .so 以后,通过dlsym
查找 xlator
的符号(函数表),相当于获取 xlator
的公开接口。配置文件中的 volume
和 subvolume
对应了 xlator
的组织关系。
volfile 会配置在 /var/lib/glusterd/vols/
下面,对应的文件名是 volfile-id 选项指定的。xlator_t
定义在 libglusterfs/src/xlator.h
里面。下面这张图就可以看到各个 translator 的关系。
glusterfsd 最开始是 protocol/server
最后是 storage/posix
两个 xlator 作为开头和结束。
glusterfs (client) 是以protocol/client
结尾。

那个 write-behind 应该对应的是缓存策略里面的 write back,异步写,而不是直写。
这种设计的好处是方便扩展,你只要填补 xlator
的实现,编译成 .so ,放到链接目录下面,就可以加载进去,不用改整个 glusterfs 的代码。
glusterfs 的整个应用的结构也可以看一下。

用户态是 fuse 实现的文件系统,通过网络协议走到 server,server 本身用的是本地的文件系统,glusterfs 推荐使用 xfs。
下面举个详细的例子。
以 writev
举例,(write 的本质也是 writev,这里的 v 指的是内存向量,写的时候用链表表示的内存向量可以减少内存的拷贝,因为要分配一段连续的内存,然后拷到一起很没有效率,而且系统调用本身也支持这个系统调用,走到底层是硬件支持的,硬件不支持,也能 hook 帮你再拷贝到一起,但上层就不用管这些细节了),他们的调用关系通过 STACK_WIND
和 STACK_UNWIND
实现,对于所有的 xlator 的 op 都是这种调用关系,本身一层结束以后通过调用 STACK_WIND
调用下一层对应的 op,然后在调用完成之后通过 STACK_UNWIND
回调 op_cbk,并且这种调用关系是树状的。

这张图解释挺好的,说明了 xlator 向下传递的过程,通过 STACK_WIND
调用下一层,通过 STACK_UNWIND
调用上一层的 cbk。
glusterfsd
每个 volume 都会起一个线程来处理。
./xlators/mount/fuse/src/fuse-bridge.c
下面是 fuse
的接口,这是客户端的入口,作为文件系统的“桥接点”,大概是为什么叫 bridge 的原因吧。
1 | static fuse_handler_t *fuse_std_ops[FUSE_OP_HIGH] = { |
看一下 fuse_write
,传了一个 xlator_t
,这个东西是 glusterfs
的分层设计的核心,每个 fuse_in_header_t
和 msg
还有 iobuf
都是 fuse 的 API。
1 | static void |
首先是传入了写入文件的描述符,要写的内存的段的地址和大小,iobuf 这个结构体和内核里的 iobuf 是查不多的。然后进到 fuse_resolve_and_resume
,这个函数主要是解析一些文件的元数据,并且返回到 writev_resume
这个回调函数上,解析的函数在 ./xlators/mount/fuse/src/fuse-resolve.c
下面,这整个是个状态机的写法,主要是解析 fd,父路径,inode 等信息。
1 | static int |
到了回到调 fuse_write_resume
上,包了一层引用计数就往下传了。
1 | iobref_add (iobref, state->iobuf); |
fuse_writev_cbk 里面 send_fuse_obj
把 iobuf
发送出去。send_fuse_data
到 send_fuse_iov
,
然后走整个的 xlator
的 writev 调用链,到 client
上,这里最主要的就是 submit_request 开始走网络 rpc 了。
1 | int32_t |
回调就会开始释放内存等等操作,这里就略过了,这里回到 fuse 的 writev_cbk
1 | static int |
send_fuse_obj
是一个宏实际上是 send_fuse_data
,把 fuse_write_out 传给 fuse 告诉 fuse 写出了多少,或者返回错误给 fuse。
1 |
|
整个的分析过程大概是从客户端的角度来看的,glusterfs 比较重要的一个 xlator
就是 dht xlator,distributed hash table,这个 xlator 决定了文件的分布。