GFS文件系统的架构分析

    Google文件系统(Google File System,GFS)是构建在廉价的服务器之上的大型分布式系统。它认为组件失效(注:可理解为服务器故障)是常态事件,而不是意外事件,通过自身对可能失效组件的持续的监控、错误侦测、灾难冗余以及自动恢复的机制,保证系统的可靠性,也降低了系统的设计成本。
 
系统架构
   

     一个GFS集群包含三个角色:一个单独的GFS Master总控制服务器 多台GFS Chunkserver(数据块服务器,简称CS)和多个GFS Client客户端.GFS存储的文件都被分割成固定大小的Chunk Chunk服务器把Chunklinux文件的形式保存在本地硬盘上,并且根据指定的Chunk标识和字节范围来读写块数据。为了保证可靠性,Chunk在不同的机器中复制多份,缺省情况下,使用3个存储复制节点,不过用户可以为不同的文件命名空间设定不同的复制级别。
 
     Master中维护了系统的元数据(SQL中的说法是:数据的数据),这些元数据包括Chunk名字空间、访问控制信息、文件和Chunk的映射信息、以及当前Chunk的位置信息.。Master还管理着系统范围内的活动,比如, Chunk租用 管理 无用Chunk的回 收、以及 Chunk在Chunk服务器之间的迁移。 Master节点使用心跳信息周期地和每个Chunk 服务器通 讯,发送指令到各个Chunk服务器并接收Chunk服务器的状态信息。
 
    Client代码实现了GFS文件系统的API接口函数以及应用程序的访问接口。应用程序从Master获取元数据,根据元数据提供的信息与Chunk服务器直接进行交互。从架构图可以看出 Client和Master之间的交互只有控制流(指令信息),没有数据流,因此降低了Master的负载  ( 因为控制流只需传送指令和状态,数据量小 Client与Chunk 之间直接传输数据流,同时由于文件被分成多个chunk进行分布式存储,因此Client可以同时并行访问多个Chunk ,从而让系统的I/O并行度提高。GFS不提供POSIX标准的API的功能,因此,其API调用不需要深入到Linux vnode级别。
 
    需要注意的是,GFS中的客户端不缓存文件数据,只缓存Master中获取的元数据。Chunk服务器也不需要缓存数据,Chunk以本地文件的方式保存, Linux操作系统的文件系统缓存会把经常访问的数据缓存在内存中。
 
一致性模型
 

    GFS主要是为了追加(Append)而不是改写(Overwrite)而设计的。一方面是因为是改写的需求比较少,或者可以通过追加来实现;另一方面是因为追加的一致性模型相比改写要更加简单有效。若出现某些副本追加成功而某些副本没有成功的情况,失败的副本可能会出现一些可识别的填充(padding)记录。GFS客户端追加失败将重试,只要返回用户追加成功,说明在所有副本中都至少追加成功了一次。当然,可能出现记录在某些chunk副本中被追加了多次,即重复记录;也可能出现一些可识别的填充记录,应用层需要能够处理这些问题。

    另外,由于GFS支持多个客户端并发追加,那么多个客户端之间的顺序是无法保证的,同一个客户端连续追加成功的多个记录也可能被打断,比如客户端先后追加成功记录R1和R2,由于追加R1和R2这两条记录的过程不是原子的,中途可能被其它客户端打断,那么GFS的chunk中记录的R1和R2可能不连续,中间夹杂着其它客户端追加的数据。

    GFS的这种一致性模型是追求性能导致的,这也增加了应用程序开发的难度。对于MapReduce应用,由于其批处理特性,可以先将数据追加到一个临时文件,在临时文件中维护索引记录每个追加成功的记录的偏移,等到文件关闭时一次性将临时文件改名为最终文件。

 

系统交互:

 

   租约(lease)和变更顺序
 
     变更是一个会改变Chunk内容或者元数据的操作,比如写入操作或者记录追加操作。变更操作会在Chunk 的所有副本上执行。 Master通过Lease赋予主Chunk对其他副本的变更权限,在Lease有效期内,对该chunk的写操作都有主Chunk负责,从而减少Master的负担。一般来说,Lease的有效期比较长,比如60秒,只要没有出现异常,主Chunk可以不断向Master请求延长Lease的有效期直到完成变更操作或整个chunk写满。Master节点和主Chunk失去联系,它仍然可以安全地在旧的租约到期后和另外一个Chunk副本签订新的租约,保证数据的有序变更。
 
   追加过程
   在下图是写入操作的控制流程。


1. 客户机向Master节点询问哪一个Chunk服务器持有当前的租约,以及其它副本的位置。 如果没有一Chunk持有租约, Master节点就选择其中一个副本建立一个租约(这个步骤在图上没有显示)。

2. Master节点将主Chunk的标识符以及其它副本的位置返回给客户机。客户机缓存这些数据以便后续的操作。只有在主Chunk不可用,或者主Chunk回复信息表明它已不再持有租约的时候,客户机才需要重新跟Master节点联系。

3. 客户机可以以任意的顺序推送数据到所有的副本上。 Chunk服务器接收到数据并保存在它的内部LRU缓存中。通过分离数据流和控制流,GFS基于网络拓扑情况对数据流的网络传输负载进行规划,提高系统性能。
 
4. 当所有的副本都确认接收到了数据,客户机发送写请求到主Chunk服务器。Chunk接收到的所有写请求,这些请求可能来自不同的客户机,主Chunk将确定这些操作顺序并完成写操作。

5. Chunk把写请求传递到所有的二级副本。每个二级副本依照主Chunk分配的序列号以相同的顺序执行这些操作。
6. 所有的二级副本回复主Chunk,它们已经完成了操作。

7. 主 Chunk服务器 应答客户端,如果有副本发生错误,将出现Chunk写成功但是某些副本不成功的情况,客户端将重试。
 
    当然,实际的追加流程远远没有这么简单。追加的过程中可能出现主Chunk的Lease过期而失去chunk修改操作的授权,主Chunk或者副本机器出现故障,等等。这些追加流程的异常处理留作读者思考。


容错和诊断机制  
 
    在GSF中,组件失效被视为常态事件,组件的失效可能造成系统不可用,更糟糕的是,还可能产生不完整的数据。下面讨论CFS如何面对这些挑战,以及当组件失效不可避免的发生时,用GFS自带工具诊断系统故障。
 
 
    chunk复制
 
     每个Chunk都被复制到不同机架上的不同的Chunk服务器上。用户可以为文件命名空间的不同部分设定不同的复制级别,缺省是3

    Master服务器的复制 
 
    为了保证Master服务器的可靠性, Master服务器的状态也要复制。 Master服务器所有的操作日志和checkpoint文件都被复制到多台机器上。
GFS Master的修改操作总是先记录操作日志,然后再修改内存,当Master发生故障重启时,可以通过操作日志恢复内存数据结构;另外,为了减少Master宕机恢复时间,Master会定期将内存中的数据以checkpoint文件的形式转储到磁盘中(注:可能是其他机器的磁盘)。为了进一步提高Master的可靠性和可用性,GFS中还有影子”Master服务器(Shadow Master 它们是影子,而不是镜像,所以它们的数据可能比”Master服务器更新要慢。影子”Master服务器为了保持自身状态是最新的,它会读取一份当前正在进行的操作的日志副本,并且依照和主Master服务器完全相同的顺序来更改内部的数据结构。影子”Master服务器也会定期和Chunk服务器握手来确定它们的状态。

诊断工具
    GFS 服务器会产生大量的日志,记录了大量关键的事件(比如,  Chunk服务器启动和关闭)以及所有的RPC的 请求和回复。这些诊断日志可以随意删除,对系统的正确运行不造成任何影响。然而,只有在存储空间允 许的情况下会尽量的保存这些日志。GFS的诊断工具通过匹配请求与
回应,以及收集不同机器上的RPC日志记录,重演所有的消息交互来诊断问题。RPC日志还用来跟踪负载测试和性能分析。


负载均衡 

        Master节点管理整个系统里所有Chunk副本,在制定Chunk副本的分布策略时需要考虑多种因素,如网络的拓扑,机架的分布,磁盘的利用率等等。

   Chunk的副本有三个用途: Chunk创建,重新复制和重新负载均衡。
   

    当Master创建了一个chunk,它会根据如下因素来选择chunk副本的初始位置:(1) 新副本所在的Chunk Server的磁盘利用率低于平均水平;(2) 限制每个Chunk Server”最近”创建的数量。(3)每个chunk的所有副本不能在同一个机架。第二点容易忽略但却很重要,因为创建完chunk以后通常需要马上写入数据,如果不限制”最近”创建的数量,当一台空的Chunk Server上线时,由于磁盘利用率低,可能导致大量的chunk瞬间迁移到这台机器从而将它压垮。

 

    当Chunk的有效副本数量少于用户指定的复制因数的时候, Master节点会尝试重新复制一个chunk副本。这可能是由几个原因引起的:一个Chunk服务器不可用了, Chunk服务器报告它所存储的一个副本损坏了, Chunk服务器的一个磁盘因为错误不可用了,或者Chunk副本的复制因数提高了。每一个chunk复制任务都有一个优先级,按照优先级从高到低在Master排队等待执行,例如GFS提高会阻塞客户机程序处理流程的Chunk的优先级。

    最后,Master会定期扫描当前副本的分布情况,如果发现磁盘使用量或者机器负载不均衡,将执行重新负载均衡操作。无论是chunk创建,chunk重新复制,还是重新平衡,它们选择chunk副本位置的策略都是相同的,并且需要限制重新复制和重新平衡任务的拷贝速度,否则可能影响系统正常的读写服务。

 
垃圾回收
 

    当文件被删除后,GFS不会马上回收其物理存储,而是立刻把删除操作以日志的方式记录下来。把文件名改为一个包含删除时间戳的、隐藏的名字。Master定时检查,如果发现文件删除超过一段时间(默认为3天,可配置),那么它会把文件从内存元数据中删除,回收物理存储资源。在文件被真正删除之前,它仍能够被Master以特殊的方式访问。为了减轻Master服务器的负担,回收文件物理资源的工作交由Chunk服务器完成:在Chunk 和Master的心跳消息中,Master会回复在Master元数据中已经不存在的chunk信息,Chunk服务器才会释放这些Chunk副本的资源。

 

    另外,Chunk副本可能会因为Chunk服务器失效期间丢失了对Chunk的修改操作而导致过期。系统对每个Chunk都维护了版本号,过期的Chunk可以通过版本号检测出来。Master仍然通过正常的垃圾回收机制来删除过期的副本。

 

 

快照

    快照(Snapshot)操作是对源文件/目录进行一个”快照”操作,生成该时刻源文件/目录的一个瞬间状态存放与目标文件/目录中。GFS中使用标准的copy-on-write机制生成快照,也就是说,”快照”只是增加GFS中chunk的引用计数,表示这个chunk被快照文件引用了,等到客户端修改这个chunk时,才需要在Chunk服务器中拷贝chunk的数据生成新的chunk,后续的修改操作落到新生成的chunk上。

    为了对某个文件做Snapshot,首先需要停止这个文件的写服务,接着增加这个文件的所有chunk的引用计数,以后修改这些chunk时会拷贝生成新的chunk。对某个文件执行Snapshot的大致步骤如下:

1, 通过Lease机制收回对文件每一个chunk写权限,停止对文件的写服务;

2, Master拷贝文件名等元数据生成一个新的Snapshot文件;

3, 对执行Snapshot的文件的所有chunk增加引用计数;

    例如,对文件foo执行快照操作生成foo_backup,foo在GFS中有三个chunk C1,C2和C3。Master首先需要收回C1,C2和C3的写Lease,从而保证文件foo处于一致的状态,接着Master复制foo文件的元数据生成foo_backup,foo_backup同样指向C1,C2和C3。快照前,C1,C2和C3只被一个文件foo引用,因此引用计数为1;执行快照操作后,这些chunk的引用计数增加为2。以后客户端再次往C3追加数据时,Master发现C3的引用计数大于1,通知C3所在的Chunk Server本次拷贝C3生成C3′,客户端的追加操作也相应地转向C3′。


ChunkServer

ChunkServer管理大小均为64MB的chunk,存储的时候需要保证chunk尽可能均匀地分布在不同的磁盘之中,可能考虑的因素包括磁盘空间,最近新建chunk数,等。另外,Linux文件系统删除64MB大文件消耗的时间太长,且没有必要,删除Chunk可以只将对应的chunk文件移动到每个磁盘中的回收站,以后新建chunk的时候可以重用。

 

 

小结:

 

 

    GFS采用中心服务器的模式,该模式的最大优点是便于管理,因为中心服务器可以获知所有子服务器的状态,因而可以很方便的得知各个子服务器的负载状况等。但是这一模式也有一个比较致命的缺点,那就是单点故障。当单点故障发生在中心服务器时,将导致整个系统的不可用。不过,按照上述描述,GFS的中心服务器只是逻辑上是一个,可以知道,其实GFS的Manster还是有后备机制—shadow Master的,Master通过后备机制来应对中心服务器故障并且缩短其灾后恢复时间。

 

 

参考文献:The Google File System

猜你喜欢

转载自hnulanwei.iteye.com/blog/2217154