4.1.3 Master设计
1.Master内存占用
Master维护了系统中的元数据,包括文件及chunk命名空间、文件到chunk之间的映射、chunk副本的位置信息。其中前两种元数据需要持久化到磁盘,chunk副本的位置信息不需要持久化,可以通过ChunkServer汇报获取。
内存是Master的稀有资源,接下来介绍如何估算Master的内存使用量。chunk的元信息包括全局唯一的ID、版本号、每个副本所在的ChunkServer编号、引用计数等。GFS系统中每个chunk大小为64MB,默认存储3份,每个chunk的元数据小于64字节。那么1PB数据的chunk元信息大小不超过1PB×3/64MB×64=3GB。另外,Master对命名空间进行了压缩存储,例如有两个文件foo1和foo2都存放在目录/home/very_long_directory_name/中,那么目录名在内存中只需要存放一次。压缩存储后,每个文件在文件命名空间的元数据也不超过64字节,由于GFS中的文件一般都是大文件,因此,文件命名空间占用内存不多。这也就说明了Master内存容量不会成为GFS的系统瓶颈。
2.负载均衡
GFS中副本的分布策略需要考虑多种因素,如网络拓扑、机架分布、磁盘利用率等。为了提高系统的可用性,GFS会避免将同一个chunk的所有副本都存放在同一个机架的情况。
系统中需要创建chunk副本的情况有三种:chunk创建、chunk复制(re-replication)以及负载均衡(rebalancing)。
当Master创建了一个chunk,它会根据如下因素来选择chunk副本的初始位置:1)新副本所在的ChunkServer的磁盘利用率低于平均水平;2)限制每个Chunk-Server“最近”创建的数量;3)每个chunk的所有副本不能在同一个机架。第二点容易忽略但却很重要,因为创建完chunk以后通常需要马上写入数据,如果不限制“最近”创建的数量,当一台空的ChunkServer上线时,由于磁盘利用率低,可能导致大量的chunk瞬间迁移到这台机器从而将它压垮。
当chunk的副本数量小于一定的数量后,Master会尝试重新复制一个chunk副本。可能的原因包括ChunkServer宕机或者ChunkServer报告自己的副本损坏,或者ChunkServer的某个磁盘故障,或者用户动态增加了chunk的副本数,等等。每个chunk复制任务都有一个优先级,按照优先级从高到低在Master排队等待执行。例如,只有一个副本的chunk需要优先复制。另外,GFS会提高所有阻塞客户端操作的chunk复制任务的优先级,例如客户端正在往一个只有一个副本的chunk追加数据,如果限制至少需要追加成功两个副本,那么这个chunk复制任务会阻塞客户端写操作,需要提高优先级。
最后,Master会定期扫描当前副本的分布情况,如果发现磁盘使用量或者机器负载不均衡,将执行重新负载均衡操作。
无论是chunk创建,chunk重新复制,还是重新负载均衡,这些操作选择chunk副本位置的策略都是相同的,并且需要限制重新复制和重新负载均衡任务的拷贝速度,否则可能影响系统正常的读写服务。
3.垃圾回收
GFS采用延迟删除的机制,也就是说,当删除文件后,GFS并不要求立即归还可用的物理存储,而是在元数据中将文件改名为一个隐藏的名字,并且包含一个删除时间戳。Master定时检查,如果发现文件删除超过一段时间(默认为3天,可配置),那么它会把文件从内存元数据中删除,以后ChunkServer和Master的心跳消息中,每一个ChunkServer都将报告自己的chunk集合,Master会回复在Master元数据中已经不存在的chunk信息,这时,ChunkServer会释放这些chunk副本。为了减轻系统的负载,垃圾回收一般在服务低峰期执行,比如每天晚上凌晨1:00开始。
另外,chunk副本可能会因为ChunkServer失效期间丢失了对chunk的修改操作而导致过期。系统对每个chunk都维护了版本号,过期的chunk可以通过版本号检测出来。Master仍然通过正常的垃圾回收机制来删除过期的副本。
4.快照
快照(Snapshot)操作是对源文件/目录进行一个“快照”操作,生成该时刻源文件/目录的一个瞬间状态存放于目标文件/目录中。GFS中使用标准的写时复制机制生成快照,也就是说,“快照”只是增加GFS中chunk的引用计数,表示这个chunk被快照文件引用了,等到客户端修改这个chunk时,才需要在ChunkServer中拷贝chunk的数据生成新的chunk,后续的修改操作落到新生成的chunk上。
为了对某个文件做快照,首先需要停止这个文件的写服务,接着增加这个文件的所有chunk的引用计数,以后修改这些chunk时会拷贝生成新的chunk。对某个文件执行快照的大致步骤如下:
1)通过租约机制收回对文件的每个chunk写权限,停止对文件的写服务;
2)Master拷贝文件名等元数据生成一个新的快照文件;
3)对执行快照的文件的所有chunk增加引用计数。
例如,对文件foo执行快照操作生成foo_backup,foo在GFS中有三个chunk:C1、C2和C3(简单起见,假设每个chunk只有一个副本)。Master首先需要收回C1、C2和C3的写租约,从而保证文件foo处于一致的状态,接着Master复制foo文件的元数据用于生成foo_backup,foo_backup同样指向C1、C2和C3。快照前,C1、C2和C3只被一个文件foo引用,因此引用计数为1;执行快照操作后,这些chunk的引用计数增加为2。以后客户端再次向C3追加数据时,Master发现C3的引用计数大于1,通知C3所在的ChunkServer本次拷贝C3生成C3',客户端的追加操作也相应地转向C3'。