The Google File System 翻译和理解( 八 )


每个主节点操作在执行前都先获得一系列的锁,通常,如果它涉及到/d1/d2/.../dn/leaf,它将:

  • 获得目录名的读锁/d1,/d1/d2,...,/d1/d2/.../dn
  • 获取完全文件名/d1/d2/.../dn/leaf的一个读锁或写锁 。
注意,这里的 leaf 根据其操作,可能是一个文件,也可能是一个目录 。
我们现在举例说明在/home/user构造快照成/save/user时,这个锁机制如何防止另一个 Master 任务创建一个文件/home/user/foo
  • 快照操作获得了/home/save上的读锁,以及/home/user/save/user上的写锁 。
  • 而文件创建操作则获得了/home/home/user上的读锁,以及/home/user/foo上的写锁 。因为它们都试图获得/home/user上的锁而造成冲突,所以这两个操作将适当的进行排序 。
文件创建不需要获取它的父目录的写锁,因为这里没有“目录”或类似 inode 等用来防止被修改的数据结构 。文件名上的读锁足以防止父目录被删除 。
这种锁机制的一个很好的性质是它允许对同一个目录下的并发操作 。比如,在一个相同目录下 , 多个文件创建操作可以同时进行:每个操作获取目录上的读锁 , 以及其文件名上的写锁 。目录名上的读锁足以防止目录被删除、重命名或进行快照 。文件名上的写锁可以使使用同一名字创建文件的两次操作顺序执行 。
因为命名空间可能包含很多节点 , 所以读写锁对象采用惰性分配策略,一旦不再使用则被删除 。同样,锁需要按一个相同的顺序被获取来防止死锁:他们先对命名空间进行排序,并在同一级别按字典序排序 。
4.2 副本布局一个GFS集群采用高度分布的多层结构,它通常有几百个块服务器分布在许多机器架构上 。这些块服务器被来自相同或不同机器架构上的数百个客户端轮流访问 。不同机架上的两台机器间的通信可能要经过一个或多个网络交换,此外,机架的入口或出口带宽可能比机架上所有机器的带宽总和要小 。多层的分布式对数据的灵活性、可靠性和可用性提出了挑战 。
块副本布局策略有两大目标:最大化数据的可靠性和可用性,最大化带宽利用率 。为了这两个目标,将副本分布在不同的机器是不够的 , 它只防止了磁盘或机器的失效,以及最大化了机器的带宽利用率 。我们也必须将副本分布到不同的机架上,这样可以确保在整个机架损坏或掉线(例如,由于网络交换或电源线路的问题造成的资源共享失效)的情况下,一个块的一些副本能够保存下来并能正常使用 。这意味着在网络流量上,特别是在读取一个块时,可以利用多个机架的整合带宽 。另一方面,写操作必须将数据导向多个机架,这个代价是我们愿意付出的 。
4.3 块副本的创建、重新复制和重新负载均衡三个原因造成了块副本的创建:块创建、重新复制和重新负载均衡 。
当主节点创建一个块时,它会选择在哪个块服务器上初始化一个空的副本 。主节点会考虑几个因素:
  1. 我们想要在一个空间使用率低于平均值的块服务器上放置新的副本,这会使块服务器间的磁盘利用率基本相等 。
  2. 我们想要限制每台块服务器上近期创建块的数量 。尽管创建本身是廉价的,但是它也预示着马上就会有大量的数据写入 。块服务器往往在一波写入后就变成实际只读的了 。
  3. 我们想要将一个块的副本分布到不同的机架上 。
当副本的可用数量低于用户指定的值时,Master 会尽快进行块的重新复制 。以下原因可能引起这个操作:
  1. 一个块服务器不可用 。
  2. 块服务器报告存储的副本可能被损坏 。
  3. 其中一个磁盘由于错误不可用 。
  4. 备份数量的设置值变大了 。
每个需要进行重新复制的块基于几个因素优先进行:
  1. 一个是块现有的副本数量与目标数差多少 。比如一个丢失两个副本的块比丢失一个副本的优先级高;
  2. 相对于最近被删除的文件的块来说,我们优先对活跃的文件的块进行重新复制(4.4);
  3. 为了最小化失效对正在运行的应用的影响,我们会提高阻塞客户进程的块的重新复制优先级 。
Master 选取优先级最高的块,通过通知一些块服务器从一个可用副本上拷贝块数据来“克隆”它 。选择副本位置的方法与创建时类似:平均磁盘空间使用率 , 限制单一块服务器上运行的克隆操作熟练,以及跨机架分布 。

推荐阅读