全局统一命名空间
Glusterfs采用了全局统一命名空间设计,将磁盘和内存资源聚集成一个单一的虚拟存储池进行管理,并在此命名空间中使用NFS/CIFS等标准协议来访问应用数据。与其他分布式文件系统有所不同的是,GlusterFS中没有专用的元数据服务器,而是独特地采用无元数据服务的设计,取而代之使用算法来定位文件,元数据和数据没有分离而是一起存储。这使得数据访问完全并行化,从而实现真正的线性性能扩展。无数据服务器极大提高了GlusterFS的性能、可靠性和稳定性。
GlusterFS是模块化堆栈式的架构设计,模块称为Translator。Translators是GlusterFS提供的一种强大文件系统功能扩展机制,这一设计思想借鉴于GNU/Hurd微内核操作系统。GlusterFS中所有的功能都通过Translator机制实现,借助这种良好定义的接口可以高效简便地扩展文件系统的功能。在Glusterfs中,每个translator都有自己的全局命名空间,并且使用自己的机制进行独立的维护和管理。
三种集群模式
Glusterfs是集群文件系统,主要有三种基本的集群模式,即分布式集群(Distributed cluster)、条带集群(Stripe cluster)、复制集群(Replica cluster)。这三种基本集群还可以采用类似堆积木的方式,构成更加复杂的复合集群,比如分布式条带集群(Distributed stripe cluster)、分布式复制集群(Distributed replica cluster)、RAID10集群(Stripe replica cluster)、分布式RAID10集群(Distributed stripe replica cluster)。
三种基本集群各由一个translator来实现,分别由自己独立的命名空间,如上图所示。对于分布式集群,文件通过HASH算法分散到集群节点上,每个节点上的命名空间均不重叠,所有集群共同构成完整的命名空间,访问时使用HASH算法进行查找定位。复制集群类似RAID1,所有节点命名空间均完全相同,每一个节点都可以表示完整的命名空间,访问时可以选择任意个节点。条带集群与RAID0相似,所有节点具有相同的命名空间,但对象属性会有所不同,文件被分成数据块以Round Robin方式分布到所有节点上,访问时需要联动所有节点来获得完整的名字信息。对于VFS的lookup, stat, readdir三个名字空间相关操作,三种集群处理方式如下。
(1)Distribued集群
.lookup:采用hash算法选择节点,如果未命中且为目录则查询卷下所有节点,还未找到且设置search_unhashed则遍历所有节点;
.stat:请求发向所有节点,如果是目录需要对属性进行聚合;
.readdir:查询所有节点,并对文件目录信息及属性进行聚合;
(2)Stripe集群
.lookup:所有节点都要被查询,进行属性聚合,检查gfid并进行自修复;
.stat:查询所有节点,进行信息聚合;
.readdir:查询首节点,属性信息需要聚合所有节点信息;
(3)Replica集群
.lookup:请求发送到所有节点,首个成功响应即返回;
.stat:查询选择的一个UP节点,如果失败则依次查询下一个节点;
.readdir:与stat相同,选择一个UP节点进行查询,如果失败则依次查询下一个UP节点;
Distributed集群
这种集群又称弹性哈希卷,它使用算法进行数据定位,这是整个Glusterfs的架构基础和最大特点,集群中的任何服务器和客户端只需根据路径和文件名就可以对数据进行定位和读写访问,因此文件定位可独立并行化进行。Glusterfs中,不需要将元数据与数据进行分离,文件元数据记录在底层文件系统的inode以及扩展属性上。GlusterFS的哈希分布是以目录为基本单位的,文件的父目录利用扩展属性记录了子卷映射信息,子文件在父目录所属存储服务器中进行分布。由于文件目录事先保存了分布信息,因此新增节点不会影响现有文件存储分布,它将从此后的新创建目录开始参与存储分布调度。
.lookup:采用hash算法查找文件
1)如果path为根目录,则选定第一个UP卷(dht_first_up_subvol)为目标卷;
2)否则,以path为输入参数计算hash值(dht_hash_compute),从父目录扩展属性中获取哈希分布信息,然后查找定位目标卷;
3)如果找到目标卷,则在目标卷中查找path;如果没有找到并且设置GF_DHT_LOOKUP_UNHASHED_ON/GF_DHT_LOOKUP_UNHASHED_AUTO,将搜索所有的卷;
4)如果没有找到目标卷,并且path为目录,则在所有子卷中查找;
.mkdir:分布到所有子卷上,新增节点参加分布上,并分配hash range
1)首先在目标卷hashed_subvol创建目录;
2)向其他所有子卷发送请求创建目录;
3)通过selfheal机制(dht_selfheal_new_directory)分配hash范围;
.create:分布到父目录所分布的子卷上,新增节点不参加分布
1)计算文件名hash值,查找目标卷;若未找到则返回;
2)如果目标卷空闲容量在预定水位以下,则创建文件并返回;
3)查找空闲容量在预定水位以下子卷,在其上创建文件,并在目标卷上创建链接指向实际文件;
Stripe集群
名字空间由所有子卷共同组成,lookup时会将请求发送到全部节点上,属性获取需要聚合。若其中任一节点出问题,则namespace和数据将不可访问。
.
lookup:请求发送到所有节点,客户端进行聚合。当所有请求成功返回方才向上返回结果;
.
create/mkdir:请求发送到所有节点,所有节点namespace相同,但属性稍有不同;
.
readdir:向第一个节点请求所有目录项,属性需要查询所有节点进行聚合;
.
readv:根据stripe size及Round Robin算法,计算出数据所在的节点,然后并行发送请求,由客户端对数据重新进行组织;
.writev:计算所写数据块所属节点及offset,所有写成功后方才向上返回;
Replica集群
所有节点具有相同的、全完全对等的名字空间,默认第一个节点作为主节点。请求通常发送到所有节点,所有成功返回后才向上作响应。
.
lookup:请求发送到所有up节点,有成功返回即响应;并处理是否需要进行sealheal,主要依据是xattr上记录的change log;
.
create/mkdir:以afr_transaction事务方式处理,请求发送到所有UP子节点上,所有成功返回后方才向上响应;
.
readdir:选择一个UP节点发请求,具有负载均衡作用,失败后则依次请求所有其他节点;
.
readv:open时打开所有UP节点,读时选择一个UP节点进行read,若失败则依次偿试所有其他节点;
.
writev:以afr_transaction事务方式处理,请求发送到所有UP子节点上,所有成功返回方才向上响应;