没有合适的资源?快使用搜索试试~ 我知道了~
首页The Google File System中文版 pdf
资源详情
资源评论
资源推荐

The
The
The
The Google
Google
Google
Google File
File
File
File System
System
System
System
中文版
译者: alex
alex
alex
alex
摘要
我们设计并实现了 Google GFS 文件系统,一个面向大规模数据密集型应用的、可伸缩的分
布式文件系统。 GFS 虽然运行在廉价的普遍硬件设备上,但是它依然了提供灾难冗余的能
力,为大量客户机提供了高性能的服务。
虽然 GFS 的设计目标与许多传统的分布式文件系统有很多相同之处,但是,我们的设计还
是以我们对自己的应用的负载情况和技术环境的分析为基础的,不管现在还是将来, GF S
和早期的分布式文件系统的设想都有明显的不同 。 所以我们重新审视了传统文件系统在设计
上的折衷选择,衍生出了完全不同的设计思路。
GFS 完全满足了我们对存储的需求。 GFS 作为存储平台已经被广泛的部署在 Google 内部
,
存储我们的服务产生和处理的数据,同时还用于那些需要大规模数据集的研究和开发工作
。
目前为止,最大的一个集群利用数千台机器的数千个硬盘,提供了数百 TB 的存储空间 , 同
时为数百个客户机服务。
在本论文中 , 我们展示了能够支持分布式应用的文件系统接口的扩展 , 讨论我们设计的许多
方面,最后列出了小规模性能测试以及真实生产系统中性能相关数据。
分类和主题描述
D [4]: 3 — D 分布文件系统
常用术语
设计,可靠性,性能,测量
关键词
容错,可伸缩性,数据存储,集群存储
1.
1.
1.
1.
简介
为了满足 Google 迅速增长的数据处理需求 , 我们设计并实现了 Google 文件系统 (Google File
System – GFS) 。 GFS 与传统的分布式文件系统有着很多相同的设计目标,比如,性能、可
伸缩性 、 可靠性以及可用性 。 但是 , 我们的设计还基于我们对我们自己的应用的负载情况和
技术环境的观察的影响 , 不管现在还是将来 , GFS 和早期文件系统的假设都有明显的不同
。
所以我们重新审视了传统文件系统在设计上的折衷选择,衍生出了完全不同的设计思路。
首先,组件失效被认为是常态事件,而不是意外事件。 GFS 包括几百甚至几千台普通的廉
价设备组装的存储机器,同时被相当数量的客户机访问。 GFS 组件的数量和质量导致在事
实上 , 任何给定时间内都有可能发生某些组件无法工作 , 某些组件无法从它们目前的失效状
态中恢复。我们遇到过各种各样的问题,比如应用程序 bug 、操作系统的 bug 、人为失误,
甚至还有硬盘 、 内存 、 连接器 、 网络以及电源失效等造成的问题 。 所以 , 持续的监控 、 错误
侦测、灾难冗余以及自动恢复的机制必须集成在 GFS 中。
其次 , 以通常的标准衡量 , 我们的文件非常巨大 。 数 GB 的文件非常普遍 。 每个文件通常都

包含许多应用程序对象,比如 web 文档。当我们经常需要处理快速增长的、并且由数亿个
对象构成的 、 数以 TB 的数据集时 , 采用管理数亿个 KB 大小的小文件的方式是非常不明智
的 , 尽管有些文件系统支持这样的管理方式 。 因此 , 设计的假设条件和参数 , 比如 I/O 操作
和 Block 的尺寸都需要重新考虑。
第三 , 绝大部分文件的修改是采用在文件尾部追加数据 , 而不是覆盖原有数据的方式 。 对文
件的随机写入操作在实际中几乎不存在 。 一旦写完之后 , 对文件的操作就只有读 , 而且通常
是按顺序读 。 大量的数据符合这些特性 , 比如 : 数据分析程序扫描的超大的数据集 ; 正在运
行的应用程序生成的连续的数据流 ; 存档的数据 ; 由一台机器生成 、 另外一台机器处理的中
间数据 , 这些中间数据的处理可能是同时进行的 、 也可能是后续才处理的 。 对于这种针对海
量文件的访问模式 , 客户端对数据块缓存是没有意义的 , 数据的追加操作是性能优化和原子
性保证的主要考量因素。
第四,应用程序和文件系统 API 的协同设计提高了整个系统的灵活性。比如,我们放松了
对 GFS 一致性模型的要求 , 这样就减轻了文件系统对应用程序的苛刻要求 , 大大简化了 GF S
的设计。我们引入了原子性的记录追加操作,从而保证多个客户端能够同时进行追加操作
,
不需要额外的同步操作来保证数据的一致性。本文后面还有对这些问题的细节的详细讨论 。
Google 已经针对不同的应用部署了多套 GFS 集群。最大的一个集群拥有超过 1000 个存储节
点,超过 300TB 的硬盘空间,被不同机器上的数百个客户端连续不断的频繁访问。
2.
2.
2.
2.
设计概述
2.1
2.1
2.1
2.1
设计预期
在设计满足我们需求的文件系统时候 , 我们的设计目标既有机会 、 又有挑战 。 之前我们已经
提到了一些需要关注的关键点,这里我们将设计的预期目标的细节展开讨论。
系统由许多廉价的普通组件组成,组件失效是一种常态。系统必须持续监控自身的状态 , 它
必须将组件失效作为一种常态,能够迅速地侦测、冗余并恢复失效的组件。
系统存储一定数量的大文件。我们预期会有几百万文件,文件的大小通常在 100MB 或者以
上 。 数个 GB 大小的文件也是普遍存在 , 并且要能够被有效的管理 。 系统也必须支持小文件
,
但是不需要针对小文件做专门的优化。
系统的工作负载主要由两种读操作组成 : 大规模的流式读取和小规模的随机读取 。 大规模的
流式读取通常一次读取数百 KB 的数据,更常见的是一次读取 1MB 甚至更多的数据。来自
同一个客户机的连续操作通常是读取同一个文件中连续的一个区域 。 小规模的随机读取通常
是在文件某个随机的位置读取几个 KB 数据 。 如果应用程序对性能非常关注 , 通常的做法是
把小规模的随机读取操作合并并排序 , 之后按顺序批量读取 , 这样就避免了在文件中前后来
回的移动读取位置。
系统的工作负载还包括许多大规模的 、 顺序的 、 数据追加方式的写操作 。 一般情况下 , 每次
写入的数据的大小和大规模读类似 。 数据一旦被写入后 , 文件就很少会被修改了 。 系统支持
小规模的随机位置写入操作,但是可能效率不彰。
系统必须高效的 、 行为定义明确的
( alex 注 : well-defined )
实现 多客户端并行追加数据到同
一个文件里的语意。我们的文件通常被用于 ” 生产者
-
消费者 “ 队列,或者其它多路文件合并
操作 。 通常会有数百个生产者 , 每个生产者进程运行在一台机器上 , 同时对一个文件进行追
加操作 。 使用最小的同步开销来实现的原子的多路追加数据操作是必不可少的 。 文件可以在

稍后读取,或者是消费者在追加的操作的同时读取文件。
高性能的稳定网络带宽远比低延迟重要 。 我们的目标程序绝大部分要求能够高速率的 、 大批
量的处理数据,极少有程序对单一的读写操作有严格的响应时间要求。
2.2
2.2
2.2
2.2
接口
GFS 提供了一套类似传统文件系统的 API 接口函数,虽然并不是严格按照 POSIX 等标 准
API 的形式实现的。文件以分层目录的形式组织,用路径名来标识。我们支持常用的操作
,
如创建新文件、删除文件、打开文件、关闭文件、读和写文件。
另外, GFS 提供了快照和记录追加操作。快照以很低的成本创建一个文件或者目录树的拷
贝 。 记录追加操作允许多个客户端同时对一个文件进行数据追加操作 , 同时保证每个客户端
的追加操作都是原子性的 。 这对于实现多路结果合并 , 以及 ” 生产者
-
消费者 ” 队列非常有用
,
多个客户端可以在不需要额外的同步锁定的情况下 , 同时对一个文件追加数据 。 我们发现这
些类型的文件对于构建大型分布应用是非常重要的。快照和记录追加操作将在 3.4 和 3.3 节分
别讨论。
2.3
2.3
2.3
2.3
架构
一个 GFS 集群包含一个单独的 Master 节点
( alex 注 : 这里的一个单独的 Master 节点的含义
是 GFS 系统中只存在一个逻辑上的 Master 组件 。 后面我们还会提到 Master 节点复制 , 因此
,
为了理解方便 , 我们把 Master 节点视为一个逻辑上的概念 , 一个逻辑的 Master 节点包括两
台物理主机,即两台 Master 服务器 ) 、
多台 Chunk 服务器,并且同时被多个客户端访问 , 如
图 1 所示 。 所有的这些机器通常都是普通的 Linux 机器 , 运行着用户级别 (user-level) 的服务进
程。我们可以很容易的把 Chunk 服务器和客户端都放在同一台机器上,前提是机器资源允
许,并且我们能够接受不可靠的应用程序代码带来的稳定性降低的风险。
GFS 存储的文件都被分割成固定大小的 Chunk 。在 Chunk 创建的时候, Master 服务器会给
每 个 Chun k 分配一个不变的 、 全球唯一的 64 位 的 Chun k 标识 。 Chun k 服务器 把 Chun k 以 linu x
文件的形式保存在本地硬盘上,并且根据指定的 Chunk 标识和字节范围来读写块数据。出
于可靠性的考虑,每个块都会复制到多个块服务器上。缺省情况下,我们使用 3 个存储复制
节点,不过用户可以为不同的文件命名空间设定不同的复制级别。

Master 节点管理所有的文件系统元数据 。 这些元数据包括名字空间 、 访问控制信息 、 文件 和
Chunk 的映射信息 、 以及当前 Chunk 的位置信息 。 Master 节点还管理着系统范围内的活动
,
比如 , Chun k 租用管理
(ale x 注 : BD B 也有关 于 leas e 的描述 , 不知道是否相同 ) 、
孤 儿 Chunk
(ale x
注: orphaned chunks)
的回收、以及 Chunk 在 Chunk 服务器之间的迁移。 Master 节点使用心
跳信息周期地和每个 Chunk 服务器通讯,发送指令到各个 Chunk 服务器并接收 Chunk 服务
器的状态信息。
GFS 客户端代码以库的形式被链接到客户程序里。客户端代码实现了 GFS 文件系统的 AP I
接口函数、应用程序与 Master 节点和 Chunk 服务器通讯、以及对数据进行读写操作。客户
端和 Master 节点的通信只获取元数据,所有的数据操作都是由客户端直接和 Chunk 服务器
进行交互的 。 我们不提供 POSIX 标准的 API 的功能 , 因此 , GFS API 调用不需要深入到 Linux
vnode 级别。
无论是客户端还是 Chunk 服务器都不需要缓存文件数据。客户端缓存数据几乎没有什么用
处,因为大部分程序要么以流的方式读取一个巨大文件,要么工作集太大根本无法被缓存
。
无需考虑缓存相关的问题也简化了客户端和整个系统的设计和实现 。 (不过,客户端会缓存
元数据 。 ) Chunk 服务器不需要缓存文件数据的原因是 , Chunk 以本地文件的方式保存 , Linu x
操作系统的文件系统缓存会把经常访问的数据缓存在内存中。
2.4
2.4
2.4
2.4
单一 Master
Master
Master
Master
节点
单一的 Master 节点的策略大大简化了我们的设计 。 单一的 Master 节点可以通过全局的信息
精确定位 Chunk 的位置以及进行复制决策。另外,我们必须减少对 Master 节点的读写,避
免 Master 节点成为系统的瓶颈。客户端并不通过 Master 节点读写文件数据。反之,客户端
向 Master 节点询问它应该联系的 Chunk 服务器。客户端将这些元数据信息缓存一段时间,
后续的操作将直接和 Chunk 服务器进行数据读写操作。
我们利用图 1 解释一下一次简单读取的流程 。 首先 , 客户端把文件名和程序指定的字节偏移
,
根据固定的 Chunk 大小,转换成文件的 Chunk 索引。然后,它把文件名和 Chunk 索引发送
给 Master 节点。 Master 节点将相应的 Chunk 标识和副本的位置信息发还给客户端。客户端
用文件名和 Chunk 索引作为 key 缓存这些信息。
之后客户端发送请求到其中的一个副本处,一般会选择最近的。请求信息包含了 Chunk 的
标识和字节范围 。 在对这个 Chunk 的后续读取操作中 , 客户端不必再和 Master 节点通讯了
,
除非缓存的元数据信息过期或者文件被重新打开 。 实际上 , 客户端通常会在一次请求中查询
多 个 Chun k 信息 , Maste
r
节点的回应也可能包含了紧跟着这些被请求 的 Chun k 后面 的 Chun k
的信息 。 在实际应用中 , 这些额外的信息在没有任何代价的情况下 , 避免了客户端和 Maste
r
节点未来可能会发生的几次通讯。
2.5
2.5
2.5
2.5
Chunk
Chunk
Chunk
Chunk
尺寸
Chunk 的大小是关键的设计参数之一。我们选择了 64MB ,这个尺寸远远大于一般文件系统
的 Block size 。 每个 Chunk 的副本都以普通 Linux 文件的形式保存在 Chunk 服务器上 , 只有
在需要的时候才扩大 。 惰性空间分配策略避免了因内部碎片造成的空间浪费 , 内部碎片或许
是对选择这么大的 Chunk 尺寸最具争议一点。

选择较大的 Chunk 尺寸有几个重要的优点。首先,它减少了客户端和 Master 节点通讯的需
求 , 因为只需要一次和 Mater 节点的通信就可以获取 Chunk 的位置信息 , 之后就可以对同一
个 Chunk 进行多次的读写操作。这种方式对降低我们的工作负载来说效果显著,因为我们
的应用程序通常是连续读写大文件。即使是小规模的随机读取,采用较大的 Chunk 尺寸也
带来明显的好处,客户端可以轻松的缓存一个数 TB 的工作数据集所有的 Chunk 位置信息
。
其次 , 采用较大 的 Chun k 尺寸 , 客户端能够对一个块进行多次操作 , 这样就可以通过 与 Chun k
服务器保持较长时间的 TCP 连接来减少网络负载。第三,选用较大的 Chunk 尺寸减少 了
Master 节点需要保存的元数据的数量 。 这就允许我们把元数据全部放在内存中 , 在 2.6.1 节我
们会讨论元数据全部放在内存中带来的额外的好处。
另一方面,即使配合惰性空间分配,采用较大的 Chunk 尺寸也有其缺陷。小文件包含较少
的 Chunk ,甚至只有一个 Chunk 。当有许多的客户端对同一个小文件进行多次的访问时 , 存
储这些 Chunk 的 Chunk 服务器就会变成热点。在实际应用中,由于我们的程序通常是连续
的读取包含多个 Chunk 的大文件,热点还不是主要的问题。
然而,当我们第一次把 GFS 用于批处理队列系统的时候,热点的问题还是产生了:一个可
执行文件 在 GF S 上保存 为 single-chun k 文件 , 之后这个可执行文件在数百台机器上同时启动
。
存放这个可执行文件的几个 Chunk 服务器被数百个客户端的并发请求访问导致系统局部过
载 。 我们通过使用更大的复制参数来保存可执行文件 , 以及错开批处理队列系统程序的启动
时间的方法解决了这个问题 。 一个可能的长效解决方案是 , 在这种的情况下 , 允许客户端从
其它客户端读取数据。
2.6
2.6
2.6
2.6
元数据
Master 服务器
( alex 注 : 注意逻辑的 Master 节点和物理的 Master 服务器的区别 。 后续我们
谈的是每个 Master 服务器的行为,如存储、内存等等,因此我们将全部使用物理名称)
存
储 3 种主要类型的元数据,包括:文件和 Chunk 的命名空间、文件和 Chunk 的对应关系 、 每
个 Chunk 副本的存放地点。所有的元数据都保存在 Master 服务器的内存中。前两种类型的
元数据(命名空间、文件和 Chunk 的对应关系)同时也会以记录变更日志的方式记录在操
作系统的系统日志文件中,日志文件存储在本地磁盘上,同时日志会被复制到其它的远 程
Master 服务器上。采用保存变更日志的方式,我们能够简单可靠的更新 Master 服务器的状
态,并且不用担心 Master 服务器崩溃导致数据不一致的风险。 Master 服务器不会持久保 存
Chunk 位置信息 。 Master 服务器在启动时 , 或者有新的 Chunk 服务器加入时 , 向各个 Chun k
服务器轮询它们所存储的 Chunk 的信息。
2.6.1
2.6.1
2.6.1
2.6.1
内存中的数据结构
因为元数据保存在内存中,所以 Master 服务器的操作速度非常快。并且, Master 服务器可
以在后台简单而高效的周期性扫描自己保存的全部状态信息 。 这种周期性的状态扫描也用于
实现 Chunk 垃圾收集、在 Chunk 服务器失效的时重新复制数据、通过 Chunk 的迁移实现 跨
Chunk 服务器的负载均衡以及磁盘使用状况统计等功能 。 4.3 和 4.4 章节将深入讨论这些行为 。
将元数据全部保存在内存中的方法有潜在问题 : Chunk 的数量以及整个系统的承载能力都受
限于 Master 服务器所拥有的内存大小 。 但是在实际应用中 , 这并不是一个严重的问题 。 Maste
r
服务器只需要不到 64 个字节的元数据就能够管理一个 64MB 的 Chunk 。 由于大多数文件都包
含多个 Chunk , 因此绝大多数 Chunk 都是满的 , 除了文件的最后一个 Chunk 是部分填充的
。
同样的 , 每个文件的在命名空间中的数据大小通常在 64 字节以下 , 因为保存的文件名是用前
剩余28页未读,继续阅读














安全验证
文档复制为VIP权益,开通VIP直接复制

评论9