GFS论文整理(一)

摘要:

    我们设计并实现了GFS:一个高扩展性,适用于数据密集型应用的分布式文件系统。运行在廉价的商用服务器上,它提供了容错能力,它能够在大量客户端请求时提供较好的整体性能。

    当享用众多具有同样上述目的的分布式文件系统时,我们的设计驱动力来对应用的工作量和技术环境,无论是当前还是预期,也折射出与早期的文件系统的背离。这些引导我们重新检测传统选择或者探索一个不同的设计方式。

    这种文件系统比较成功的满足了我们的存储需要,它作为一个数据的存储和处理平台被广泛的应用在google,作为研究和开发大数据集合数据。最大的分布式数据能够提供成千上万TB的数据存储,存储在无数个硬盘和机器上,同时可以支持大量的客户端并发调用。

   

简介:

    我们已经设计和实现了GFS来满足在大数据处理方面快速增长的需要,GFS  和先前的文件系统,具

有相同的目标:扩展性,可用性,可靠性。

    首先,组件故障是一个平常的事情而不是异常。GFS系统可能会有上千台机器组成,而且也会有相当级别的客户端(调用),组件的数量和质量实质上决定了某时的可用性和数据的恢复能力,我们遇到过很多问题,它们是有多方面原因造成的,例如应用的bug,操作系统的bug,人为的错误,硬盘问题,内存,网络,电力供应等等。所以,持续的监控,错误检测,容错,自动恢复这些特性将被融入整个系统。

 

    再者,对于传统的标准而言,这些文件将是很庞大的,数GB的文件是很常见的。每个文件会包含许多像web文档这样的数据,当我们定期的去处理这些数TB的这种特性的数据. 快速增长的数据集合时,会发现管理它们将是一件很棘手的事情,尽管文件系统能够支持它。因此,设计假设和IO操作的参数/block尺寸等,需要重新对待。

    第三,大部分文件数据的变更是通过append(追加)而不是重写的方式,在一个文件内随机写操作几乎是不存在的。一旦写入,那么这个文件只读,并且经常是有序读。有些能够构成大仓储,数据分析程序能够扫描。有些或许是应用程序持续产生的数据流。有些或许是档案数据,有些或许是供其他机器处理的中间数据(实时或者稍后)。针对这些特定的大文件存储方式,appending成为了性能优化和原子性保证的焦点,同时在客户端缓存数据的方式失去了优势。

    第四,联合设计应用和文件系统api,通过增加我们的灵活性,使整个系统收益。例如,我们放松了GFS的数据一致性模型,大大简化了文件系统的设计,并且没有给应用系统增加额外的负担。我们引入了原子性append操作,可以让多个客户端操作并发的append一个文件,在它们之间却无需额外的同步。

    多个GFS分布式环境应用与不同的目的,最大的一个超过1000个存储节点,超过300TB的硬盘存储,并且被无数个客户端大量的访问着。

 

设计总览:

    在设计这个文件系统时,预期的设想使我们遇到了很多挑战。我们展示以下GFS设计的关键点。

    1)系统构建在廉价的商业服务器上,且它们会经常出现故障。系统需要持续的自我监测,检测/容忍/并能在故障时及时修复。

    2)系统存储适当量的大文件,我们预期有数百万的文件,文件在100M左右,当然GB级别的文件也是很常有的并且需要被高效的管理。小文件也必须支持,但是我们可能不会优化它们(意思是,针对大文件存储,是优化的重点)

    3)主要包括2种方式的read:大数据流read和小随即读。在大数据流读中,个别的操作是读取上百KB1MB或者更大的读取将是很常见的。同一客户端的连续操作经常会读取一个文件邻近的region。小随即读通常会在任意的offset读取几个KB的数据。对于性能敏感的应用经常批量和排序这些small reads,稳步向前操作文件,而不是来回移动。(顺序读取)

    4)还会有很多大数据/顺序写操作,通过向文件append的方式进行。我们的文件经常作为producer-consumer(生产者-消费者)队列或者多路合并。多个生产者运行在一台机器上,将会并发的append文件。原子性与最小同步开销是必不可少的。

    5)持续的高带宽比低延迟更加重要。我们的大部分目标应用,要求对大量数据的处理速度,而不是个别read或者write上严格的响应时间。

 

    GFS提供了一些类似的文件系统接口,虽然它没有按照规范的API例如POSIX。文件通过目录层级组织起来,通过路径名称来识别。我们支持常用的操作如create/deleteopenclosereadwrite

    此外,GFS具有snapshot(快照)和记录追加(record append)操作。snapshot以较少的开支创建一个文件或者目录树(directory tree)的copyRecord append允许多个客户端并发的在同一个文件中追加数据,同时尚可确保每个client append操作的原子性,这对实现多路合并结果(multi-way merge)很有用,producer-consumer队列可以被多个客户端同时append而无需多余的lock。我们发现这些文件特性在构建大规模分布式应用时具有重要价值。

 

架构:

    一个GFS分布式环境,有一个master和多个chunkserver构成,它可以被多个客户端访问。这些(serverclient)通常是一些运行着用户级别的服务程序的商用linux机器。chunkserverclient运行在同一台机器也是很容易的,当然前提是机器的资源是允许使用的,同时较低的可用性是可以接受的。

    文件被分成固定尺寸的chunks,每个chunk通过一个全局不变的64chunk handle来标识,这个chunk handlechunk创建时master机器分配的。chunkserverlinux文件的方式把chunks存储在本地磁盘上,对于read/write数据时将会操作由chunk handle和字节区间(byte range)指定的chunk。为了可用性,每个chunk被复制分散在多台机器上;默认情况下,每个chunkreplicas3个,当然用户可以指定不同的file namespace中的region具有不同的replication的级别。

    Master机器保存了文件系统的所有metadata(元数据),包括namespace(命名空间),访问权限控制,文件与chunks的影射关系,还有当前chunks的位置。它(master)也控制系统范围内的activities(活动),例如chunk lease(契约)管理,孤立(失效)chunk的回收,chunkserver chunk的迁移(migration)。master会间歇性的与每个chunkserver通讯,在heartbeat messages(心跳消息)中发送指令和收集chunkserver的状态。

    GFS客户端程序(client code)会被引入到实现文件系统API的应用中,应用程序通过client codemasterchunkserver交互,来实现对数据的readwriteClientmaster交互进行metadata方面的操作,但是实际数据的交互将直接与chunkserver通信。我们没有提供POSIX  API,因此将不需要挂载到linux vnode层。

    clientchunkserver均不会缓存文件数据。client缓存收益甚微,因为大部分应用stream through庞大的文件或者加工的数据的太大而无法缓存。没有缓存,意味着将无需考虑缓存数据同步的因素,这简化了客户端以及整个系统的设计。chunkservers也无需缓存文件数据,因为chunks存储在本地文件文件中,linux buffer cache已经把这些频繁访问的数据保存了在内存中。

 

Master

    Master很大程度上简化了我们的设计,使得master能够使用全局知识(global knowledge)来做复杂的chunk置放和复制方面的决策。此外,我们必须最小化对master的调用,所以master不会成为cluster的瓶颈。client从不通过masterreadwrite文件数据,相反,client会询问master 去连接哪个chunkserverclient会缓存这些信息,接下来操作就是clientchunkserver直接交互。

 

 

    让我们解释一下一个简单的read操作的交互过程,参见图1.首先,使用固定chunk sizeclient将应用指定的文件名称和byte offset转换成文件系统的一个chunk索引(filename byte offset可以最终确定为某个file中的特定chunk信息)。然后,它(client)向master发送一个包含文件明和chunk索引的请求,master响应给client相应的chunk handlereplicas的位置。Client使用fileNamechunk index作为key来缓存这些信息。

    此后client向其中一个replicas发送请求,多数情况下是最近的一个replicas。请求指定了chunk handle和此chunk中的byte range。后续对同一个chunk reads将无需与master交互,直到cache过期或者file被重新打开。事实上,client通常会在一次master交互中询问多个chunk的情况,避免了以后client-master的多次交互,事实上也不会带来额外的性能开支。

 

Chunk Size

    chunk size是一个关键的设计参数,我们选择了64MB,这个值通常比文件系统的block size要大很多。每个chunk replicas都是作为一个普通的linux文件存储在server上,并且会在需要的时候扩展它。延迟空间分配策略避免了对存储空间的浪费(内部碎片),也许最大的反对点就是这种大尺寸的chunk

    一个大尺寸的chunk你能够提供一些重要的优势。首先,它降低了clientmaster交互的次数,因为readwrite同一个chunk只需要初始时与master一次交互获取chunk位置即可。它的降低,对于我们的workloads来说特别显著,因为应用大多数是顺序的readwrite一个大文件。即使一些小的随即度操作(small random reads),客户端能够适当的缓存数TB数据中所有的chunk位置信息。再者,对于一个较大的chunk,客户端能够运行大量操作在此指定的chunk上,它能够通过保持现有的TCP连接(client-->chunkserver的连接)来降低网络开销。第三,它(大尺寸chunk设计)降低了mastermetadata的存储尺寸,这就允许我们把metadata存储在内存中,也会带来其他的优势(接下来讨论)。

    另一个方面开说,大尺寸chunk,即使采用延迟空间分配,也会有它的缺点。小文件包含少量的chunk,或许只有一个。在多个客户端访问同一个文件时,存储这些chunkchunkserver可能成为热点(hot spots)。实践中,hot spots还不是一个主要的问题,因为我们的应用大多数情况下是顺序read一个多chunks的大文件。

    可是,在hotspots尚未发展时,GFS开始使用的是批量队列系统:一个可执行文件作为一个single-chunk的文件被写入到GFS,然后同时在多个机器上启动。存储这个可执行文件(executeable)的几个chunkservers在数个请求同时访问时可能会过载。我们解决了这个问题,通过使用更高的复制因子(higher replication factor)存储这个执行文件,使被处理队列系统错开应用启动的时间。在这种情况下,一个潜在的解决办法就是允许客户端可以从其他客户端读取数据。(事实上此解决办法是不可取的)

 

Metadata

    master存储3个主要类型的metadatafile and chunk namespaces(文件和chunk的命名空间),the mapping from files to chunks(文件与chunk影射关系),the location of each chunks‘ replicaschunk replicas位置)。这些元数据保存在master的内存中。前2种类型的metadatanamespaces file-chunk mapping)也会通过记录变更的方式持久存储一个操作日志文件中(operation log),这个操作日志文件存储在master的本地磁盘并且被replicated在其他的远程机器上(和chunk的机制一样)。有了日志,我们就能够简单而且可靠的去更新master的状态,无需担心master机器crash所带来的不一致问题。

    因为metadata存储在内存中,master操作将是很迅速的。此外,对与master后台间歇性扫描整个state也将是很简单和高效的。间歇性扫描,是用来实现chunk回收/重复制故障机器的chunk/chunk迁移(负载均衡,和跨chunkserver磁盘空间使用率)。

    这种内存存储方式,有一个潜在的顾虑是chunk的数量,因为整个系统的容量会受到master内存大小的限制。在实践中,这似乎不是一个很严重的限制。每个64MBchunk,在master中之需要64Bmetadata存储,大部分chunk都是满的(full)因为通常一个文件会包含多个chunks,只有最后一个(chunk)是可以被filled(填充数据)。类似,file namespace数据通常只需要少于64B的数据,因为它(master)存储file names会进行前缀压缩。

    如果需要支撑更大的文件系统,那么给master机器增加内存也是很简单和廉价的。因此将metadata内存储存,可以获得灵活性/性能/可用性/简易性等。

 

Chunk位置:

    master不会持久存储chunkserver所持有的replicas信息,它(master)仅仅是在启动后去各个chuankserverpoll这些数据,然后会保持自己所持有chunk信息的更新,因为它控制了所有chunk位置分配,以及使用定期的heartbeat消息监控chunkserver的状态。

    我们起初尝试过在master上持久存储chunk位置信息,但是我们觉得master启动时从chunkserver请求这些数据然后间歇性同步的设计更加简单。这样可以避免一些问题:保持masterchunkservers的同步(chunkserver的加入,离群),修改名称失败,重启等等。在一个具有数百台机器的分布式环境中,这些情况还是会经常发生的。

    可以从另一个方向来认识这种设计,chunkserver上是否持有chunkchunkserver具有最终决定权。那就没有必要在master中再持久存储一份视图数据,而且chunkserver的一些error会导致chunk信息的丢失(硬盘损坏或者不可用),甚至有的操作会重命名chunkserver


GFS论文整理(二):[http://shift-alt-ctrl.iteye.com/blog/1842286]
GFS论文整理(三):[http://shift-alt-ctrl.iteye.com/blog/1842509]
GFS论文整理(四):[http://shift-alt-ctrl.iteye.com/blog/1842510]

猜你喜欢

转载自shift-alt-ctrl.iteye.com/blog/1842245
GFS