GFS论文学习笔记

枯木逢春不在茂
年少且惜镜边人

写在前面

夜来无事,看看论文吧

正文开始

设计思路

  1. 首先,组件失效被认为是常态事件,而不是意外事件
  2. 其次,以通常的标准衡量,我们的文件非常巨大
  3. 第三,绝大部分文件的修改是采用在文件尾部追加数据,而不是覆盖原有数据的方式
  4. 第四,应用程序和文件系统 API 的协同设计提高了整个系统的灵活性

设计预期

  • 系统的工作负载主要由两种读操作组成:大规模的流式读取和小规模的随机读取
    在这里插入图片描述

单一的 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 节点未来可能会发生的几次通讯。

Chunk尺寸大小

选择较大的 Chunk 尺寸有几个重要的优点。

首先,它减少了客户端和 Master 节点通讯的需求,因为只需要一次和 Mater 节点的通信就可以获取 Chunk 的位置信息,之后就可以对同一个 Chunk 进行多次的读写操作。这种方式对降低我们的工作负载来说效果显著,因为我们的应用程序通常是连续读写大文件。即使是小规模的随机读取,采用较大的 Chunk 尺寸也带来明显的好处,客户端可以轻松的缓存一个数 TB 的工作数据集所有的 Chunk 位置信息。

其次,采用较大的 Chunk 尺寸,客户端能够对一个块进行多次操作,这样就可以
通过与 Chunk 服务器保持较长时间的 TCP 连接来减少网络负载。

第三,选用较大的 Chunk 尺寸减少了 Master节点需要保存的元数据的数量。这就允许我们把元数据全部放在内存中。

另一方面,即使配合惰性空间分配,采用较大的 Chunk 尺寸也有其缺

由于 Chunk 位置信息会被客户端缓存,所以在信息刷新前,客户端有可能从一个失效的副本读取了数据。在缓存的超时时间和文件下一次被打开的时间之间存在一个时间窗,文件再次被打开后会清除缓存中与该文件有关的所有 Chunk 位置信息。而且,由于我们的文件大多数都是只进行追加操作的,所以,一个失效的副本通常返回一个提前结束的 Chunk 而不是过期的数据。当一个 Reader16重新尝试并联络 Master 服务器时,它就会立刻得到最新的 Chunk 位置信息。

快照

就像 AFS(alex 注:AFS,即 Andrew File System,一种分布式文件系统),我们用标准的 copy-on-write技术实现快照。当 Master 节点收到一个快照请求,它首先取消作快照的文件的所有 Chunk 的租约。这个措施保证了后续对这些 Chunk 的写操作都必须与 Master 交互以找到租约持有者。这就给 Master 节点一个率先创建Chunk 的新拷贝的机会。
租约取消或者过期之后,Master 节点把这个操作以日志的方式记录到硬盘上。然后,Master 节点通过复制源文件或者目录的元数据的方式,把这条日志记录的变化反映到保存在内存的状态中。新创建的快照文件和源文件指向完全相同的 Chunk 地址。

Master节点的操作

Master 节点执行所有的名称空间操作。此外,它还管理着整个系统里所有 Chunk 的副本:它决定 Chunk的存储位置,创建新 Chunk 和它的副本,协调各种各样的系统活动以保证 Chunk 被完全复制,在所有的 Chunk服务器之间的进行负载均衡,回收不再使用的存储空间

4.1 名称空间管理和锁

每个 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 等用来禁止修改的数据结构。文件名的读取锁足以防止父目录被删除。

创建,重新复制,重新负载均衡

(1)我们希望在低于平均硬盘使用率的 Chunk 服务器上存储新的副本。这样的做法最终能够平衡 Chunk
服务器之间的硬盘使用率。
(2)我们希望限制在每个 Chunk 服务器上“最近”的 Chunk 创建操作的次数。虽然创建操作本身是廉价的,但是创建操作也意味着随之会有大量的写入数据的操作,因为 Chunk 在 Writer 真正写入数据的时候才被创建,而在我们的“追加一次,读取多次”的工作模式下,Chunk 一旦写入成功之后就会变为只读的了。
(3)如上所述,我们希望把 Chunk 的副本分布在多个机架之间。

Master 节点选择优先级最高的 Chunk,然后命令某个 Chunk 服务器直接从可用的副本”克隆”一个副本出来。选择新副本的位置的策略和创建时类似:平衡硬盘使用率、限制同一台 Chunk 服务器上的正在进行的克隆操作的数量、在机架间分布副本。

垃圾回收

GFS 在文件删除后不会立刻回收可用的物理空间。GFS 空间回收采用惰性的策略,只在文件和 Chunk 级的常规垃圾收集时进行。我们发现这个方法使系统更简单、更可靠。

机制

当一个文件被应用程序删除时,Master 节点象对待其它修改操作一样,立刻把删除操作以日志的方式记录下来。但是,Master 节点并不马上回收资源,而是把文件名改为一个包含删除时间戳的、隐藏的名字。当Master 节点对文件系统命名空间做常规扫描的时候,它会删除所有三天前的隐藏文件(这个时间间隔是可以设置的)。直到文件被真正删除,它们仍旧可以用新的特殊的名字读取,也可以通过把隐藏文件改名为正常显示的文件名的方式“反删除”。当隐藏文件被从名称空间中删除,Master 服务器内存中保存的这个文件的相关元数据才会被删除。这也有效的切断了文件和它包含的所有 Chunk 的连接
在对 Chunk 名字空间做类似的常规扫描时,Master 节点找到孤儿 Chunk(不被任何文件包含的 Chunk)并删除它们的元数据。Chunk 服务器在和 Master 节点交互的心跳信息中,报告它拥有的 Chunk 子集的信息,Master 节点回复 Chunk 服务器哪些 Chunk 在 Master 节点保存的元数据中已经不存在了。Chunk 服务器可以任意删除这些 Chunk 的副本。

讨论

相比于直接删除-垃圾回收的优势

  1. 对于组件失效是常态的大规模分布式系统,垃圾回收方式简单可靠。Chunk 可能在某些 Chunk 服务器创建成功,某些 Chunk 服务器上创建失败,失败的
    副本处于无法被 Master 节点识别的状态。副本删除消息可能丢失,Master 节点必须重新发送失败的删除消息,包括自身的和 Chunk 服务器的24。垃圾回收提供了一致的、可靠的清除无用副本的方法

2.,垃圾回收把存储空间的回收操作合并到 Master 节点规律性的后台活动中,比如,例行扫描和与 Chunk 服务器握手等。因此,操作被批量的执行,开销会被分散。而且该操作在Master节点相对空闲的时候完成。这样Master节点就可以给那些需要快速反应的客户机请求提供更快捷的响应。

3.延缓存储空间回收为意外的、不可逆转的删除操作提供了安全保障。

过期失效的副本检测

当 Chunk 服务器失效时,Chunk 的副本有可能因错失了一些修改操作而过期失效。Master 节点保存了每个 Chunk 的版本号,用来区分当前的副本和过期副本。

无论何时,只要 Master 节点和 Chunk 签订一个新的租约,它就增加 Chunk 的版本号,然后通知最新的副本。Master 节点和这些副本都把新的版本号记录在它们持久化存储的状态信息中。这个动作发生在任何客户机得到通知以前,因此也是对这个 Chunk 开始写之前。如果某个副本所在的 Chunk 服务器正好处于失效状态,那么副本的版本号就不会被增加。Master 节点在这个 Chunk 服务器重新启动,并且向 Master 节点报告它拥有的 Chunk 的集合以及相应的版本号的时候,就会检测出它包含过期的 Chunk。如果 Master 节点看到一个比它记录的版本号更高的版本号,Master 节点会认为它和 Chunk 服务器签订租约的操作失败了,因此会选择更高的版本号作为当前的版本号。

一重保障措施是,Master 节点在通知客户机哪个 Chunk 服务器持有租约、或者指示 Chunk 服务器从哪个 Chunk 服务器进行克隆时,消息中都附带了 Chunk 的版本号

容错和诊断

GFS的高可用性

两个策略:

  1. 快速恢复
  2. 复制

快速恢复

不管 Master 服务器和 Chunk 服务器是如何关闭的,它们都被设计为可以在数秒钟内恢复它们的状态并重新启动。事实上,我们并不区分正常关闭和异常关闭;通常,我们通过直接 kill 掉进程来关闭服务器。客户机和其它的服务器会感觉到系统有点颠簸,正在发出的请求会超时,需要重新连接到重启后的服务器,然后重试这个请求

chunk复制

正如之前讨论的,每个 Chunk 都被复制到不同机架上的不同的 Chunk 服务器上。用户可以为文件命名空间的不同部分设定不同的复制级别。缺省是 3。当有 Chunk 服务器离线了,或者通过 Chksum 校验(参考 5.2节)发现了已经损坏的数据,Master 节点通过克隆已有的副本保证每个 Chunk 都被完整复制

Master服务器的复制

为了保证 Master 服务器的可靠性,Master 服务器的状态也要复制。Master 服务器所有的操作日志和checkpoint 文件都被复制到多台机器上。

简单说来,一个 Master 服务进程负责所有的修改操作,包括后台的服务,比如垃圾回收等改变系统内部状态活动。当它失效的时,几乎可以立刻重新启动。如果 Master 进程所在的机器或者磁盘失效了,处于 GFS 系统外部的监控进程会在其它的存有完整操作日志的机器上启动一个新的 Master 进程。客户端使用规范的名字访问 Master(比如 gfs-test)节点,这个名字类似 DNS 别名,因此也就可以在 Master 进程转到别的机器上执行时,通过更改别名的实际指向访问新的 Master 节点。

集群中还存在“影子”master,这些“影子”服务器在“主”Master 服务器宕机的时候提供文件系统的只读访问。它们是影子,而不是镜像,所以它们的数据可能比“主”Master 服务器更新要慢,通常是不到 1 秒。对于那些不经常改变的文件、或者那些允许获取的数据有少量过期的应用程序,“影子”Master 服务器能够提高读取的效率。事实上,因为文件内容是从 Chunk 服务器上读取的,因此,应用程序不会发现过期的文件内容。在这个短暂的时间窗内,过期的可能是文件的元数据,比如目录的内容或者访问控制信息。

“影子”Master 服务器为了保持自身状态是最新的,它会读取一份当前正在进行的操作的日志副本,并且依照和主 Master 服务器完全相同的顺序来更改内部的数据结构。和主 Master 服务器一样,“影子”Master服务器在启动的时候也会从 Chunk 服务器轮询数据(之后定期拉数据),数据中包括了 Chunk 副本的位置信息;“影子”Master 服务器也会定期和 Chunk 服务器“握手”来确定它们的状态。在主 Master 服务器因创建和删除副本导致副本位置信息更新时,“影子”Master 服务器才和主 Master 服务器通信来更新自身状态。

数据完整性

每个 Chunk 服务器都使用 Checksum 来检查保存的数据是否损坏。考虑到一个 GFS 集群通常都有好几百台机器、几千块硬盘,磁盘损坏导致数据在读写过程中损坏或者丢失是非常常见的(第 7 节讲了一个原因)。我们可以通过别的 Chunk 副本来解决数据损坏问题,但是跨越 Chunk 服务器比较副本来检查数据是否损坏很不实际。另外,GFS 允许有歧义的副本存在:GFS 修改操作的语义,特别是早先讨论过的原子纪录追加的操作,并不保证副本完全相同(alex 注:副本不是 byte-wise 完全一致的)。因此,每个 Chunk 服务器必须独立维
护 Checksum 来校验自己的副本的完整性

对于读操作来说,在把数据返回给客户端或者其它的 Chunk 服务器之前,Chunk 服务器会校验读取操作涉及的范围内的块的 Checksum。因此 Chunk 服务器不会把错误数据传递到其它的机器上。如果发生某个块的Checksum 不正确,Chunk 服务器返回给请求者一个错误信息,并且通知 Master 服务器这个错误。作为回应,请求者应当从其它副本读取数据,Master 服务器也会从其它副本克隆数据进行恢复。当一个新的副本就绪后,Master 服务器通知副本错误的 Chunk 服务器删掉错误的副本。

Checksum 对读操作的性能影响很小,可以基于几个原因来分析一下。因为大部分的读操作都至少要读取几个块,而我们只需要读取一小部分额外的相关数据进行校验。GFS 客户端代码通过每次把读取操作都对齐在 Checksum block 的边界上,进一步减少了这些额外的读取操作的负面影响。另外,在 Chunk 服务器上,Checksum 的查找和比较都不需要 I/O 操作,Checksum 的计算可以和 I/O 操作同时进行。

诊断工具

详尽的、深入细节的诊断日志,在问题隔离、调试、以及性能分析等方面给我们带来无法估量的帮助,同时也只需要很小的开销。没有日志的帮助,我们很难理解短暂的、不重复的机器之间的消息交互。GFS 的服务器会产生大量的日志,记录了大量关键的事件(比如,Chunk 服务器启动和关闭)以及所有的 RPC 的请求和回复。这些诊断日志可以随意删除,对系统的正确运行不造成任何影响。然而,我们在存储空间允许的情况下会尽量的保存这些日志。

RPC 日志包含了网络上发生的所有请求和响应的详细记录,但是不包括读写的文件数据。通过匹配请求与回应,以及收集不同机器上的 RPC 日志记录,我们可以重演所有的消息交互来诊断问题。日志还用来跟踪负载测试和性能分析。日志对性能的影响很小(远小于它带来的好处),因为这些日志的写入方式是顺序的、异步的。最近发生的事件日志保存在内存中,可用于持续不断的在线监控。

度量

我们将使用一些小规模基准测试来展现 GFS 系统架构和实现上的一些固有瓶颈

小规模基准测试

我们在一个包含 1 台 Master 服务器,2 台 Master 服务器复制节点,16 台 Chunk 服务器和 16 个客户机组成的 GFS 集群上测量性能。注意,采用这样的集群配置方案只是为了易于测试。典型的 GFS 集群有数百个Chunk 服务器和数百个客户机。

读取

在这里插入图片描述

元数据(实际应用中的集群A-B)

Chunk 服务器总共保存了十几 GB 的元数据,大多数是来自用户数据的、64KB 大小的块的 Checksum。保存在 Chunk 服务器上其它的元数据是 Chunk 的版本号信息。
在 Master 服务器上保存的元数据就小的多了,大约只有数十 MB,或者说平均每个文件 100 字节的元数据。这和我们设想的是一样的,Master 服务器的内存大小在实际应用中并不会成为 GFS 系统容量的瓶颈。大多数文件的元数据都是以前缀压缩模式存放的文件名。Master 服务器上存放的其它元数据包括了文件的所有者和权限、文件到 Chunk 的映射关系,以及每一个 Chunk 的当前版本号。此外,针对每一个 Chunk,我们都保存了当前的副本位置以及对它的引用计数,这个引用计数用于实现写时拷贝(即 COW,copy-on-write)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值