Google文件系统(二)

262 阅读9分钟

译自The Google File System

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

2.4 单一Master节点

单一Master节点大大简化了设计,可以通过全局信息精确定位数据块的位置并进行复制决策。另外,我们必须减少对Master节点的读写,避免Master节点成为系统的瓶颈。客户端不通过Master节点读写文件数据,而是向Master节点询问其应该联系的数据块服务器。客户端将这些元数据信息缓存一段时间,后续的操作则直接与数据块服务器交互。

图1为一次简单的读取流程。首先,客户端根据固定数据块的大小把文件名和程序指定的字节转换成文件的数据块索引;然后把文件名和数据库索引发送给Master节点。

图1 GFS架构

Master节点将相应的数据块标识和副本的位置信息发还给客户端。客户端以文件名和数据块索引为key来缓存这些信 息。之后客户端将请求发送给最近的副本。请求信息包括数据块标识和字节大小范围。 如果缓存的元数据信息没有过期或文件没有被重新打开,则对该数据块进行后续读取操作时,客户端不需要再与Master节点通讯。实际上,客户端一般会在一次请求中查询多个数据块信息,Master节点的回应也可能包含与被请求数据块相邻的数据块的信息。在实际应用中,这部分额外信息能够减少客户端和Master节点的通讯次数。

2.5 数据块大小

数据块大小是一项设计重点。我们选择了64MB,远大于一般文件系统的数据块大小。每个数据块副本都以普通Linux文件的形式保存在数据块服务器上,需要时可以扩大。惰性空间分配策略避免了内部碎片造成的空间浪费。

数据块较大有以下几项优点。首先,减少了客户端和Master节点的通讯需求,因为对同一个数据块的读写只需要与Master节点通信一次便能获得数据块的位置信息,从而显著降低工作负载。即使是小规模的随机读取,较大的数据块也带能让客户端轻松缓存数TB的工作数据集上所有数据块的位置信息。其次,支持客户端对一个块进行多次操作,通过与数据块服务器保持较长时间的TCP连接减少网络负载。第三,减少了 Master 节点需要保存的元数据量。这样就可以把所有元数据放在内存中。

另一方面,即使配合惰性空间分配,采用较大的 Chunk也有其缺陷。小文件的数据块数量较少,有时只有一个数据块。多个客户端访问同一个小文件时,存储数据块的服务器便会变成热点。在实际应用中,由于我们的程序通常是连续读取包含多个数据块的大文件,因此热点还不是主要问题。

但把GFS用于批处理队列系统时,热点问题还是出现了:一个可执行文件在GFS上保存为单数据块文件,随后该文件在数百台机器上同时启动。存放该可执行文件的数据块服务器被数百个客户端同时访问,导致系统局部过载。为了解决这个问题,我们使用更大的复制参数来保存可执行文件,并错开批处理队列系统程序的启动时间。长效解决方案是允许客户端从其它客户端读取数据。

2.6 元数据

Master服务器主要存储三种类型的元数据,包括文件和数据块的命名空间、文件和数据块的对应关系以及每个数据块副本的存储位置。所有的元数据都保存在Master服务器的内存中。前两种类型的元数据同时也会以记录变更日志的方式持久化Master本地磁盘上,同时也会被复制到远程机器上。

通过保存变更日志,能够简单可靠地更新Master服务器的状态,且不用担心Master服务器崩溃会导致数据不一致。Master服务器不会持久保存数据块的位置信息。启动时或新的数据块服务器加入时,Master服务器向各个数据块服务器轮询其所存储的数据块的信息。

2.6.1 内存中的数据结构

由于元数据存储在内存中,因此Master操作速度很快。此外,Master服务器可以在后台简单高效地周期性扫描其保存的全部状态信息。这种周期性的状态扫描也用于数据块的垃圾收集、数据块服务器失效时的数据重新复制、通过数据块的迁移实现跨数据块服务器的负载均衡以及磁盘使用状况统计等功能。

但把元数据全部保存在内存中也存在问题:数据块的数量以及整个系统的承载能力都受限于Master服务器的内存大小。但实际应用中,这个问题并不严重,因为对于一个64MB的数据块,其元数据的大小不到64个字节。由于大多数文件包含多个数据块,因此除了最后一个数据块以外,绝大多数数据块都是满的。同样,每个文件的命名空间数据通常也不到64字节,因为保存的文件名是用前缀压缩算法压缩过的。

如果需要支持更大的文件系统,可以扩大Master服务器内存,以较低的成本把元数据全部保存在内存里,改善了系统的简洁性、可靠性、高性能和灵活性。

2.6.2 数据块位置信息

Master服务器并不会持久化保存数据块服务器存储指定数据块副本的记录,只是在启动的时候轮询服务器,从而获取这些信息。Master服务器管理着所有数据块位置的分配,且通过周期性的心跳信息监控数据块服务器的状态,因而能够获得最新信息。

最初,我们计划把数据块的位置信息持久保存在Master服务器上,后来发现在启动的时候轮询数据块服务器并定期轮询更新更简单。这种设计简化了数据块服务器加入集群、离开集群、更名、失效以及重启时,Master服务器和数据块服务器数据同步的问题。 在由数百台服务器构成的集群中,这类情况会频繁出现。

从另一个角度来说,只有数据块服务器才能最终确定一个数据块是否在其硬盘上。我们没有考虑在Master服务器上维护这些信息的全局视图,因为数据块服务器的错误(如硬盘损坏或无法访问)可能会导致数据块自动消失,操作人员也可能重命名数据块服务器。

2.6.3 操作日志

操作日志包含了关键元数据的变更历史记录,对GFS非常重要。因为操作日志不仅是元数据唯一的持久化存储记录,也是判断同步操作顺序的逻辑时间基线。文件数据块及其版本都由其创建的逻辑时间来唯一永久标识。

操作日志非常重要,我们必须妥善保存日志文件,确保元数据的变更持久化后,这些变更才能对客户端可见。否则,即使数据块本身没有出现任何问题,仍有可能丢失整个文件系统或丢失客户端最近的操作。所以,我们会把日志复制到多台远程机器上,把相应的日志记录写入到本地及远程机器的硬盘后,才会响应客户端的操作请求。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文件。

参考资料

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