您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 信息化管理 > google+gfs文件系统深入分析
1摘要我们设计并实现了GoogleGFS文件系统,一个面向大规模数据密集型应用的、可伸缩的分布式文件系统。GFS虽然运行在廉价的普遍硬件设备上,但是它依然了提供灾难冗余的能力,为大量客户机提供了高性能的服务。虽然GFS的设计目标与许多传统的分布式文件系统有很多相同之处,但是,我们的设计还是以我们对自己的应用的负载情况和技术环境的分析为基础的,不管现在还是将来,GFS和早期的分布式文件系统的设想都有明显的不同。所以我们重新审视了传统文件系统在设计上的折衷选择,衍生出了完全不同的设计思路。GFS完全满足了我们对存储的需求。GFS作为存储平台已经被广泛的部署在Google内部,存储我们的服务产生和处理的数据,同时还用于那些需要大规模数据集的研究和开发工作。目前为止,最大的一个集群利用数千台机器的数千个硬盘,提供了数百TB的存储空间,同时为数百个客户机服务。在本论文中,我们展示了能够支持分布式应用的文件系统接口的扩展,讨论我们设计的许多方面,最后列出了小规模性能测试以及真实生产系统中性能相关数据。常用术语设计,可靠性,性能,测量关键词容错,可伸缩性,数据存储,集群存储1.简介为了满足Google迅速增长的数据处理需求,我们设计并实现了Google文件系统(GoogleFileSystem–GFS)。GFS与传统的分布式文件系统有着很多相同的设计目标,比如,性能、可伸缩性、可靠性以及可用性。但是,我们的设计还基于我们对我们自己的应用的负载情况和技术环境的观察的影响,不管现在还是将来,GFS和早期文件系统的假设都有明显的不同。所以我们重新审视了传统文件系统在设计上的折衷选择,衍生出了完全不同的设计思路。首先,组件失效被认为是常态事件,而不是意外事件。GFS包括几百甚至几千台普通的廉价设备组装的存储机器,同时被相当数量的客户机访问。GFS组件的数量和质量导致在事实上,任何给定时间内都有可能发生某些组件无法工作,某些组件无法从它们目前的失效状态中恢复。我们遇到过各种各样的问题,比如应用程序bug、操作系统的bug、人为失误,甚至还有硬盘、内存、连接器、网络以及电源失效等造成的问题。所以,持续的监控、错误侦测、灾难冗余以及自动恢复的机制必须集成在GFS中。2其次,以通常的标准衡量,我们的文件非常巨大。数GB的文件非常普遍。每个文件通常都包含许多应用程序对象,比如web文档。当我们经常需要处理快速增长的、并且由数亿个对象构成的、数以TB的数据集时,采用管理数亿个KB大小的小文件的方式是非常不明智的,尽管有些文件系统支持这样的管理方式。因此,设计的假设条件和参数,比如I/O操作和Block的尺寸都需要重新考虑。第三,绝大部分文件的修改是采用在文件尾部追加数据,而不是覆盖原有数据的方式。对文件的随机写入操作在实际中几乎不存在。一旦写完之后,对文件的操作就只有读,而且通常是按顺序读。大量的数据符合这些特性,比如:数据分析程序扫描的超大的数据集;正在运行的应用程序生成的连续的数据流;存档的数据;由一台机器生成、另外一台机器处理的中间数据,这些中间数据的处理可能是同时进行的、也可能是后续才处理的。对于这种针对海量文件的访问模式,客户端对数据块缓存是没有意义的,数据的追加操作是性能优化和原子性保证的主要考量因素。第四,应用程序和文件系统API的协同设计提高了整个系统的灵活性。比如,我们放松了对GFS一致性模型的要求,这样就减轻了文件系统对应用程序的苛刻要求,大大简化了GFS的设计。我们引入了原子性的记录追加操作,从而保证多个客户端能够同时进行追加操作,不需要额外的同步操作来保证数据的一致性。本文后面还有对这些问题的细节的详细讨论。Google已经针对不同的应用部署了多套GFS集群。最大的一个集群拥有超过1000个存储节点,超过300TB的硬盘空间,被不同机器上的数百个客户端连续不断的频繁访问。2.设计概述2.1设计预期在设计满足我们需求的文件系统时候,我们的设计目标既有机会、又有挑战。之前我们已经提到了一些需要关注的关键点,这里我们将设计的预期目标的细节展开讨论。◆系统由许多廉价的普通组件组成,组件失效是一种常态。系统必须持续监控自身的状态,它必须将组件失效作为一种常态,能够迅速地侦测、冗余并恢复失效的组件。◆系统存储一定数量的大文件。我们预期会有几百万文件,文件的大小通常在100MB或者以上。数个GB大小的文件也是普遍存在,并且要能够被有效的管理。系统也必须支持小文件,但是不需要针对小文件做专门的优化。◆系统的工作负载主要由两种读操作组成:大规模的流式读取和小规模的随机读取。大规模的流式读取通常一次读取数百KB的数据,更常见的是一次读取1MB甚至更多的数据。来自同一个客户机的连续操作通常是读取同一个文件中连续的3一个区域。小规模的随机读取通常是在文件某个随机的位置读取几个KB数据。如果应用程序对性能非常关注,通常的做法是把小规模的随机读取操作合并并排序,之后按顺序批量读取,这样就避免了在文件中前后来回的移动读取位置。◆系统的工作负载还包括许多大规模的、顺序的、数据追加方式的写操作。一般情况下,每次写入的数据的大小和大规模读类似。数据一旦被写入后,文件就很少会被修改了。系统支持小规模的随机位置写入操作,但是可能效率不彰。◆系统必须高效的、行为定义明确的(alex注:well-defined)实现多客户端并行追加数据到同一个文件里的语意。我们的文件通常被用于”生产者-消费者“队列,或者其它多路文件合并操作。通常会有数百个生产者,每个生产者进程运行在一台机器上,同时对一个文件进行追加操作。使用最小的同步开销来实现的原子的多路追加数据操作是必不可少的。文件可以在稍后读取,或者是消费者在追加的操作的同时读取文件。◆高性能的稳定网络带宽远比低延迟重要。我们的目标程序绝大部分要求能够高速率的、大批量的处理数据,极少有程序对单一的读写操作有严格的响应时间要求。2.2接口GFS提供了一套类似传统文件系统的API接口函数,虽然并不是严格按照POSIX等标准API的形式实现的。文件以分层目录的形式组织,用路径名来标识。我们支持常用的操作,如创建新文件、删除文件、打开文件、关闭文件、读和写文件。另外,GFS提供了快照和记录追加操作。快照以很低的成本创建一个文件或者目录树的拷贝。记录追加操作允许多个客户端同时对一个文件进行数据追加操作,同时保证每个客户端的追加操作都是原子性的。这对于实现多路结果合并,以及”生产者-消费者”队列非常有用,多个客户端可以在不需要额外的同步锁定的情况下,同时对一个文件追加数据。我们发现这些类型的文件对于构建大型分布应用是非常重要的。快照和记录追加操作将在3.4和3.3节分别讨论。2.3架构一个GFS集群包含一个单独的Master节点(alex注:这里的一个单独的Master节点的含义是GFS系统中只存在一个逻辑上的Master组件。后面我们还会提到Master节点复制,因此,为了理解方便,我们把Master节点视为一个逻辑上的概念,一个逻辑的Master节点包括两台物理主机,即两台Master服务器)、多台Chunk服务器,并且同时被多个客户端访问,如图1所示。所有的这些机器通常都是普通的Linux机器,运行着用户级别(user-level)的服务进程。我们可以很容易的把Chunk服务器和客户端都放在同一台机器上,前提是机器资源允许,并且我们能够接受不可靠的应用程序代码带来的稳定性降低的风险。4GFS存储的文件都被分割成固定大小的Chunk。在Chunk创建的时候,Master服务器会给每个Chunk分配一个不变的、全球唯一的64位的Chunk标识。Chunk服务器把Chunk以linux文件的形式保存在本地硬盘上,并且根据指定的Chunk标识和字节范围来读写块数据。出于可靠性的考虑,每个块都会复制到多个块服务器上。缺省情况下,我们使用3个存储复制节点,不过用户可以为不同的文件命名空间设定不同的复制级别。Master节点管理所有的文件系统元数据。这些元数据包括名字空间、访问控制信息、文件和Chunk的映射信息、以及当前Chunk的位置信息。Master节点还管理着系统范围内的活动,比如,Chunk租用管理(alex注:BDB也有关于lease的描述,不知道是否相同)、孤儿Chunk(alex注:orphanedchunks)的回收、以及Chunk在Chunk服务器之间的迁移。Master节点使用心跳信息周期地和每个Chunk服务器通讯,发送指令到各个Chunk服务器并接收Chunk服务器的状态信息。GFS客户端代码以库的形式被链接到客户程序里。客户端代码实现了GFS文件系统的API接口函数、应用程序与Master节点和Chunk服务器通讯、以及对数据进行读写操作。客户端和Master节点的通信只获取元数据,所有的数据操作都是由客户端直接和Chunk服务器进行交互的。我们不提供POSIX标准的API的功能,因此,GFSAPI调用不需要深入到Linuxvnode级别。无论是客户端还是Chunk服务器都不需要缓存文件数据。客户端缓存数据几乎没有什么用处,因为大部分程序要么以流的方式读取一个巨大文件,要么工作集太大根本无法被缓存。无需考虑缓存相关的问题也简化了客户端和整个系统的设计和实现。(不过,客户端会缓存元数据。)Chunk服务器不需要缓存文件数据的原因是,Chunk以本地文件的方式保存,Linux操作系统的文件系统缓存会把经常访问的数据缓存在内存中。52.4单一Master节点单一的Master节点的策略大大简化了我们的设计。单一的Master节点可以通过全局的信息精确定位Chunk的位置以及进行复制决策。另外,我们必须减少对Master节点的读写,避免Master节点成为系统的瓶颈。客户端并不通过Master节点读写文件数据。反之,客户端向Master节点询问它应该联系的Chunk服务器。客户端将这些元数据信息缓存一段时间,后续的操作将直接和Chunk服务器进行数据读写操作。我们利用图1解释一下一次简单读取的流程。首先,客户端把文件名和程序指定的字节偏移,根据固定的Chunk大小,转换成文件的Chunk索引。然后,它把文件名和Chunk索引发送给Master节点。Master节点将相应的Chunk标识和副本的位置信息发还给客户端。客户端用文件名和Chunk索引作为key缓存这些信息。之后客户端发送请求到其中的一个副本处,一般会选择最近的。请求信息包含了Chunk的标识和字节范围。在对这个Chunk的后续读取操作中,客户端不必再和Master节点通讯了,除非缓存的元数据信息过期或者文件被重新打开。实际上,客户端通常会在一次请求中查询多个Chunk信息,Master节点的回应也可能包含了紧跟着这些被请求的Chunk后面的Chunk的信息。在实际应用中,这些额外的信息在没有任何代价的情况下,避免了客户端和Master节点未来可能会发生的几次通讯。2.5Chunk尺寸Chunk的大小是关键的设计参数之一。我们选择了64MB,这个尺寸远远大于一般文件系统的Blocksize。每个Chunk的副本都以普通Linux文件的形式保存在Chunk服务器上,只有在需要的时候才扩大。惰性空间分配策略避免了因内部碎片造成的空间浪费,内部碎片或许是对选择这么大的Chunk尺寸最具争议一点。选择较大的Chunk尺寸有几个重要的优点。首先,它减少了客户端和Master节点通讯的需求,因为只需要一次和Mater节点的通信就可以获取Chunk的位置信息,之后就可以对同一个Chunk进行多次的读写操作。这种方式对降低我们的工作负载来说效果显著,因为我们的应用程序通常是连续读写大文件。即使是小规模的随机读取,采用较大的Chunk尺寸也带来明显的好处,客户端可以轻松的缓存一个数TB的工作数据集所有的Chunk位置信息。其次,采用较大的Chunk尺寸,客户端能够对一个块进行多次操作,这样就可以通过与Chunk服务器保持较长时间的TCP连接来减少网络负载。第三,选用较大的Chun
本文标题:google+gfs文件系统深入分析
链接地址:https://www.777doc.com/doc-4605047 .html