乐趣区

关于大数据:大数据理论篇HDFS的基石Google-File-System

Google File System

但但凡要开始讲大数据的,都绕不开最后的 Google 三驾马车:Google File System(GFS),MapReduce,BigTable。

为这所有的根底的 Google File System,岂但没有任何垮台的迹象,还在一直的演变,事实上撑持着 Google 这个宏大的互联网公司的所有计算。

以下是原文内容,内容较长,倡议具体浏览。

摘要

​ 咱们设计并实现了 Google GFS 文件系统,一个面向大规模数据密集型利用的、可伸缩的分布式文件系统。
GFS 尽管运行在便宜的广泛硬件设施上,然而它仍然了提供劫难冗余的能力,为大量客户机提供了高性能的服务。
​ 尽管 GFS 的设计指标与许多传统的分布式文件系统有很多相同之处,然而,咱们的设计还是以咱们对本人的利用的负载状况和技术环境的剖析为根底的,不论当初还是未来,GFS 和晚期的分布式文件系统的构想都有显著的不同。所以咱们从新扫视了传统文件系统在设计上的折衷抉择,衍生出了齐全不同的设计思路。
​ GFS 齐全满足了咱们对存储的需要。GFS 作为存储平台曾经被宽泛的部署在 Google 外部,存储咱们的服务产生和解决的数据,同时还用于那些须要大规模数据集的钻研和开发工作。目前为止,最大的一个集群利用数千台机器的数千个硬盘,提供了数百 TB 的存储空间,同时为数百个客户机服务。
​ 在本论文中,咱们展现了可能反对分布式应用的文件系统接口的扩大,探讨咱们设计的许多方面,最初列出了小规模性能测试以及实在生产零碎中性能相干数据。

1 简介

​ 为了满足 Google 迅速增长的数据处理需要,咱们设计并实现了 Google 文件系统(Google File System – GFS)。GFS 与传统的分布式文件系统有着很多雷同的设计指标,比方,性能、可伸缩性、可靠性以及可用性。
​ 然而,咱们的设计还基于咱们对咱们本人的利用的负载状况和技术环境的察看的影响,不论当初还是未来,GFS 和晚期文件系统的假如都有显著的不同。所以咱们从新扫视了传统文件系统在设计上的折衷抉择,衍生出了齐全不同的设计思路。

  • 首先,组件生效被认为是常态事件,而不是意外事件。GFS 包含几百甚至几千台一般的便宜设施组装的存储机器,同时被相当数量的客户机拜访。GFS 组件的数量和品质导致在事实上,任何给定工夫内都有可能产生某些组件无奈工作,某些组件无奈从它们目前的生效状态中复原。咱们遇到过各种各样的问题,比方应用程序 bug、操作系统的 bug、人为失误,甚至还有硬盘、内存、连接器、网络以及电源生效等造成的问题。所以,继续的监控、谬误侦测、劫难冗余以及主动复原的机制必须集成在 GFS 中。
  • 其次,以通常的规范掂量,咱们的文件十分微小。数 GB 的文件十分广泛。每个文件通常都蕴含许多应用程序对象,比方 web 文档。当咱们常常须要解决快速增长的、并且由数亿个对象形成的、数以 TB 的数据集时,采纳治理数亿个 KB 大小的小文件的形式是十分不明智的,只管有些文件系统反对这样的治理形式。因而,设计的假如条件和参数,比方 I/O 操作和 Block 的尺寸都须要重新考虑。
  • 第三,绝大部分文件的批改是采纳在文件尾部追加数据,而不是笼罩原有数据的形式。对文件的随机写入操作在理论中简直不存在。一旦写完之后,对文件的操作就只有读,而且通常是按程序读。大量的数据合乎这些个性,比方:数据分析程序扫描的超大的数据集;正在运行的应用程序生成的间断的数据流;存档的数据;由一台机器生成、另外一台机器解决的两头数据,这些两头数据的解决可能是同时进行的、也可能是后续才解决的。对于这种针对海量文件的拜访模式,客户端对数据块缓存是没有意义的,数据的追加操作是性能优化和原子性保障的次要考量因素。
  • 第四,应用程序和文件系统 API 的协同设计进步了整个零碎的灵活性。比方,咱们放松了对 GFS 一致性模型的要求,这样就加重了文件系统对应用程序的刻薄要求,大大简化了 GFS 的设计。咱们引入了原子性的记录追加操作,从而保障多个客户端可能同时进行追加操作,不须要额定的同步操作来保证数据的一致性。本文前面还有对这些问题的细节的具体探讨。
    Google 曾经针对不同的利用部署了多套 GFS 集群。最大的一个集群领有超过 1000 个存储节点,超过 300TB 的硬盘空间,被不同机器上的数百个客户端连续不断的频繁拜访。

2 设计概述

2.1 设计预期

​ 在设计满足咱们需要的文件系统时候,咱们的设计指标既有机会、又有挑战。之前咱们曾经提到了一些须要关注的关键点,这里咱们将设计的预期指标的细节展开讨论。
​ 零碎由许多便宜的一般组件组成,组件生效是一种常态。零碎必须继续监控本身的状态,它必须将组件生效作为一种常态,可能迅速地侦测、冗余并复原生效的组件。零碎存储肯定数量的大文件。咱们预期会有几百万文件,文件的大小通常在 100MB 或者以上。数个 GB 大小的文件也是普遍存在,并且要可能被无效的治理。零碎也必须反对小文件,然而不须要针对小文件做专门的优化。

​ 零碎的工作负载次要由两种读操作组成:大规模的流式读取和小规模的随机读取。大规模的流式读取通常一次读取数百 KB 的数据,更常见的是一次读取 1MB 甚至更多的数据。来自同一个客户机的间断操作通常是读取同一个文件中间断的一个区域。小规模的随机读取通常是在文件某个随机的地位读取几个 KB 数据。如果应用程序对性能十分关注,通常的做法是把小规模的随机读取操作合并并排序,之后按程序批量读取,这样就防止了在文件中前后来回的挪动读取地位。零碎的工作负载还包含许多大规模的、程序的、数据追加形式的写操作。个别状况下,每次写入的数据的大小和大规模读相似。数据一旦被写入后,文件就很少会被批改了。零碎反对小规模的随机地位写入操作,然而可能效率不彰。零碎必须高效的、行为定义明确的 2 实现多客户端并行追加数据到同一个文件里的语意。咱们的文件通常被用于“生产者 - 消费者”队列,或者其它多路文件合并操作。通常会有数百个生产者,每个生产者过程运行在一台机器上,同时对一个文件进行追加操作。应用最小的同步开销来实现的原子的多路追加数据操作是必不可少的。文件能够在稍后读取,或者是消费者在追加的操作的同时读取文件。高性能的稳固网络带宽远比低提早重要。咱们的目标程序绝大部分要求可能高速率的、大批量的解决数据,极少有程序对繁多的读写操作有严格的响应工夫要求。

2.2 接口

​ GFS 提供了一套相似传统文件系统的 API 接口函数,尽管并不是严格依照 POSIX 等规范 API 的模式实现的。文件以分层目录的模式组织,用路径名来标识。咱们反对罕用的操作,如创立新文件、删除文件、关上
文件、敞开文件、读和写文件。
另外,GFS 提供了快照和记录追加操作。快照以很低的老本创立一个文件或者目录树的拷贝。记录追加操作容许多个客户端同时对一个文件进行数据追加操作,同时保障每个客户端的追加操作都是原子性的。这对于实现多路后果合并,以及“生产者 - 消费者”队列十分有用,多个客户端能够在不须要额定的同步锁定的状况下,同时对一个文件追加数据。咱们发现这些类型的文件对于构建大型散布利用是十分重要的。快照和记录追加操作将在 3.4 和 3.3 节别离探讨。

2.3 架构

​ 一个 GFS 集群蕴含一个独自的 Master 节点 3、多台 Chunk 服务器,并且同时被多个客户端拜访,如图 1 所示。所有的这些机器通常都是一般的 Linux 机器,运行着用户级别 (user-level) 的服务过程。咱们能够很容易的把 Chunk 服务器和客户端都放在同一台机器上,前提是机器资源容许,并且咱们可能承受不牢靠的利用程序代码带来的稳定性升高的危险。

​ GFS 存储的文件都被宰割成固定大小的 Chunk。在 Chunk 创立的时候,Master 服务器会给每个 Chunk 调配一个不变的、寰球惟一的 64 位的 Chunk 标识。Chunk 服务器把 Chunk 以 Linux 文件的模式保留在本地硬盘上,并且依据指定的 Chunk 标识和字节范畴来读写块数据。出于可靠性的思考,每个块都会复制到多个块服务器上。缺省状况下,咱们应用 3 个存储复制节点,不过用户能够为不同的文件命名空间设定不同的复制级别。
​ Master 节点治理所有的文件系统元数据。这些元数据包含名字空间、访问控制信息、文件和 Chunk 的映射信息、以及以后 Chunk 的地位信息。Master 节点还治理着零碎范畴内的流动,比方,Chunk 租用治理、孤儿 Chunk 的回收、以及 Chunk 在 Chunk 服务器之间的迁徙。Master 节点应用心跳信息周期地和每个 Chunk 服务器通信,发送指令到各个 Chunk 服务器并接管 Chunk 服务器的状态信息。
​ GFS 客户端代码以库的模式被链接到客户程序里。客户端代码实现了 GFS 文件系统的 API 接口函数、应用程序与 Master 节点和 Chunk 服务器通信、以及对数据进行读写操作。客户端和 Master 节点的通信只获取元数据,所有的数据操作都是由客户端间接和 Chunk 服务器进行交互的。咱们不提供 POSIX 规范的 API 的性能,因而,GFS API 调用不须要深刻到 Linux vnode 级别。
​ 无论是客户端还是 Chunk 服务器都不须要缓存文件数据。客户端缓存数据简直没有什么用途,因为大部分程序要么以流的形式读取一个微小文件,要么工作集太大根本无法被缓存。无需思考缓存相干的问题也简化了客户端和整个零碎的设计和实现。Chunk 服务器不须要缓存文件数据的起因是,Chunk 以本地文件的形式保留,Linux 操作系统的文件系统缓存会把常常拜访的数据缓存在内存中。

2.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.5 Chunk 尺寸

​ Chunk 的大小是要害的设计参数之一。咱们抉择了 64MB,这个尺寸远远大于个别文件系统的 Block size。
每个 Chunk 的正本都以一般 Linux 文件的模式保留在 Chunk 服务器上,只有在须要的时候才扩充。惰性空间
调配策略防止了因外部碎片造成的空间节约,外部碎片或者是对抉择这么大的 Chunk 尺寸最具争议一点。
​ 抉择较大的 Chunk 尺寸有几个重要的长处。首先,它缩小了客户端和 Master 节点通信的需要,因为只须要一次和 Mater 节点的通信就能够获取 Chunk 的地位信息,之后就能够对同一个 Chunk 进行屡次的读写操作。这种形式对升高咱们的工作负载来说效果显著,因为咱们的应用程序通常是间断读写大文件。即便是小规模的随机读取,采纳较大的 Chunk 尺寸也带来显著的益处,客户端能够轻松的缓存一个数 TB 的工作数据集所有的 Chunk 地位信息。其次,采纳较大的 Chunk 尺寸,客户端可能对一个块进行屡次操作,这样就能够通过与 Chunk 服务器放弃较长时间的 TCP 连贯来缩小网络负载。第三,选用较大的 Chunk 尺寸缩小了 Master 节点须要保留的元数据的数量。这就容许咱们把元数据全副放在内存中,在 2.6.1 节咱们会探讨元数据全副放在内存中带来的额定的益处。
​ 另一方面,即便配合惰性空间调配,采纳较大的 Chunk 尺寸也有其缺点。小文件蕴含较少的 Chunk,甚至只有一个 Chunk。当有许多的客户端对同一个小文件进行屡次的拜访时,存储这些 Chunk 的 Chunk 服务器就会变成热点。在理论利用中,因为咱们的程序通常是间断的读取蕴含多个 Chunk 的大文件,热点还不是次要的问题。
然而,当咱们第一次把 GFS 用于批处理队列零碎的时候,热点的问题还是产生了:一个可执行文件在 GFS 上保留为 single-chunk 文件,之后这个可执行文件在数百台机器上同时启动。寄存这个可执行文件的几个 Chunk 服务器被数百个客户端的并发申请拜访导致系统部分过载。咱们通过应用更大的复制参数来保留可执行文件,以及错开批处理队列零碎程序的启动工夫的办法解决了这个问题。一个可能的长效解决方案是,在这种的状况下,容许客户端从其它客户端读取数据。

2.6 元数据

​ Master 服务器存储 3 种次要类型的元数据,包含:文件和 Chunk 的命名空间、文件和 Chunk 的对应关系、
每个 Chunk 正本的寄存地点。所有的元数据都保留在 Master 服务器的内存中。前两种类型的元数据同时也会以记录变更日志的形式记录在操作系统的系统日志文件中,日志文件存储在本地磁盘上,同时日志会被复制到其它的近程 Master 服务器上。采纳保留变更日志的形式,咱们可能简略牢靠的更新 Master 服务器的状态,并且不必放心 Master 服务器解体导致数据不统一的危险。Master 服务器不会长久保留 Chunk 地位信息。Master 服务器在启动时,或者有新的 Chunk 服务器退出时,向各个 Chunk 服务器轮询它们所存储的 Chunk 的信息。

2.6.1 内存中的数据结构

​ 因为元数据保留在内存中,所以 Master 服务器的操作速度十分快。并且,Master 服务器能够在后盾简略
而高效的周期性扫描本人保留的全副状态信息。这种周期性的状态扫描也用于实现 Chunk 垃圾收集、在 Chunk
服务器生效的时从新复制数据、通过 Chunk 的迁徙实现跨 Chunk 服务器的负载平衡以及磁盘应用情况统计等
性能。4.3 和 4.4 章节将深刻探讨这些行为。
​ 将元数据全副保留在内存中的办法有潜在问题:Chunk 的数量以及整个零碎的承载能力都受限于 Master
服务器所领有的内存大小。然而在理论利用中,这并不是一个重大的问题。Master 服务器只须要不到 64 个字
节的元数据就可能治理一个 64MB 的 Chunk。因为大多数文件都蕴含多个 Chunk,因而绝大多数 Chunk 都是
满的,除了文件的最初一个 Chunk 是局部填充的。同样的,每个文件的在命名空间中的数据大小通常在 64
字节以下,因为保留的文件名是用前缀压缩算法压缩过的。
​ 即使是须要反对更大的文件系统,为 Master 服务器减少额定内存的费用是很少的,而通过减少无限的
费用,咱们就可能把元数据全副保留在内存里,加强了零碎的简洁性、可靠性、高性能和灵活性。

2.6.2 Chunk 地位信息

​ Master 服务器并不保留长久化保留哪个 Chunk 服务器存有指定 Chunk 的正本的信息。Master 服务器只是
在启动的时候轮询 Chunk 服务器以获取这些信息。Master 服务器可能保障它持有的信息始终是最新的,因为
它管制了所有的 Chunk 地位的调配,而且通过周期性的心跳信息监控 Chunk 服务器的状态。
​ 最后设计时,咱们试图把 Chunk 的地位信息长久的保留在 Master 服务器上,然而起初咱们发现在启动的
时候轮询 Chunk 服务器,之后定期轮询更新的形式更简略。这种设计简化了在有 Chunk 服务器退出集群、离
开集群、更名、生效、以及重启的时候,Master 服务器和 Chunk 服务器数据同步的问题。在一个领有数百台
服务器的集群中,这类事件会频繁的产生。
​ 能够从另外一个角度去了解这个设计决策:只有 Chunk 服务器能力最终确定一个 Chunk 是否在它的硬盘
上。咱们从没有思考过在 Master 服务器上保护一个这些信息的全局视图,因为 Chunk 服务器的谬误可能会导
致 Chunk 主动隐没(比方,硬盘损坏了或者无法访问了),亦或者操作人员可能会重命名一个 Chunk 服务器。

2.6.3 操作日志

​ 操作日志蕴含了要害的元数据变更历史记录。这对 GFS 十分重要。这不仅仅是因为操作日志是元数据唯
一的长久化存储记录,它也作为判断同步操作程序的逻辑工夫基线。文件和 Chunk,连同它们的版本 (参考
4.5 节),都由它们创立的逻辑工夫惟一的、永恒的标识。
​ 操作日志十分重要,咱们必须确保日志文件的残缺,确保只有在元数据的变动被长久化后,日志才对客
户端是可见的。否则,即便 Chunk 自身没有呈现任何问题,咱们仍有可能失落整个文件系统,或者失落客户
端最近的操作。所以,咱们会把日志复制到多台近程机器,并且只有把相应的日志记录写入到本地以及近程
机器的硬盘后,才会响应客户端的操作申请。Master 服务器会收集多个日志记录后批量解决,以缩小写入磁
盘和复制对系统整体性能的影响。
​ Master 服务器在劫难复原时,通过重演操作日志把文件系统复原到最近的状态。为了缩短 Master 启动的
工夫,咱们必须使日志足够小。Master 服务器在日志增长到一定量时对系统状态做一次 Checkpoint,将所
有的状态数据写入一个 Checkpoint 文件。在劫难复原的时候,Master 服务器就通过从磁盘上读取这 Checkpoint 文件,以及重演 Checkpoint 之后的无限个日志文件就可能复原零碎。Checkpoint 文件以压缩 B- 树局势的数据结构存储,能够间接映射到内存,在用于命名空间查问时无需额定的解析。这大大提高了复原速度,加强了可用性。
​ 因为创立一个 Checkpoint 文件须要肯定的工夫,所以 Master 服务器的外部状态被组织为一种格局,这种格局要确保在 Checkpoint 过程中不会阻塞正在进行的批改操作。Master 服务器应用独立的线程切换到新的日志文件和创立新的 Checkpoint 文件。新的 Checkpoint 文件包含切换前所有的批改。对于一个蕴含数百万个文件的集群,创立一个 Checkpoint 文件须要 1 分钟左右的工夫。创立实现后,Checkpoint 文件会被写入在本地和近程的硬盘里。
​ Master 服务器复原只须要最新的 Checkpoint 文件和后续的日志文件。旧的 Checkpoint 文件和日志文件可
以被删除,然而为了应答灾难性的故障,咱们通常会多保留一些历史文件。Checkpoint 失败不会对正确性产
生任何影响,因为复原性能的代码能够检测并跳过没有实现的 Checkpoint 文件。

2.7 一致性模型

​ GFS 反对一个宽松的一致性模型,这个模型可能很好的撑持咱们的高度散布的利用,同时还放弃了绝对简略且容易实现的长处。本节咱们探讨 GFS 的一致性的保障机制,以及对应用程序的意义。咱们也着重形容了 GFS 如何治理这些一致性保障机制,然而实现的细节将在本论文的其它局部探讨。

2.7.1 GFS 一致性保障机制

​ 文件命名空间的批改(例如,文件创建)是原子性的。它们仅由 Master 节点的管制:命名空间锁提供了
原子性和正确性(4.1 章)的保障;Master 节点的操作日志定义了这些操作在全局的程序(2.6.3 章)。

数据批改后文件 region 的状态取决于操作的类型、胜利与否、以及是否同步批改。表 1 总结了各种操作
的后果。
如果所有客户端,无论从哪个正本读取,读到的数据都一样,那么咱们认为文件 region 是“统一的”;
如果对文件的数据批改之后,region 是统一的,并且客户端可能看到写入操作全副的内容,那么这个 region
是“已定义的”。
当一个数据批改操作胜利执行,并且没有受到同时执行的其它写入操作的烦扰,那么影响的 region 就是
已定义的(隐含了一致性):所有的客户端都能够看到写入的内容。并行批改操作胜利实现之后,region 处于统一的、未定义的状态:所有的客户端看到同样的数据,然而无奈读到任何一次写入操作写入的数据。通常状况下,文件 region 内蕴含了来自多个批改操作的、混淆的数据片段。失败的批改操作导致一个 region 处于不统一状态(同时也是未定义的):不同的客户在不同的工夫会看到不同的数据。前面咱们将形容利用如何辨别已定义和未定义的 region。应用程序没有必要再去细分未定义 region 的不同类型。

    数据批改操作分为写入或者记录追加两种。写入操作把数据写在应用程序指定的文件偏移地位上。即便

有多个批改操作并行执行时,记录追加操作至多能够把数据原子性的追加到文件中一次,然而偏移地位是由
GFS 抉择的(3.3 章)。GFS 返回给客户端一个偏移量,示意了蕴含了写入记录的、已定义的 region 的终点。
另外,GFS 可能会在文件两头插入填充数据或者重复记录。这些数据占据的文件 region 被认定是不统一的,
这些数据通常比用户数据小的多。通过了一系列的胜利的批改操作之后,GFS 确保被批改的文件 region 是已定义的,并且蕴含最初一次批改操作写入的数据。GFS 通过以下措施确保上述行为:

(a)对 Chunk 的所有正本的批改操作程序统一(3.1 章),

(b)应用 Chunk 的版本号来检测正本是否因为它所在的 Chunk 服务器宕机(4.5 章)而错过了批改操作
而导致其生效。

​ 生效的正本不会再进行任何批改操作,Master 服务器也不再返回这个 Chunk 正本的地位信息给客户端。它们会被垃圾收集零碎尽快回收。因为 Chunk 地位信息会被客户端缓存,所以在信息刷新前,客户端有可能从一个生效的正本读取了数据。在缓存的超时工夫和文件下一次被关上的工夫之间存在一个工夫窗,文件再次被关上后会革除缓存中与该文件无关的所有 Chunk 地位信息。而且,因为咱们的文件大多数都是只进行追加操作的,所以,一个生效的正本通常返回一个提前结束的 Chunk 而不是过期的数据。当一个 Reader 16 从新尝试并联系 Master 服务器时,它就会立即失去最新的 Chunk 地位信息。
​ 即便在批改操作胜利执行很长时间之后,组件的生效也可能损坏或者删除数据。GFS 通过 Master 服务器和所有 Chunk 服务器的定期“握手”来找到生效的 Chunk 服务器,并且应用 Checksum 来校验数据是否损坏(5.2 章)。一旦发现问题,数据要尽快利用无效的正本进行复原(4.3 章)。只有当一个 Chunk 的所有正本在 GFS 检测到谬误并采取应答措施之前全副失落,这个 Chunk 才会不可逆转的失落。在个别状况下 GFS 的反应时间是几分钟。即便在这种状况下,Chunk 也只是不可用了,而不是损坏了:应用程序会收到明确的错误信息而不是损坏的数据。

2.7.2 程序的实现

​ 应用 GFS 的应用程序能够利用一些简略技术实现这个宽松的一致性模型,这些技术也用来实现一些其它的指标性能,包含:尽量采纳追加写入而不是笼罩,Checkpoint,自验证的写入操作,自标识的记录。
​ 在理论利用中,咱们所有的应用程序对文件的写入操作都是尽量采纳数据追加形式,而不是笼罩形式。
一种典型的利用,应用程序从头到尾写入数据,生成了一个文件。写入所有数据之后,应用程序主动将文件改名为一个永恒保留的文件名,或者周期性的作 Checkpoint,记录胜利写入了多少数据。Checkpoint 文件能够蕴含程序级别的校验和。Readers 仅校验并解决上个 Checkpoint 之后产生的文件 region,这些文件 region 的状态肯定是已定义的。这个办法满足了咱们一致性和并发解决的要求。追加写入比随机地位写入更加有效率,对应用程序的失败解决更具备弹性。Checkpoint 能够让 Writer 以渐进的形式从新开始,并且能够避免 Reader 解决曾经被胜利写入,然而从应用程序的角度来看还并未实现的数据。
​ 咱们再来剖析另一种典型的利用。许多应用程序并行的追加数据到同一个文件,比方进行后果的合并或者是一个生产者 - 消费者队列。记录追加形式的“至多一次追加”的个性保障了 Writer 的输入。Readers 应用上面的办法来解决必然性的填充数据和反复内容。Writers 在每条写入的记录中都蕴含了额定的信息,例如 Checksum,用来验证它的有效性。Reader 能够利用 Checksum 辨认和摈弃额定的填充数据和记录片段。如果利用不能容忍偶然的反复内容(比方,如果这些反复数据触发了非幂等操作),能够用记录的惟一标识符来过滤它们,这些惟一标识符通常用于命名程序中解决的实体对象,例如 web 文档。这些记录 I/O 性能都蕴含在咱们的程序共享的库中,并且实用于 Google 外部的其它的文件接口实现。所以,雷同序列的记录,加上一些偶然呈现的反复数据,都被散发到 Reader 了。

3 零碎交互

​ 咱们在设计这个零碎时,一个重要的准则是最小化所有操作和 Master 节点的交互。带着这样的设计理念,咱们当初形容一下客户机、Master 服务器和 Chunk 服务器如何进行交互,以实现数据批改操作、原子的记录追加操作以及快照性能。

3.1 租约(lease)和变更程序

​ 变更是一个会扭转 Chunk 内容或者元数据的操作,比方写入操作或者记录追加操作。变更操作会在 Chunk
的所有正本上执行。咱们应用租约(lease)机制来放弃多个正本间变更程序的一致性。Master 节点为 Chunk 的一个正本建设一个租约,咱们把这个正本叫做主 Chunk。主 Chunk 对 Chunk 的所有更改操作进行序列化。
所有的正本都听从这个序列进行批改操作。因而,批改操作全局的程序首先由 Master 节点抉择的租约的程序
决定,而后由租约中主 Chunk 调配的序列号决定。
​ 设计租约机制的目标是为了最小化 Master 节点的管理负担。租约的初始超时设置为 60 秒。不过,只有
Chunk 被批改了,主 Chunk 就能够申请更长的租期,通常会失去 Master 节点的确认并收到租约缩短的工夫。
这些租约缩短申请和批准的信息通常都是附加在 Master 节点和 Chunk 服务器之间的心跳音讯中来传递。有时
Master 节点会试图提前勾销租约(例如,Master 节点想勾销在一个曾经被改名的文件上的批改操作)。即便
Master 节点和主 Chunk 失去分割,它依然能够平安地在旧的租约到期后和另外一个 Chunk 正本签订新的租约。
在图 2 中,咱们根据步骤编号,展示写入操作的管制流程。

​ 客户机向 Master 节点询问哪一个 Chunk 服务器持有以后的租约,以及其它正本的地位。如果没有一个
Chunk 持有租约,Master 节点就抉择其中一个正本建设一个租约(这个步骤在图上没有显示)。
​ Master 节点将主 Chunk 的标识符以及其它正本(又称为 secondary 正本、二级正本)的地位返回给客户机。客户机缓存这些数据以便后续的操作。只有在主 Chunk 不可用,或者主 Chunk 回复信息表明它已不再持有租约的时候,客户机才须要从新跟 Master 节点分割。
​ 客户机把数据推送到所有的正本上。客户机能够以任意的程序推送数据。Chunk 服务器接管到数据并保留在它的外部 LRU 缓存中,始终到数据被应用或者过期替换进来。因为数据流的网络传输负载十分高,通过拆散数据流和控制流,咱们能够基于网络拓扑状况对数据流进行布局,进步零碎性能,而不必去理睬哪个 Chunk 服务器保留了主 Chunk。3.2 章节会进一步探讨这点。
​ 当所有的正本都确认接管到了数据,客户机发送写申请到主 Chunk 服务器。这个申请标识了早前推送到所有正本的数据。主 Chunk 为接管到的所有操作调配间断的序列号,这些操作可能来自不同的客户机,序列号保障了操作程序执行。它以序列号的程序把操作利用到它本人的本地状态中(alex 注:也就是在本地执行这些操作,这句话按字面翻译有点费解,兴许应该翻译为“它程序执行这些操作,并更新本人的状态”)。主 Chunk 把写申请传递到所有的二级正本。每个二级正本按照主 Chunk 调配的序列号以雷同的程序执行这些操作。
​ 所有的二级正本回复主 Chunk,它们曾经实现了操作。
​ 主 Chunk 服务器 20 回复客户机。任何正本产生的任何谬误都会返回给客户机。在呈现谬误的状况下,写
入操作可能在主 Chunk 和一些二级正本执行胜利。(如果操作在主 Chunk 上失败了,操作就不会被调配序列
号,也不会被传递。)客户端的申请被确认为失败,被批改的 region 处于不统一的状态。咱们的客户机代码通
过反复执行失败的操作来解决这样的谬误。在从头开始反复执行之前,客户机会先从步骤(3)到步骤(7)做几次尝试。
​ 如果应用程序一次写入的数据量很大,或者数据逾越了多个 Chunk,GFS 客户机代码会把它们分成多个写操作。这些操作都遵循后面形容的管制流程,然而可能会被其它客户机上同时进行的操作打断或者笼罩。因而,共享的文件 region 的尾部可能蕴含来自不同客户机的数据片段,尽管如此,因为这些合成后的写入操作在所有的正本上都以雷同的程序执行实现,Chunk 的所有正本都是统一的。这使文件 region 处于 2.7 节形容的统一的、然而未定义的状态。

3.2 数据流

​ 为了进步网络效率,咱们采取了把数据流和控制流离开的措施。在控制流从客户机到主 Chunk、而后再到所有二级正本的同时,数据以管道的形式,程序的沿着一个精心抉择的 Chunk 服务器链推送。咱们的指标是充分利用每台机器的带宽,防止网络瓶颈和高延时的连贯,最小化推送所有数据的延时。
​ 为了充分利用每台机器的带宽,数据沿着一个 Chunk 服务器链程序的推送,而不是以其它拓扑模式扩散推送(例如,树型拓扑构造)。线性推送模式下,每台机器所有的进口带宽都用于以最快的速度传输数据,而不是在多个接受者之间调配带宽。
​ 为了尽可能的避免出现网络瓶颈和高提早的链接(eg,inter-switch 最有可能呈现相似问题),每台机器都尽量的在网络拓扑中抉择一台还没有接管到数据的、离本人最近的机器作为指标推送数据。假如客户机把数据从 Chunk 服务器 S1 推送到 S4。它把数据推送到最近的 Chunk 服务器 S1。S1 把数据推送到 S2,因为 S2 和 S4 中最靠近的机器是 S2。同样的,S2 把数据传递给 S3 和 S4 之间更近的机器,顺次类推推送上来。咱们的网络拓扑非常简单,通过 IP 地址就能够计算出节点的“间隔”。
​ 最初,咱们利用基于 TCP 连贯的、管道式数据推送形式来最小化提早。Chunk 服务器接管到数据后,马上开始向前推送。管道形式的数据推送对咱们帮忙很大,因为咱们采纳全双工的替换网络。接管到数据后立即向前推送不会升高接管的速度。在没有网络拥塞的状况下,传送 B 字节的数据到 R 个正本的现实工夫是 B /T+RL,T 是网络的吞吐量,L 是在两台机器数据传输的提早。通常状况下,咱们的网络连接速度是 100Mbps(T),L 将远小于 1ms。因而,1MB 的数据在现实状况下 80ms 左右就能散发进来。

3.3 原子的记录追加

​ GFS 提供了一种原子的数据追加操作–记录追加。传统形式的写入操作,客户程序会指定数据写入的偏移量。对同一个 region 的并行写入操作不是串行的:region 尾部可能会蕴含多个不同客户机写入的数据片段。应用记录追加,客户机只须要指定要写入的数据。GFS 保障至多有一次原子的写入操作胜利执行(即写入一个程序的 byte 流),写入的数据追加到 GFS 指定的偏移地位上,之后 GFS 返回这个偏移量给客户机。这相似于在 Unix 操作系统编程环境中,对以 O_APPEND 模式关上的文件,多个并发写操作在没有竞态条件时的行为。
​ 记录追加在咱们的散布利用中十分频繁的应用,在这些分布式应用中,通常有很多的客户机并行地对同一个文件追加写入数据。如果咱们采纳传统形式的文件写入操作,客户机须要额定的简单、低廉的同步机制,例如应用一个分布式的锁管理器。在咱们的工作中,这样的文件通常用于多个生产者 / 繁多消费者的队列零碎,或者是合并了来自多个客户机的数据的后果文件。
​ 记录追加是一种批改操作,它也遵循 3.1 节形容的管制流程,除了在主 Chunk 有些额定的管制逻辑。客户机把数据推送给文件最初一个 Chunk 的所有正本,之后发送申请给主 Chunk。主 Chunk 会查看这次记录追加操作是否会使 Chunk 超过最大尺寸(64MB)。如果超过了最大尺寸,主 Chunk 首先将以后 Chunk 填充到最大尺寸,之后告诉所有二级正本做同样的操作,而后回复客户机要求其对下一个 Chunk 从新进行记录追加操作。(记录追加的数据大小严格控制在 Chunk 最大尺寸的 1/4,这样即便在最坏状况下,数据碎片的数量依然在可控的范畴。)通常状况下追加的记录不超过 Chunk 的最大尺寸,主 Chunk 把数据追加到本人的正本内,而后告诉二级正本把数据写在跟主 Chunk 一样的地位上,最初回复客户机操作胜利。
​ 如果记录追加操作在任何一个正本上失败了,客户端就须要从新进行操作。从新进行记录追加的后果是,同一个 Chunk 的不同正本可能蕴含不同的数据–反复蕴含一个记录全副或者局部的数据。GFS 并不保障 Chunk 的所有正本在字节级别是完全一致的。它只保证数据作为一个整体原子的被至多写入一次。这个个性能够通过简略察看推导进去:如果操作胜利执行,数据肯定曾经写入到 Chunk 的所有正本的雷同偏移地位上。这之后,所有的正本至多都到了记录尾部的长度,任何后续的记录都会追加到更大的偏移地址,或者是不同的 Chunk 上,即便其它的 Chunk 正本被 Master 节点选为了主 Chunk。就咱们的一致性保障模型而言,记录追加操作胜利写入数据的 region 是已定义的(因而也是统一的),反之则是不统一的(因而也就是未定义的)。正如咱们在 2.7.2 节探讨的,咱们的程序能够解决不统一的区域。

3.4 快照

​ 快照操作简直能够霎时实现对一个文件或者目录树(“源”)做一个拷贝,并且简直不会对正在进行的其它操作造成任何烦扰。咱们的用户能够应用快照迅速的创立一个微小的数据集的分支拷贝(而且常常是递归的拷贝拷贝),或者是在做实验性的数据操作之前,应用快照操作备份以后状态,这样之后就能够轻松的提交或者回滚到备份时的状态。
​ 就像 AFS(alex 注:AFS,即 Andrew File System,一种分布式文件系统),咱们用规范的 copy-on-write 技术实现快照。当 Master 节点收到一个快照申请,它首先勾销作快照的文件的所有 Chunk 的租约。这个措施保障了后续对这些 Chunk 的写操作都必须与 Master 交互以找到租约持有者。这就给 Master 节点一个率先创立
Chunk 的新拷贝的机会。
​ 租约勾销或者过期之后,Master 节点把这个操作以日志的形式记录到硬盘上。而后,Master 节点通过复制源文件或者目录的元数据的形式,把这条日志记录的变动反映到保留在内存的状态中。新创建的快照文件和源文件指向完全相同的 Chunk 地址。
​ 在快照操作之后,当客户机第一次想写入数据到 Chunk C,它首先会发送一个申请到 Master 节点查问以后的租约持有者。Master 节点留神到 Chunk C 的援用计数超过了 1 22。Master 节点不会马上回复客户机的申请,
而是抉择一个新的 Chunk 句柄 C`。之后,Master 节点要求每个领有 Chunk C 以后正本的 Chunk 服务器创立一
个叫做 C` 的新 Chunk。通过在源 Chunk 所在 Chunk 服务器上创立新的 Chunk,咱们确保数据在本地而不是通
过网络复制(咱们的硬盘比咱们的 100Mb 以太网大概快 3 倍)。从这点来讲,申请的解决形式和任何其它 Chunk 没什么不同:Master 节点确保新 Chunk C` 的一个正本领有租约,之后回复客户机,客户机失去回复后就能够失常的写这个 Chunk,而不用理睬它是从一个已存在的 Chunk 克隆进去的。

4 Master 节点的操作

​ Master 节点执行所有的名称空间操作。此外,它还治理着整个零碎里所有 Chunk 的正本:它决定 Chunk 的存储地位,创立新 Chunk 和它的正本,协调各种各样的系统活动以保障 Chunk 被齐全复制,在所有的 Chunk 服务器之间的进行负载平衡,回收不再应用的存储空间。本节咱们探讨上述的主题。

4.1 名称空间治理和锁

​ Master 节点的很多操作会破费很长的工夫:比方,快照操作必须勾销 Chunk 服务器上快照所波及的所有的 Chunk 的租约。咱们不心愿在这些操作的运行时,延缓了其它的 Master 节点的操作。因而,咱们容许多个
操作同时进行,应用名称空间的 region 上的锁来保障执行的正确程序。
​ 不同于许多传统文件系统,GFS 没有针对每个目录实现可能列出目录下所有文件的数据结构。GFS 也不
反对文件或者目录的链接(即 Unix 术语中的硬链接或者符号链接)。在逻辑上,GFS 的名称空间就是一个全
门路和元数据映射关系的查找表。利用前缀压缩,这个表能够高效的存储在内存中。在存储名称空间的树型
构造上,每个节点(绝对路径的文件名或绝对路径的目录名)都有一个关联的读写锁。
每个 Master 节点的操作在开始之前都要取得一系列的锁。通常状况下,如果一个操作波及 /d1/d2/…
/dn/leaf,那么操作首先要取得目录 /d1,/d1/d2,…,/d1/d2/…/dn 的读锁,以及 /d1/d2/…/dn/leaf 的读写锁。留神,依据操作的不同,leaf 能够是一个文件,也能够是一个目录。
​ 当初,咱们演示一下在 /home/user 被快照到 /save/user 的时候,锁机制如何避免创立文件 /home/user/foo。
​ 快照操作获取 /home 和 /save 的读取锁,以及 /home/user 和 /save/user 的写入锁。文件创建操作取得 /home 和 /home/user 的读取锁,以及 /home/user/foo 的写入锁。这两个操作要程序执行,因为它们试图获取的 /home/user 的锁是互相抵触。文件创建操作不须要获取父目录的写入锁,因为这里没有“目录”,或者相似 inode 等用来禁止批改的数据结构。文件名的读取锁足以避免父目录被删除。
​ 采纳这种锁计划的长处是反对对同一目录的并行操作。比方,能够再同一个目录下同时创立多个文件:
每一个操作都获取一个目录名的上的读取锁和文件名上的写入锁。目录名的读取锁足以的避免目录被删除、
改名以及被快照。文件名的写入锁序列化文件创建操作,确保不会屡次创立同名的文件。
因为名称空间可能有很多节点,读写锁采纳惰性调配策略,在不再应用的时候立即被删除。同样,锁的
获取也要根据一个全局统一的程序来防止死锁:首先按名称空间的档次排序,在同一个档次内按字典程序排
序。

4.2 正本的地位

​ GFS 集群是高度散布的多层布局构造,而不是立体构造。典型的拓扑构造是有数百个 Chunk 服务器装置
在许多机架上。Chunk 服务器被来自同一或者不同机架上的数百个客户机轮流拜访。不同机架上的两台机器
间的通信可能逾越一个或多个网络交换机。另外,机架的出入带宽可能比机架内所有机器加和在一起的带宽
要小。多层散布架构对数据的灵活性、可靠性以及可用性方面提出特有的挑战。
​ Chunk 正本地位抉择的策略服务两大指标:最大化数据可靠性和可用性,最大化网络带宽利用率。为了
实现这两个目标,仅仅是在多台机器上别离存储这些正本是不够的,这只能预防硬盘损坏或者机器生效带来的影响,以及最大化每台机器的网络带宽利用率。咱们必须在多个机架间散布贮存 Chunk 的正本。这保障 Chunk
的一些正本在整个机架被毁坏或掉线(比方,共享资源,如电源或者网络交换机造成的问题)的状况下仍然
存在且放弃可用状态。这还意味着在网络流量方面,尤其是针对 Chunk 的读操作,可能无效利用多个机架的
整合带宽。另一方面,写操作必须和多个机架上的设施进行网络通信,然而这个代价是咱们违心付出的。

4.3 创立,从新复制,从新负载平衡

​ Chunk 的正本有三个用处:Chunk 创立,从新复制和从新负载平衡。
​ 当 Master 节点创立一个 Chunk 时,它会抉择在哪里搁置初始的空的正本。Master 节点会思考几个因素
(1)咱们心愿在低于均匀硬盘使用率的 Chunk 服务器上存储新的正本。这样的做法最终可能均衡 Chunk
服务器之间的硬盘使用率。
(2)咱们心愿限度在每个 Chunk 服务器上“最近”的 Chunk 创立操作的次数。尽管创立操作自身是廉
价的,然而创立操作也意味着随之会有大量的写入数据的操作,因为 Chunk 在 Writer 真正写入数据的时候才
被创立,而在咱们的“追加一次,读取屡次”的工作模式下,Chunk 一旦写入胜利之后就会变为只读的了。
(3)如上所述,咱们心愿把 Chunk 的正本散布在多个机架之间。
当 Chunk 的无效正本数量少于用户指定的复制因数的时候,Master 节点会从新复制它。这可能是由几个
起因引起的:一个 Chunk 服务器不可用了,Chunk 服务器报告它所存储的一个正本损坏了,Chunk 服务器的
一个磁盘因为谬误不可用了,或者 Chunk 正本的复制因数进步了。每个须要被从新复制的 Chunk 都会依据几
个因素进行排序。一个因素是 Chunk 现有正本数量和复制因数相差多少。例如,失落两个正本的 Chunk 比丢
失一个正本的 Chunk 有更高的优先级。另外,咱们优先从新复制沉闷(live)文件的 Chunk 而不是最近刚被
删除的文件的 Chunk(查看 4.4 节)。最初,为了最小化生效的 Chunk 对正在运行的应用程序的影响,咱们提
高会阻塞客户机程序处理流程的 Chunk 的优先级。
​ Master 节点抉择优先级最高的 Chunk,而后命令某个 Chunk 服务器间接从可用的正本”克隆”一个正本
进去。抉择新正本的地位的策略和创立时相似:均衡硬盘使用率、限度同一台 Chunk 服务器上的正在进行的
克隆操作的数量、在机架间散布正本。为了避免克隆产生的网络流量大大超过客户机的流量,Master 节点对
整个集群和每个 Chunk 服务器上的同时进行的克隆操作的数量都进行了限度。另外,Chunk 服务器通过调节
它对源 Chunk 服务器读申请的频率来限度它用于克隆操作的带宽。
最初,Master 服务器周期性地对正本进行从新负载平衡:它查看以后的正本散布状况,而后挪动正本以便更好的利用硬盘空间、更无效的进行负载平衡。而且在这个过程中,Master 服务器逐步的填满一个新的 Chunk 服务器,而不是在短时间内用新的 Chunk 填满它,以至于过载。新正本的存储地位抉择策略和下面探讨的雷同。另外,Master 节点必须抉择哪个正本要被移走。通常状况,Master 节点移走那些残余空间低于平均值的 Chunk 服务器上的正本,从而均衡零碎整体的硬盘使用率。

4.4 垃圾回收

​ GFS 在文件删除后不会立即回收可用的物理空间。GFS 空间回收采纳惰性的策略,只在文件和 Chunk 级
的惯例垃圾收集时进行。咱们发现这个办法使零碎更简略、更牢靠。

4.4.1 机制

​ 当一个文件被应用程序删除时,Master 节点象看待其它批改操作一样,立即把删除操作以日志的形式记
录下来。然而,Master 节点并不马上回收资源,而是把文件名改为一个蕴含删除工夫戳的、暗藏的名字。当
Master 节点对文件系统命名空间做惯例扫描的时候,它会删除所有三天前的暗藏文件(这个工夫距离是能够
设置的)。直到文件被真正删除,它们仍旧能够用新的非凡的名字读取,也能够通过把暗藏文件改名为失常显
示的文件名的形式“反删除”。当暗藏文件被从名称空间中删除,Master 服务器内存中保留的这个文件的相干
元数据才会被删除。这也无效的切断了文件和它蕴含的所有 Chunk 的连贯。
​ 在对 Chunk 名字空间做相似的惯例扫描时,Master 节点找到孤儿 Chunk(不被任何文件蕴含的 Chunk)
并删除它们的元数据。Chunk 服务器在和 Master 节点交互的心跳信息中,报告它领有的 Chunk 子集的信息,
Master 节点回复 Chunk 服务器哪些 Chunk 在 Master 节点保留的元数据中曾经不存在了。Chunk 服务器能够任
意删除这些 Chunk 的正本。

4.4.2 探讨

​ 尽管分布式垃圾回收在编程语言畛域是一个须要简单的计划能力解决的难题,然而在 GFS 零碎中是十分
简略的。咱们能够轻易的失去 Chunk 的所有援用:它们都只存储在 Master 服务器上的文件到块的映射表中。
咱们也能够很轻易的失去所有 Chunk 的正本:它们都以 Linux 文件的模式存储在 Chunk 服务器的指定目录下。
所有 Master 节点不能辨认的正本都是“垃圾”。
​ 垃圾回收在空间回收方面相比间接删除有几个劣势。首先,对于组件生效是常态的大规模分布式系统,
垃圾回收形式简略牢靠。Chunk 可能在某些 Chunk 服务器创立胜利,某些 Chunk 服务器上创立失败,失败的
正本处于无奈被 Master 节点辨认的状态。正本删除音讯可能失落,Master 节点必须从新发送失败的删除音讯,
包含本身的和 Chunk 服务器的 24。垃圾回收提供了统一的、牢靠的革除无用正本的办法。第二,垃圾回收把
存储空间的回收操作合并到 Master 节点规律性的后盾流动中,比方,例行扫描和与 Chunk 服务器握手等。因
此,操作被批量的执行,开销会被扩散。另外,垃圾回收在 Master 节点绝对闲暇的时候实现。这样 Master 节点就能够给那些须要快速反应的客户机申请提供更快捷的响应。第三,延缓存储空间回收为意外的、不可
逆转的删除操作提供了平安保障。
​ 依据咱们的应用教训,提早回收空间的次要问题是,提早回收会妨碍用户调优存储空间的应用,特地是
当存储空间比拟紧缺的时候。当应用程序反复创立和删除临时文件时,开释的存储空间不能马上重用。咱们
通过显式的再次删除一个曾经被删除的文件的形式减速空间回收的速度。咱们容许用户为命名空间的不同部
分设定不同的复制和回收策略。例如,用户能够指定某些目录树上面的文件不做复制,删除的文件被即时的、
不可复原的从文件系统移除。

4.5 过期生效的正本检测

​ 当 Chunk 服务器生效时,Chunk 的正本有可能因错失了一些批改操作而过期生效。Master 节点保留了每
个 Chunk 的版本号,用来辨别以后的正本和过期正本。
​ 无论何时,只有 Master 节点和 Chunk 签订一个新的租约,它就减少 Chunk 的版本号,而后告诉最新的
正本。Master 节点和这些正本都把新的版本号记录在它们长久化存储的状态信息中。这个动作产生在任何客
户机失去告诉以前,因而也是对这个 Chunk 开始写之前。如果某个正本所在的 Chunk 服务器正好处于生效状
态,那么正本的版本号就不会被减少。Master 节点在这个 Chunk 服务器重新启动,并且向 Master 节点报告它
领有的 Chunk 的汇合以及相应的版本号的时候,就会检测出它蕴含过期的 Chunk。如果 Master 节点看到一个
比它记录的版本号更高的版本号,Master 节点会认为它和 Chunk 服务器签订租约的操作失败了,因而会抉择
更高的版本号作为以后的版本号。
​ Master 节点在例行的垃圾回收过程中移除所有的过期生效正本。在此之前,Master 节点在回复客户机的
Chunk 信息申请的时候,简略的认为那些过期的块基本就不存在。另外一重保障措施是,Master 节点在告诉
客户机哪个 Chunk 服务器持有租约、或者批示 Chunk 服务器从哪个 Chunk 服务器进行克隆时,音讯中都附带
了 Chunk 的版本号。客户机或者 Chunk 服务器在执行操作时都会验证版本号以确保总是拜访以后版本的数据。

5 容错和诊断

​ 咱们在设计 GFS 时遇到的最大挑战之一是如何解决频繁产生的组件生效。组件的数量和品质让这些问题
呈现的频率远远超过个别零碎意外产生的频率:咱们不能齐全依赖机器的稳定性,也不能齐全置信硬盘的可
靠性。组件的生效可能造成零碎不可用,更蹩脚的是,还可能产生不残缺的数据。咱们探讨咱们如何面对这
些挑战,以及当组件生效不可避免的产生时,用 GFS 自带工具诊断系统故障。

5.1 高可用性

​ 在 GFS 集群的数百个服务器之中,在任何给定的工夫必定会有些服务器是不可用的。咱们应用两条简略然而无效的策略保障整个零碎的高可用性:疾速复原和复制。

5.1.1 疾速复原

​ 不论 Master 服务器和 Chunk 服务器是如何敞开的,它们都被设计为能够在数秒钟内复原它们的状态并重
新启动。事实上,咱们并不辨别失常敞开和异样敞开;通常,咱们通过间接 kill 掉过程来敞开服务器。客户
机和其它的服务器会感觉到零碎有点平稳 25,正在收回的申请会超时,须要从新连贯到重启后的服务器,而后
重试这个申请。6.6.2 章节记录了实测的启动工夫。

5.1.2 Chunk 复制

​ 正如之前探讨的,每个 Chunk 都被复制到不同机架上的不同的 Chunk 服务器上。用户能够为文件命名空
间的不同局部设定不同的复制级别。缺省是 3。当有 Chunk 服务器离线了,或者通过 Chksum 校验(参考 5.2
节)发现了曾经损坏的数据,Master 节点通过克隆已有的正本保障每个 Chunk 都被残缺复制 26。尽管 Chunk
复制策略对咱们十分无效,然而咱们也在寻找其它模式的跨服务器的冗余解决方案,比方应用奇偶校验、或
者 Erasure codes 27 来解决咱们日益增长的只读存储需要。咱们的零碎次要的工作负载是追加形式的写入和读取
操作,很少有随机的写入操作,因而,咱们认为在咱们这个高度解耦合的零碎架构下实现这些简单的冗余方
案很有挑战性,但并非不可实现。

5.1.3 Master 服务器的复制

​ 为了保障 Master 服务器的可靠性,Master 服务器的状态也要复制。Master 服务器所有的操作日志和
checkpoint 文件都被复制到多台机器上。对 Master 服务器状态的批改操作可能提交胜利的前提是,操作日志
写入到 Master 服务器的备节点和本机的磁盘。简略说来,一个 Master 服务过程负责所有的批改操作,包含后
台的服务,比方垃圾回收等扭转零碎外部状态流动。当它生效的时,简直能够立即重新启动。如果 Master 进
程所在的机器或者磁盘生效了,处于 GFS 零碎内部的监控过程会在其它的存有残缺操作日志的机器上启动一
个新的 Master 过程。客户端应用标准的名字拜访 Master(比方 gfs-test)节点,这个名字相似 DNS 别名,因
此也就能够在 Master 过程转到别的机器上执行时,通过更改别名的理论指向拜访新的 Master 节点。
此外,GFS 中还有些“影子”Master 服务器,这些“影子”服务器在“主”Master 服务器宕机的时候提
供文件系统的只读拜访。它们是影子,而不是镜像,所以它们的数据可能比“主”Master 服务器更新要慢,
通常是不到 1 秒。对于那些不常常扭转的文件、或者那些容许获取的数据有大量过期的应用程序,“影子”Master 服务器可能进步读取的效率。事实上,因为文件内容是从 Chunk 服务器上读取的,因而,应用程序不
会发现过期的文件内容。在这个短暂的工夫窗内,过期的可能是文件的元数据,比方目录的内容或者拜访控
制信息。
​“影子”Master 服务器为了放弃本身状态是最新的,它会读取一份以后正在进行的操作的日志正本,并
且按照和主 Master 服务器完全相同的程序来更改外部的数据结构。和主 Master 服务器一样,“影子”Master
服务器在启动的时候也会从 Chunk 服务器轮询数据(之后定期拉数据),数据中包含了 Chunk 正本的地位信
息;“影子”Master 服务器也会定期和 Chunk 服务器“握手”来确定它们的状态。在主 Master 服务器因创立
和删除正本导致正本地位信息更新时,“影子”Master 服务器才和主 Master 服务器通信来更新本身状态。

5.2 数据完整性

​ 每个 Chunk 服务器都应用 Checksum 来查看保留的数据是否损坏。思考到一个 GFS 集群通常都有好几百
台机器、几千块硬盘,磁盘损坏导致数据在读写过程中损坏或者失落是十分常见的(第 7 节讲了一个起因)。
咱们能够通过别的 Chunk 副原本解决数据损坏问题,然而逾越 Chunk 服务器比拟副原本检查数据是否损坏很
不理论。另外,GFS 容许有歧义的正本存在:GFS 批改操作的语义,特地是新近探讨过的原子纪录追加的操
作,并不保障正本完全相同 (alex 注:正本不是 byte-wise 完全一致的)。因而,每个 Chunk 服务器必须独立维
护 Checksum 来校验本人的正本的完整性。
​ 咱们把每个 Chunk 都分成 64KB 大小的块。每个块都对应一个 32 位的 Checksum。和其它元数据一样,
Checksum 与其它的用户数据是离开的,并且保留在内存和硬盘上,同时也记录操作日志。
​ 对于读操作来说,在把数据返回给客户端或者其它的 Chunk 服务器之前,Chunk 服务器会校验读取操作
波及的范畴内的块的 Checksum。因而 Chunk 服务器不会把谬误数据传递到其它的机器上。如果产生某个块的
Checksum 不正确,Chunk 服务器返回给请求者一个错误信息,并且告诉 Master 服务器这个谬误。作为回应,
请求者该当从其它正本读取数据,Master 服务器也会从其它正本克隆数据进行复原。当一个新的正本就绪后,
Master 服务器告诉正本谬误的 Chunk 服务器删掉谬误的正本。
​ Checksum 对读操作的性能影响很小,能够基于几个起因来剖析一下。因为大部分的读操作都至多要读取
几个块,而咱们只须要读取一小部分额定的相干数据进行校验。GFS 客户端代码通过每次把读取操作都对齐
在 Checksum block 的边界上,进一步缩小了这些额定的读取操作的负面影响。另外,在 Chunk 服务器上,
Checksum 的查找和比拟不须要 I/O 操作,Checksum 的计算能够和 I/O 操作同时进行。
Checksum 的计算针对在 Chunk 尾部的追加写入操作做了高度优化(与之对应的是笼罩现有数据的写入操
作),因为这类操作在咱们的工作中占了很大比例。咱们只增量更新最初一个不残缺的块的 Checksum,并且
用所有的追加来的新 Checksum 块来计算新的 Checksum。即便是最初一个不残缺的 Checksum 块曾经损坏了,而且咱们不可能马上查看进去,因为新的 Checksum 和已有数据不吻合,在下次对这个块进行读取操作的时候,
会查看出数据曾经损坏了。
​ 相比之下,如果写操作笼罩曾经存在的一个范畴内的 Chunk,咱们必须读取和校验被笼罩的第一个和最
后一个块,而后再执行写操作;操作实现之后再从新计算和写入新的 Checksum。如果咱们不校验第一个和最
后一个被写的块,那么新的 Checksum 可能会暗藏没有被笼罩区域内的数据谬误。
在 Chunk 服务器闲暇的时候,它会扫描和校验每个不流动的 Chunk 的内容。这使得咱们可能发现很少被
读取的 Chunk 是否残缺。一旦发现有 Chunk 的数据损坏,Master 能够创立一个新的、正确的正本,而后把损
坏的正本删除掉。这个机制也防止了非流动的、已损坏的 Chunk 坑骗 Master 节点,使 Master 节点认为它们已
经有了足够多的正本了。

5.3 诊断工具

​ 详尽的、深刻细节的诊断日志,在问题隔离、调试、以及性能剖析等方面给咱们带来无法估量的帮忙,
同时也只须要很小的开销。没有日志的帮忙,咱们很难了解短暂的、不反复的机器之间的音讯交互。GFS 的
服务器会产生大量的日志,记录了大量要害的事件(比方,Chunk 服务器启动和敞开)以及所有的 RPC 的请
求和回复。这些诊断日志能够随便删除,对系统的正确运行不造成任何影响。然而,咱们在存储空间容许的
状况下会尽量的保留这些日志。
​ RPC 日志蕴含了网络上产生的所有申请和响应的具体记录,然而不包含读写的文件数据。通过匹配申请
与回应,以及收集不同机器上的 RPC 日志记录,咱们能够重演所有的音讯交互来诊断问题。日志还用来跟踪
负载测试和性能剖析。
​ 日志对性能的影响很小(远小于它带来的益处),因为这些日志的写入形式是程序的、异步的。最近产生
的事件日志保留在内存中,可用于继续一直的在线监控。

6 度量

​ 本节中,咱们将应用一些小规模基准测试来展示 GFS 零碎架构和实现上的一些固有瓶颈,还有些来自
Google 外部应用的实在的 GFS 集群的基准数据。

6.1 小规模基准测试

​ 咱们在一个蕴含 1 台 Master 服务器,2 台 Master 服务器复制节点,16 台 Chunk 服务器和 16 个客户机组
成的 GFS 集群上测量性能。留神,采纳这样的集群配置计划只是为了易于测试。典型的 GFS 集群有数百个
Chunk 服务器和数百个客户机。
​ 所有机器的配置都一样:两个 PIII 1.4GHz 处理器,2GB 内存,两个 80G/5400rpm 的硬盘,以及 100Mbps 全双工以太网连贯到一个 HP2524 交换机。GFS 集群中所有的 19 台服务器都连贯在一个交换机,所有 16 台
客户机连贯到另一个交换机上。两个交换机之间应用 1Gbps 的线路连贯。

6.1.1 读取

​ N 个客户机从 GFS 文件系统同步读取数据。每个客户机从 320GB 的文件汇合中随机读取 4MB region 的
内容。读取操作反复执行 256 次,因而,每个客户机最终都读取 1GB 的数据。所有的 Chunk 服务器加起来总
共只有 32GB 的内存,因而,咱们预期只有最多 10% 的读取申请命中 Linux 的文件系统缓冲。咱们的测试结
果应该和一个在没有文件系统缓存的状况下读取测试的后果靠近。

​ 上边的曲线显示了咱们网络拓扑下的共计实践吞吐量下限。下边的曲线显示了观测到的吞吐量。这个曲
线有着 95% 的可靠性,因为有时候测量会不够准确。
​ 图 3(a)显示了 N 个客户机整体的读取速度以及这个速度的实践极限。当连贯两个交换机的 1Gbps 的链
路饱和时,整体读取速度达到实践的极限值是 125MB/S,或者说每个客户机配置的 100Mbps 网卡达到饱和时,
每个客户机读取速度的实践极限值是 12.5MB/s。实测后果是,当一个客户机读取的时候,读取的速度是 10MB/s,
​ 也就是说达到客户机实践读取速度极限值的 80%。对于 16 个客户机,整体的读取速度达到了 94MB/s,大概
是实践整体读取速度极限值的 75%,也就是说每个客户机的读取速度是 6MB/s。读取效率从 80% 升高到了 75%,
次要的起因是当读取的客户机减少时,多个客户机同时读取一个 Chunk 服务器的几率也减少了,导致整体的
读取效率降落。

6.1.2 写入

​ N 个客户机同时向 N 个不同的文件中写入数据。每个客户机以每次 1MB 的速度间断写入 1GB 的数据。
图 3(b)显示了整体的写入速度和它们实践上的极限值。实践上的极限值是 67MB/s,因为咱们须要把每一
byte 写入到 16 个 Chunk 服务器中的 3 个上,而每个 Chunk 服务器的输出连贯速度是 12.5MB/s。

​ 一个客户机的写入速度是 6.3MB,大略是实践极限值的一半。导致这个后果的次要起因是咱们的网络协
议栈。它与咱们推送数据到 Chunk 服务器时采纳的管道模式不相适应。从一个正本到另一个正本的数据传输
提早升高了整个的写入速度。
​ 16 个客户机整体的写入速度达到了 35MB/s(即每个客户机 2.2MB/s),大概只是实践极限值的一半。和
多个客户机读取的情景很类型,随着客户机数量的减少,多个客户机同时写入同一个 Chunk 服务器的几率也
减少了。而且,16 个客户机并行写入可能引起的抵触比 16 个客户机并行读取要大得多,因为每个写入都会
波及三个不同的正本。
​ 写入的速度比咱们设想的要慢。在理论利用中,这没有成为咱们的次要问题,因为即便在单个客户机上
可能感触到延时,它也不会在有大量客户机的时候对整体的写入带宽造成显著的影响。

6.1.3 记录追加

​ 图 3(c)显示了记录追加操作的性能。N 个客户机同时追加数据到一个文件。记录追加操作的性能受限
于保留文件最初一个 Chunk 的 Chunk 服务器的带宽,而与客户机的数量无关。记录追加的速度由一个客户机
的 6.0MB/s 开始,降落到 16 个客户机的 4.8MB/s 为止,速度的降落次要是因为不同客户端的网络拥塞以及网
络传输速度的不同而导致的。
​ 咱们的程序偏向于同时解决多个这样的文件。换句话说,即 N 个客户机同时追加数据到 M 个共享文件中,
这里 N 和 M 都是数十或者数百以上。所以,在咱们的理论利用中,Chunk 服务器的网络拥塞并没有成为一个
重大问题,如果 Chunk 服务器的某个文件正在写入,客户机会去写另外一个文件。

6.2 理论利用中的集群

​ 咱们当初来认真评估一下 Google 外部正在应用的两个集群,它们具备肯定的代表性。集群 A 通常被上百
个工程师用于钻研和开发。典型的工作是被人工初始化后间断运行数个小时。它通常读取数 MB 到数 TB 的
数据,之后进行转化或者剖析,最初把后果写回到集群中。集群 B 次要用于解决以后的生产数据。集群 B 的
工作继续的工夫更长,在很少人工干预的状况下,继续的生成和解决数 TB 的数据集。在这两个案例中,一
个独自的“工作”都是指运行在多个机器上的多个过程,它们同时读取和写入多个文件。

6.2.1 存储

​ 如上表前五行所形容的,两个集群都由上百台 Chunk 服务器组成,反对数 TB 的硬盘空间;两个集群虽
然都存储了大量的数据,然而还有残余的空间。“已用空间”蕴含了所有的 Chunk 正本。实际上所有的文件都
复制了三份。因而,集群实际上各存储了 18TB 和 52TB 的文件数据。
两个集群存储的文件数量都差不多,然而集群 B 上有大量的死文件。所谓“死文件”是指文件被删除了
或者是被新版本的文件替换了,然而存储空间还没有来得及被回收。因为集群 B 存储的文件较大,因而它的
Chunk 数量也比拟多。

6.2.2 元数据

​ Chunk 服务器总共保留了十几 GB 的元数据,大多数是来自用户数据的、64KB 大小的块的 Checksum。
保留在 Chunk 服务器上其它的元数据是 Chunk 的版本号信息,咱们在 4.5 节形容过。
在 Master 服务器上保留的元数据就小的多了,大概只有数十 MB,或者说均匀每个文件 100 字节的元数
据。这和咱们构想的是一样的,Master 服务器的内存大小在理论利用中并不会成为 GFS 零碎容量的瓶颈。大
少数文件的元数据都是以前缀压缩模式寄存的文件名。Master 服务器上寄存的其它元数据包含了文件的所有
者和权限、文件到 Chunk 的映射关系,以及每一个 Chunk 的以后版本号。此外,针对每一个 Chunk,咱们都
保留了以后的正本地位以及对它的援用计数,这个援用计数用于实现写时拷贝(即 COW,copy-on-write)。
对于每一个独自的服务器,无论是 Chunk 服务器还是 Master 服务器,都只保留了 50MB 到 100MB 的元
数据。因而,复原服务器是十分疾速的:在服务器响应客户申请之前,只须要花几秒钟工夫从磁盘上读取这
些数据就能够了。不过,Master 服务器会继续平稳一段时间–通常是 30 到 60 秒–直到它实现轮询所有的 Chunk 服务器,并获取到所有 Chunk 的地位信息。

6.2.3 读写速率

​ 表三显示了不同时段的读写速率。在测试的时候,这两个集群都运行了一周左右的工夫。(这两个集群最
近都因为降级新版本的 GFS 重新启动过了)。
​ 集群重新启动后,均匀写入速率小于 30MB/s。当咱们提取性能数据的时候,集群 B 正进行大量的写入操
作,写入速度达到了 100MB/s,并且因为每个 Chunk 都有三个正本的起因,网络负载达到了 300MB/s。
读取速率要比写入速率高的多。正如咱们构想的那样,总的工作负载中,读取的比例远远高于写入的比
例。两个集群都进行着沉重的读取操作。特地是,集群 A 在一周工夫内都维持了 580MB/s 的读取速度。集群
A 的网络配置能够反对 750MB/ s 的速度,显然,它无效的利用了资源。集群 B 反对的峰值读取速度是 1300MB/s,
然而它的利用只用到了 380MB/s。

6.2.4 Master 服务器的负载

​ 表 3 的数据显示了发送到 Master 服务器的操作申请大略是每秒钟 200 到 500 个。Master 服务器能够轻松
的应酬这个申请速度,所以 Master 服务器的解决能力不是零碎的瓶颈。
在晚期版本的 GFS 中,Master 服务器偶然会成为瓶颈。它大多数工夫里都在程序扫描某个很大的目录
(蕴含数万个文件)去查找某个特定的文件。因而咱们批改了 Master 服务器的数据结构,通过对名字空间进
行二分查找来提高效率。当初 Master 服务器能够轻松的每秒钟进行数千次文件拜访。如果有需要的话,咱们
能够通过在名称空间数据结构之前设置名称查问缓冲的形式进一步提高速度。

6.2.5 复原工夫

​ 当某个 Chunk 服务器生效了,一些 Chunk 正本的数量可能会低于复制因子指定的数量,咱们必须通过克
隆正本使 Chunk 正本数量达到复制因子指定的数量。复原所有 Chunk 正本所破费的工夫取决于资源的数量。
在咱们的试验中,咱们把集群 B 上的一个 Chunk 服务器 Kill 掉。这个 Chunk 服务器上大概有 15000 个 Chunk,
共计 600GB 的数据。为了减小克隆操作对正在运行的应用程序的影响,以及为 GFS 调度决策提供修改空间,
咱们缺省的把集群中并发克隆操作的数量设置为 91 个(Chunk 服务器的数量的 40%),每个克隆操作最多允
许应用的带宽是 6.25MB/s(50mbps)。所有的 Chunk 在 23.2 分钟内复原了,复制的速度高达 440MB/s。
在另外一个测试中,咱们 Kill 掉了两个 Chunk 服务器,每个 Chunk 服务器大概有 16000 个 Chunk,共
计 660GB 的数据。这两个故障导致了 266 个 Chunk 只有单个正本。这 266 个 Chunk 被 GFS 优先调度进行复
制,在 2 分钟内复原到至多有两个正本;当初集群被带入到另外一个状态,在这个状态下,零碎能够容忍另
外一个 Chunk 服务器生效而不失落数据。

6.3 工作负荷剖析(Workload Breakdown)

​ 本节中,咱们展现了对两个 GFS 集群工作负载状况的详细分析,这两个集群和 6.2 节中的相似,然而不
完全相同。集群 X 用于钻研和开发,集群 Y 用于生产数据处理。

6.3.1 方法论和注意事项

​ 本章节列出的这些后果数据只包含客户机发动的原始申请,因而,这些后果可能反映咱们的应用程序对
GFS 文件系统产生的全副工作负载。它们不蕴含那些为了实现客户端申请而在服务器间交互的申请,也不包
含 GFS 外部的后盾流动相干的申请,比方前向转发的写操作,或者从新负载平衡等操作。
​ 咱们从 GFS 服务器记录的实在的 RPC 申请日志中推导重建出对于 IO 操作的统计信息。例如,GFS 客
户程序可能会把一个读操作分成几个 RPC 申请来进步并行度,咱们能够通过这些 RPC 申请推导出原始的读
操作。因为咱们的拜访模式是高度程式化,所以咱们认为任何不合乎的数据都是误差 28。应用程序如果可能记
录更详尽的日志,就有可能提供更精确的诊断数据;然而为了这个目标去从新编译和重新启动数千个正在运
行的客户机是不事实的,而且从那么多客户机上收集后果也是个沉重的工作。
​ 应该防止从咱们的工作负荷数据中适度的演绎出广泛的论断 29。因为 Google 齐全管制着 GFS 和应用 GFS
的应用程序,所以,应用程序都针对 GFS 做了优化,同时,GFS 也是为了这些应用程序而设计的。这样的相
互作用也可能存在于个别程序和文件系统中,然而在咱们的案例中这样的作用影响可能更显著。

表 4 显示了操作按波及的数据量大小的散布状况。读取操作按操作波及的数据量大小出现了双峰分布。
小的读取操作(小于 64KB)个别是由查找操作的客户端发动的,目标在于从微小的文件中查找小块的数据。
大的读取操作(大于 512KB)个别是从头到尾程序的读取整个文件。

    在集群 Y 上,有相当数量的读操作没有返回任何的数据。在咱们的利用中,尤其是在生产零碎中,常常

应用文件作为生产者 - 消费者队列。生产者并行的向文件中追加数据,同时,消费者从文件的尾部读取数据。
某些状况下,消费者读取的速度超过了生产者写入的速度,这就会导致没有读到任何数据的状况。集群 X 通
罕用于短暂的数据分析工作,而不是长时间运行的分布式应用,因而,集群 X 很少呈现这种状况。

    写操作按数据量大小也同样出现为双峰分布。大的写操作(超过 256KB)通常是因为 Writer 应用了缓存

机制导致的。Writer 缓存较小的数据,通过频繁的 Checkpoint 或者同步操作,或者只是简略的统计小的写入
(小于 64KB)的数据量(alex 注:即会集屡次小的写入操作,当数据量达到一个阈值,一次写入),之后批量
写入。

    再来察看一下记录追加操作。咱们能够看到集群 Y 中大的记录追加操作所占比例比集群 X 多的多,这是

因为集群 Y 用于咱们的生产零碎,针对 GFS 做了更全面的调优。

表 5 显示了按操作波及的数据量的大小统计进去的总数据传输量。在所有的操作中,大的操作(超过
256KB)占据了次要的传输量。小的读取(小于 64KB)尽管传输的数据量比拟少,然而在读取的数据量中仍
占了相当的比例,这是因为在文件中随机 Seek 的工作负荷而导致的。

6.3.3 记录追加 vs. 写操作

​ 记录追加操作在咱们的生产零碎中大量应用。对于集群 X,记录追加操作和一般写操作的比例依照字节
比是 108:1,依照操作次数比是 8:1。对于作为咱们的生产零碎的集群 Y 来说,这两个比例别离是 3.7:1 和 2.5:1。
更进一步,这一组数据阐明在咱们的两个集群上,记录追加操作所占比例都要比写操作要大。对于集群 X,
在整个测量过程中,记录追加操作所占比率都比拟低,因而后果会受到一两个应用某些特定大小的 buffer 的
应用程序的影响。
​ 如同咱们所预期的,咱们的数据批改操作次要是记录追加操作而不是笼罩形式的写操作。咱们测量了第
一个正本的数据笼罩写的状况。这近似于一个客户机成心笼罩刚刚写入的数据,而不是减少新的数据。对于
集群 X,笼罩写操作在写操作所占据字节上的比例小于 0.0001%,在所占据操作数量上的比例小于 0.0003%。
对于集群 Y,这两个比率都是 0.05%。尽管这只是某一片断的状况,然而依然高于咱们的预期。这是因为这
些笼罩写的操作,大部分是因为客户端在产生谬误或者超时当前重试的状况。这在实质上应该不算作工作负
荷的一部分,而是重试机制产生的后果。

6.3.4 Master 的工作负荷

表 6 显示了 Master 服务器上的申请按类型辨别的明细表。大部分的申请都是读取操作查问 Chunk 地位信
息(FindLocation)、以及批改操作查问 lease 持有者的信息(FindLease-Locker)。

    集群 X 和 Y 在删除申请的数量上有着显著的不同,因为集群 Y 存储了生产数据,个别会从新生成数据

以及用新版本的数据替换旧有的数据。数量上的差别也被暗藏在了 Open 申请中,因为旧版本的文件可能在以
从新写入的模式关上时,隐式的被删除了(相似 UNIX 的 open 函数中的“w”模式)。

    FindMatchingFiles 是一个模式匹配申请,反对“ls”以及其它相似的文件系统操作。不同于 Master 服务

器的其它申请,它可能会检索 namespace 的大部分内容,因而是十分低廉的操作。集群 Y 的这类申请要多一
些,因为自动化数据处理的工作过程须要查看文件系统的各个局部,以便从全局上理解应用程序的状态。与
之不同的是,集群 X 的应用程序更加偏向于由独自的用户管制,通常事后晓得本人所须要应用的全副文件的
名称。

7 教训

在建造和部署 GFS 的过程中,咱们经验了各种各样的问题,有些是操作上的,有些是技术上的。

    起初,GFS 被构想为咱们的生产零碎的后端文件系统。随着时间推移,在 GFS 的应用中逐渐的减少了对

钻研和开发工作的反对。咱们开始减少一些小的性能,比方权限和配额,到了当初,GFS 曾经初步反对了这
些性能。尽管咱们生产零碎是严格受控的,然而用户层却不总是这样的。须要更多的基础架构来避免用户间
的互相烦扰。

    咱们最大的问题是磁盘以及和 Linux 相干的问题。很多磁盘都宣称它们反对某个范畴内的 Linux IDE 硬盘

驱动程序,然而理论利用中反映进去的状况却不是这样,它们只反对最新的驱动。因为协定版本很靠近,所以

大部分磁盘都能够用,然而偶然也会有因为协定不匹配,导致驱动和内核对于驱动器的状态判断失误。这会导致数据因为内核中的问题意外的被毁坏了。这个问题促使咱们应用 Checksum 来校验数据,同时咱们也批改内核来解决这些因为协定不匹配带来的问题。
较早的时候,咱们在应用 Linux 2.2 内核时遇到了些问题,次要是 fsync()的效率问题。它的效率与文件的大小而不是文件批改局部的大小无关。这在咱们的操作日志文件过大时给出了难题,尤其是在咱们尚未实现 Checkpoint 的时候。咱们费了很大的力量用同步写来解决这个问题,然而最初还是移植到了 Linux2.4 内核上。

    另一个和 Linux 相干的问题是单个读写锁的问题,也就是说,在某一个地址空间的任意一个线程都必须在从磁盘 page in(读锁)的时候先 hold 住,或者在 mmap()调用(写锁)的时候改写地址空间。咱们发现即便咱们的零碎负载很轻的状况下也会有偶然的超时,咱们破费了很多的精力去查找资源的瓶颈或者硬件的问题。最初咱们终于发现这个单个锁在磁盘线程替换以前映射的数据到磁盘的时候,锁住了以后的网络线程,阻止它把新数据映射到内存。因为咱们的性能次要受限于网络接口,而不是内存 copy 的带宽,因而,咱们用 pread()代替 mmap(),用了一个额定的 copy 动作来解决这个问题。只管偶然还是有其它的问题,Linux 的凋谢源代码还是使咱们可能疾速探索和了解零碎的行为。在适当的

时候,咱们会改良内核并且和公开源码组织共享这些改变。

8 相干工作

​ 和其它的大型分布式文件系统,比方 AFS[5]相似,GFS 提供了一个与地位无关的名字空间,这使得数据
能够为了负载平衡或者劫难冗余等目标在不同地位通明的迁徙。不同于 AFS 的是,GFS 把文件散布存储到不
同的服务器上,这种形式更相似 Xfs[1]和 Swift[3],这是为了进步整体性能以及劫难冗余的能力。因为磁盘相对来说比拟便宜,并且复制的形式比 RAID[9]办法简略的多,GFS 目前只应用复制的形式来进行冗余,因而要比 xFS 或者 Swift 占用更多的裸存储空间 (alex 注:Raw storage,裸盘的空间)。
​ 与 AFS、xFS、Frangipani[12] 以及 Intermezzo[6]等文件系统不同的是,GFS 并没有在文件系统层面提供
任何 Cache 机制。咱们次要的工作在单个应用程序执行的时候简直不会反复读取数据,因为它们的工作形式
要么是流式的读取一个大型的数据集,要么是在大型的数据集中随机 Seek 到某个地位,之后每次读取大量的
数据。
​ 某些分布式文件系统,比方 Frangipani、xFS、Minnesota’s GFS[11]、GPFS[10],去掉了核心服务器,只
依赖于分布式算法来保障一致性和可管理性。咱们抉择了核心服务器的办法,目标是为了简化设计,减少可
靠性,可能灵便扩大。特地值得一提的是,因为处于核心地位的 Master 服务器保留有简直所有的 Chunk 相干
信息,并且管制着 Chunk 的所有变更,因而,它极大地简化了本来非常复杂的 Chunk 调配和复制策略的实现
办法。咱们通过缩小 Master 服务器保留的状态信息的数量,以及将 Master 服务器的状态复制到其它节点来保证系统的劫难冗余能力。扩大能力和高可用性(对于读取)目前是通过咱们的影子 Master 服务器机制来保障
的。对 Master 服务器状态更改是通过预写日志的形式实现长久化。为此,咱们能够调整为应用相似 Harp[7]
中的 primary-copy 计划,从而提供比咱们当初的计划更严格的一致性保障。
​ 咱们解决了一个难题,这个难题相似 Lustre[8]在如何在有大量客户端时保障系统整体性能遇到的问题。
不过,咱们通过只关注咱们的应用程序的需要,而不是提供一个兼容 POSIX 的文件系统,从而达到了简化问
题的目标。此外,GFS 设计预期是应用大量的不牢靠节点组建集群,因而,劫难冗余计划是咱们设计的外围。
GFS 很相似 NASD 架构 [4]。NASD 架构是基于网络磁盘的,而 GFS 应用的是一般计算机作为 Chunk 服
务器,就像 NASD 原形中计划一样。所不同的是,咱们的 Chunk 服务器采纳惰性调配固定大小的 Chunk 的方
式,而不是调配变长的对象存储空间。此外,GFS 实现了诸如从新负载平衡、复制、复原机制等等在生产环
境中须要的个性。
​ 不同于与 Minnesota’s GFS 和 NASD,咱们并不扭转存储设备的 Model 30。咱们只关注用一般的设施来解
决非常复杂的分布式系统日常的数据处理。
​ 咱们通过原子的记录追加操作实现了生产者 - 消费者队列,这个问题相似 River[2]中的分布式队列。River
应用的是跨主机的、基于内存的分布式队列,为了实现这个队列,必须认真管制数据流;而 GFS 采纳能够被
生产者并发追加记录的长久化的文件的形式实现。River 模式反对 m- 到 -n 的分布式队列,然而短少由长久化
存储提供的容错机制,GFS 只反对 m- 到 -1 的队列。多个消费者能够同时读取一个文件,然而它们输出流的区
间必须是对齐的。

9 结束语

​ Google 文件系统展现了一个应用一般硬件反对大规模数据处理的零碎的特质。尽管一些设计要点都是针
对咱们的非凡的须要定制的,然而还是有很多个性实用于相似规模的和老本的数据处理工作。
首先,咱们依据咱们以后的和可预期的未来的利用规模和技术环境来评估传统的文件系统的个性。咱们
的评估后果将咱们疏导到一个应用齐全不同于传统的设计思路上。依据咱们的设计思路,咱们认为组件生效
是常态而不是异样,针对采纳追加形式(有可能是并发追加)写入、而后再读取(通常序列化读取)的大文
件进行优化,以及扩大规范文件系统接口、放松接口限度来改良整个零碎。
​ 咱们零碎通过继续监控,复制要害数据,疾速和主动复原提供劫难冗余。Chunk 复制使得咱们能够对
Chunk 服务器的生效进行容错。高频率的组件生效要求零碎具备在线修复机制,可能周期性的、通明的修复
损坏的数据,也可能第一工夫从新建设失落的正本。此外,咱们应用 Checksum 在磁盘或者 IDE 子系统级别
检测数据损坏,在这样磁盘数量惊人的大零碎中,损坏率是相当高的。咱们的设计保障了在有大量的并发读写操作时可能提供很高的共计吞吐量。咱们通过拆散控制流和数据流来实现这个指标,控制流在 Master 服务器解决,而数据流在 Chunk 服务器和客户端解决。当个别的操作波及到 Master 服务器时,因为 GFS 抉择的 Chunk 尺寸较大(alex 注:从而减小了元数据的大小),以及通过 ChunkLease 将管制权限移交给主正本,这些措施将 Master 服务器的累赘降到最低。这使得一个简略、核心的 Master 不会成为成为瓶颈。咱们置信咱们对网络协议栈的优化能够晋升以后对于每客户端的写入吞吐量限度。GFS 胜利的实现了咱们对存储的需要,在 Google 外部,无论是作为钻研和开发的存储平台,还是作为生产零碎的数据处理平台,都失去了宽泛的利用。它是咱们继续翻新和解决整个 WEB 范畴内的难题的一个重要工具。

更多 Flink,Kafka,Spark 等相干技术博文,科技资讯,欢送关注实时流式计算 公众号后盾回复“电子书”下载 300 页 Flink 实战电子书

退出移动版