Master节点执行所有的名称空间操作。此外,它还管理着整个系统里所有Chunk的副本:它决定Chunk 的存储位置,创建新Chunk和它的副本,协调各种各样的系统活动以保证Chunk被完全复制,在所有的 Chunk服务器之间的进行负载均衡,回收不再使用的存储空间。本节我们讨论上述的主题。
4.1 名称空间管理和锁
Master节点的很多操作会花费很长的时间:比如,快照操作必须取消Chunk服务器上快照所涉及的所有的 Chunk的租约。我们不希望在这些操作的运行时,延缓了其它的Master节点的操作。因此,我们允许多个 操作同时进行,使用名称空间的region上的锁来保证执行的正确顺序。
不同于许多传统文件系统,GFS没有针对每个目录实现能够列出目录下所有文件的数据结构。GFS也不支
持文件或者目录的链接(即Unix术语中的硬链接或者符号链接)。在逻辑上,GFS的名称空间就是一个全 路径和元数据映射关系的查找表。利用前缀压缩,这个表可以高效的存储在内存中。在存储名称空间的树 型结构上,每个节点(绝对路径的文件名或绝对路径的目录名)都有一个关联的读写锁。
每个Master节点的操作在开始之前都要获得一系列的锁。通常情况下,如果一个操作涉及/d1/d2/…/dn /leaf,那么操作首先要获得目录/d1,/d1/d2,…,/d1/d2/…/dn的读锁,以及/d1/d2/…/dn/leaf的读 写锁。注意,根据操作的不同,leaf可以是一个文件,也可以是一个目录。
现在,我们演示一下在/home/user被快照到/save/user的时候,锁机制如何防止创建文件/home/user /foo。快照操作获取/home和/save的读取锁,以及/home/user和/save/user的写入锁。文件创建操作获 得/home和/home/user的读取锁,以及/home/user/foo的写入锁。这两个操作要顺序执行,因为它们试 图获取的/home/user的锁是相互冲突。文件创建操作不需要获取父目录的写入锁,因为这里没有”目 录”,或者类似inode等用来禁止修改的数据结构。文件名的读取锁足以防止父目录被删除。
采用这种锁方案的优点是支持对同一目录的并行操作。比如,可以再同一个目录下同时创建多个文件:每 一个操作都获取一个目录名的上的读取锁和文件名上的写入锁。目录名的读取锁足以的防止目录被删除、
改名以及被快照。文件名的写入锁序列化文件创建操作,确保不会多次创建同名的文件。
因为名称空间可能有很多节点,读写锁采用惰性分配策略,在不再使用的时候立刻被删除。同样,锁的获 取也要依据一个全局一致的顺序来避免死锁:首先按名称空间的层次排序,在同一个层次内按字典顺序排 序。
4.2 副本的位置
GFS集群是高度分布的多层布局结构,而不是平面结构。典型的拓扑结构是有数百个Chunk服务器安装在 许多机架上。Chunk服务器被来自同一或者不同机架上的数百个客户机轮流访问。不同机架上的两台机器 间的通讯可能跨越一个或多个网络交换机。另外,机架的出入带宽可能比机架内所有机器加和在一起的带 宽要小。多层分布架构对数据的灵活性、可靠性以及可用性方面提出特有的挑战。
Chunk副本位置选择的策略服务两大目标:最大化数据可靠性和可用性,最大化网络带宽利用率。为了实 现这两个目的,仅仅是在多台机器上分别存储这些副本是不够的,这只能预防硬盘损坏或者机器失效带来 的影响,以及最大化每台机器的网络带宽利用率。我们必须在多个机架间分布储存Chunk的副本。这保证 Chunk的一些副本在整个机架被破坏或掉线(比如,共享资源,如电源或者网络交换机造成的问题)的情 况下依然存在且保持可用状态。这还意味着在网络流量方面,尤其是针对Chunk的读操作,能够有效利用 多个机架的整合带宽。另一方面,写操作必须和多个机架上的设备进行网络通信,但是这个代价是我们愿 意付出的。
4.3 创建,重新复制,重新负载均衡
Chunk的副本有三个用途:Chunk创建,重新复制和重新负载均衡。
当Master节点创建一个Chunk时,它会选择在哪里放置初始的空的副本。Master节点会考虑几个因 素。(1)我们希望在低于平均硬盘使用率的Chunk服务器上存储新的副本。这样的做法最终能够平衡 Chunk服务器之间的硬盘使用率。(2)我们希望限制在每个Chunk服务器上”最近”的Chunk创建操作的 次数。虽然创建操作本身是廉价的,但是创建操作也意味着随之会有大量的写入数据的操作,因为Chunk 在Writer真正写入数据的时候才被创建,而在我们的”追加一次,读取多次”的工作模式下,Chunk一旦写 入成功之后就会变为只读的了。(3)如上所述,我们希望把Chunk的副本分布在多个机架之间。
当Chunk的有效副本数量少于用户指定的复制因数的时候,Master节点会重新复制它。这可能是由几个原 因引起的:一个Chunk服务器不可用了,Chunk服务器报告它所存储的一个副本损坏了,Chunk服务器 的一个磁盘因为错误不可用了,或者Chunk副本的复制因数提高了。每个需要被重新复制的Chunk都会根 据几个因素进行排序。一个因素是Chunk现有副本数量和复制因数相差多少。例如,丢失两个副本的 Chunk比丢失一个副本的Chunk有更高的优先级。另外,我们优先重新复制活跃(live)文件的Chunk而 不是最近刚被删除的文件的Chunk(查看4.4节)。最后,为了最小化失效的Chunk对正在运行的应用程
序的影响,我们提高会阻塞客户机程序处理流程的Chunk的优先级。
Master节点选择优先级最高的Chunk,然后命令某个Chunk服务器直接从可用的副本”克隆”一个副本出 来。选择新副本的位置的策略和创建时类似:平衡硬盘使用率、限制同一台Chunk服务器上的正在进行的 克隆操作的数量、在机架间分布副本。为了防止克隆产生的网络流量大大超过客户机的流量,Master节点 对整个集群和每个Chunk服务器上的同时进行的克隆操作的数量都进行了限制。另外,Chunk服务器通过 调节它对源Chunk服务器读请求的频率来限制它用于克隆操作的带宽。
最后,Master服务器周期性地对副本进行重新负载均衡:它检查当前的副本分布情况,然后移动副本以便 更好的利用硬盘空间、更有效的进行负载均衡。而且在这个过程中,Master服务器逐渐的填满一个新的 Chunk服务器,而不是在短时间内用新的Chunk填满它,以至于过载。新副本的存储位置选择策略和上面 讨论的相同。另外,Master节点必须选择哪个副本要被移走。通常情况,Master节点移走那些剩余空间 低于平均值的Chunk服务器上的副本,从而平衡系统整体的硬盘使用率。
4.4 垃圾回收
GFS在文件删除后不会立刻回收可用的物理空间。GFS空间回收采用惰性的策略,只在文件和Chunk级的 常规垃圾收集时进行。我们发现这个方法使系统更简单、更可靠。
4.4.1 机制
当一个文件被应用程序删除时,Master节点象对待其它修改操作一样,立刻把删除操作以日志的方式记录 下来。但是,Master节点并不马上回收资源,而是把文件名改为一个包含删除时间戳的、隐藏的名字。当 Master节点对文件系统命名空间做常规扫描的时候,它会删除所有三天前的隐藏文件(这个时间间隔是可 以设置的)。直到文件被真正删除,它们仍旧可以用新的特殊的名字读取,也可以通过把隐藏文件改名为 正常显示的文件名的方式“反删除”。当隐藏文件被从名称空间中删除,Master服务器内存中保存的这个文 件的相关元数据才会被删除。这也有效的切断了文件和它包含的所有Chunk的连接(alex注:原文是This effectively severs its links to all its chunks)。
在对Chunk名字空间做类似的常规扫描时,Master节点找到孤儿Chunk(不被任何文件包含的Chunk)
并删除它们的元数据。Chunk服务器在和Master节点交互的心跳信息中,报告它拥有的Chunk子集的信 息,Master节点回复Chunk服务器哪些Chunk在Master节点保存的元数据中已经不存在了。Chunk服务 器可以任意删除这些Chunk的副本。
4.4.2 讨论
虽然分布式垃圾回收在编程语言领域是一个需要复杂的方案才能解决的难题,但是在GFS系统中是非常简 单的。我们可以轻易的得到Chunk的所有引用:它们都只存储在Master服务器上的文件到块的映射表中。
我们也可以很轻易的得到所有Chunk的副本:它们都以Linux文件的形式存储在Chunk服务器的指定目录 下。所有Master节点不能识别的副本都是”垃圾”。
垃圾回收在空间回收方面相比直接删除有几个优势。首先,对于组件失效是常态的大规模分布式系统,垃 圾回收方式简单可靠。Chunk可能在某些Chunk服务器创建成功,某些Chunk服务器上创建失败,失败 的副本处于无法被Master节点识别的状态。副本删除消息可能丢失,Master节点必须重新发送失败的删 除消息,包括自身的和Chunk服务器的(alex注:自身的指删除metadata的消息)。垃圾回收提供了一 致的、可靠的清除无用副本的方法。第二,垃圾回收把存储空间的回收操作合并到Master节点规律性的后 台活动中,比如,例行扫描和与Chunk服务器握手等。因此,操作被批量的执行,开销会被分散。另外,
垃圾回收在Master节点相对空闲的时候完成。这样Master节点就可以给那些需要快速反应的客户机请求
垃圾回收在Master节点相对空闲的时候完成。这样Master节点就可以给那些需要快速反应的客户机请求