Google文件系统(一)

译自The Google File System

作者:Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung

摘要

我们设计并实现了面向大规模数据密集型应用的可扩展文件系统GFS。 GFS虽然运行在普遍硬件设备上,但依然具备灾难冗余能力,为大量客户机提供高性能服务。

GFS的设计目标虽然与传统的分布式文件系统有很多相同之处,但我们的设计是基于对Google应用当前和未来负载情况和技术环境的分析,因此与早期的分布式文件系统的设想存在明显的差异。所以我们重新审视了传统文件系统,最后得出了完全不同的设计思路。

GFS完全满足了我们的存储需求。作为存储平台,GFS已经在Google内部得到广泛部署,用于存储服务产生和处理的数据,同时还支持需要大规模数据集的研究和开发工作。目前为止,最大的集群利用数千台机器的数千个硬盘提供了数百TB的存储空间,同时服务数百个客户机。

本文介绍了能够支持分布式应用的文件系统接口的扩展、GFS的设计、小规模性能测试结果及真实生产系统中的性能相关数据。

1 引言

我们设计并实现了适用于大规模数据密集型应用的可扩展文件系统GFS,满足Google不断提高的数据处理需求。GFS在性能、可扩展性、可靠性和可用性方面的设计目标与很多传统的分布式文件系统相似。

但GFS的设计主要还是基于对Google当前和未来应用负载情况和技术环境的观察和分析,因而与早期文件系统的设计存在显著不同。基于对传统文件系统的分析,我们设计出了全新的分布式文件系统。

第一,组件失效时常态而非异常。文件系统由数百台甚至上千台配置较低的存储机器构成,每台客户机的访问量很大。组件的数量和质量决定了机器可能会出现故障,且可能无法恢复。我们遇到过应用程序bug、操作系统bug、人为失误以及硬盘、内存、连接器、网络及电源故障引起的各种问题。因此,GFS必须含有不间断的监控、错误监测、灾难冗余以及自动恢复机制。

第二,文件很大。数GB的文件非常常见。每个文件一般都包含很多应用程序对象,如web文档。处理数亿个对象构成且快速增长的TB级数据集时,传统的管理数亿个KB级小文件的方式并不适用。 因此,设计时必须重新考虑假设条件和参数,如I/O操作和Block的大小。

第三,对绝大部分文件的修改是采用在文件尾部追加数据而非覆盖原有数据的方式。现实中几乎不存在对文件的随机写。写入之后,只能按顺序读取文件。 很多数据都具备这类特征,比如数据分析程序扫描的大型数据集,正在运行的应用程序连续生成的数据流,存档数据,以及在一台机器上生成、另一台机器上同步或异步处理的中间数据。对于海量数据的访问,客户端的缓存数据块是没有用武之地的,数据追加操作才是性能优化和原子性保证重点。

第四,应用程序与文件系统API的协同设计降低了对GFS一致性模型的要求,在不对应用程序造成负担的前提下简化了文件系统。通过原子性追加操作,保证了多个客户端能够同时进行追加操作,不需要额外的同步操作。下文将对这些问题展开详细讨论。

Google已针对不同的应用部署了多套GFS集群。最大的集群有1000多个存储节点,300多TB的硬盘空间,被多台机器上的数百个客户端连续频繁访问。

2 设计概述

2.1 设计目标

文件系统的设计要有一定的挑战性和创新空间。之前我们已经提到了一些关键点,现在来详细讨论设计目标。

系统由很多普通商用组件构成,组件失效是常态。系统必须持续监控自身的状态,迅速侦测、冗余并恢复失效组件。

系统存储一定数量的大文件,预期约为几百万,文件的大小通常为100MB及以上。数GB大小的文件也很常见,且需进行有效管理。系统也需要支持小文件,但不需要对此进行专门的优化。

系统的工作负载主要由两类读操作组成:大规模的流式读取和小规模的随机读取。大规模的流式读取通常一次读取几百KB的数据,多位1MB甚至更多的数据。来自同一个客户机的连续操作通常是读取同一个文件中的一个连续区域。小规模的随机读取通常是从文件的某个随机位置读取几KB数据。 如果应用程序对性能要求非常高,一般会合并并排序小规模的随机读取操作,之后按顺序批量读取,从而避免在文件中来回读取。

系统的工作负载还包括许多大规模的顺序追加写操作。一般情况下,每次写入的数据大小与大规模读相近。一旦写入后,文件就很少会被修改了。系统支持小规模的随机位置写入操作,但效率一般。

系统必须高效地将多个客户端的数据并行追加到同一个文件里。我们的文件通常用于“生产者-消费者”队列或多路文件合并。通常情况下,运行在不同机器上的数百个生产者会同时对一个文件进行追加操作,因此,以最小的同步开销实现原子性多路数据追加操作非常重要。消费者可稍后读取文件,也可以在追加的同时读取。

高性能的稳定网络带宽比低延迟更重要。我们绝大多数目标程序要求能够快速大批量地处理数据,很少有程序对单一的读写操作有严格的响应时间要求。

2.2 接口

GFS提供了一套类似传统文件系统的API接口函数,但接口并不是严格按照POSIX等标准API的形式实现的。文件以分层目录的形式组织,用路径名来标识。我们支持常用的操作,包括创建、删除、打开、关闭以及读写文件。

另外,GFS能够快照并记录追加操作。快照能以较低的成本创建文件或目录树副本。记录追加操作支持多个客户端同时对一个文件进行数据追加操作,保证每个客户端的追加操作都是原子性的。这对于实现多路结果合并及“生产者-消费者”队列非常有用,多个客户端可以在不需要额外同步锁定的情况下,同时对一个文件追加数据。我们发现这类文件对于构建大型分布应用非常重要。快照和记录追加操作的功能将在第3.4和3.3节分别讨论。

2.3 架构

一个GFS集群包含一个Master节点和多台数据块服务器,同时被多个客户端访问,如图1所示。这些机器一般是商用Linux机器,运行着用户级的服务进程。只要机器资源允许,且能够接受不可靠应用程序代码对稳定性的影响,便可以把数据块服务器和客户端部署在同一台机器上。

图1 GFS架构

GFS存储的文件都被分割成固定大小的数据块。创建数据块时,Master服务器会给每个数据块分配不变且唯一的64位标识。数据块服务器以Linux文件的形式把数据块存储在本地硬盘上,根据指定的数据块标识和字节范围读写数据块。为了提高可靠性,每个数据块都会复制到多个数据块服务器上。缺省条件下,我们使用3个存储复制节点,不过用户可以为不同的文件命名空间设定不同的复制级别。

Master节点管理所有文件系统的元数据,包括命名空间、访问控制信息、文件和数据块的映射信息以及当前数据块的位置信息。Master节点还管理着系统范围内的相关活动,如数据块租用管理、孤立数据块回收以及数据块在数据块服务器之间的迁移。

Master节点定期使用心跳信息与每个数据块服务器通讯,向各个数据块服务器发送指令,并接收数据块服务器的状态信息。

GFS客户端代码以库的形式链接到客户程序中,客户端代码实现了GFS文件系统的API接口函数,并与Master节点和数据块服务器通讯,完成应用程序对数据的读写操作。客户端和Master节点的通信只获取元数据,所有的数据操作都是由客户端与数据块服务器直接交互完成的。我们不提供POSIX标准的API功 能,因此GFS API调用不需要深入到Linux vnode级别。

客户端和Chunk服务器均不缓存文件数据。客户端缓存数据几乎没有什么用处,因为大部分程序要么以流的方式读取大型文件,要么工作集太大根本无法被缓存。不考虑缓存问题也简化了客户端和整个系统的设计和实现。(但客户端会缓存元数据。)数据块服务器不需要缓存文件数据,因为数据块以本地文件的形式保存,Linux操作系统的文件系统缓存会把经常访问的数据缓存在内存中。

参考资料

  1. Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung. The Google File System
  2. Yan Wei. The Google File System中文版

转载于:https://juejin.im/post/5d0b24cb5188256c6e487d32

猜你喜欢

转载自blog.csdn.net/weixin_34072857/article/details/93177428