Google文件系统(三)

译自The Google File System

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

2.7 一致性模型

GFS支持弱一致性模型。这种模型能够很好地支撑高度分布式应用,同时实现相对简单容易。本节讨论GFS的一致性保障机制及其对应用程序的意义。

2.7.1 GFS一致性保障机制

文件命名空间的修改(如文件创建)是原子性的,仅由Master节点控制:命名空间锁保证了原子性和正确性;Master节点的操作日志定义了操作的全局顺序。

数据修改后,文件区域的状态取决于操作的类型、成功与否、以及是否存在同步修改。 表1列出了各种操作的结果。如果所有客户端无论从各个副本读取的数据都是一样的,则视其文件区域为一致。如果修改文件数据后,文件区域是一致的,且客户端能够看到全部写入操作的内容,则该区域为“已定义”区域。如果一个数据修改操作成功执行且没有受到同时执行的其它写入操作的干扰,则影响的区域就是已定义区域(隐含了一致性):所有的客户端都可以看到写入的内容。并行修改操作成功完成之后,区域处于未定义的一致状态:所有的客户端可以看到同样的数据,但无法读取任何一次写入操作写入的数据。通常情况下,文件区域内包含了来自多个修改操作的数据片段。修改操作失败会导致区域处于不一致状态(同时也是未定义状态):不同的客户在不同的时间会看到不同的数据。后文将介绍应用如何区分已定义区域和未定义区域。应用程序不需要进一步细分未定义区域的类型。

数据修改操作分为写入和追加两种。写入操作把数据写在应用程序指定的文件位置上。即便存在多个并行修改操作,记录追加操作可以至少把数据原子性地追加到文件中一次,但是追加位置取决于GFS。GFS给客户端返回一个位置信息,标记了包含写入记录的已定义区域的起点。另外,GFS可能会在文件中间插入填充数据或者重复记录。一般认为,这些数据占据的文件区域是不一致的,且这类数据通常比用户数据小很多。

完成一系列成功修改操作之后,GFS确保被修改的文件区域是已定义的,且包含最后一次修改操作写入的数据。GFS 通过以下措施确保上述行为:(a)按照同样的顺序对数据块的所有副本进行修改操作,(b)通过数据块版本号检测副本是否因其所在的数据块服务器宕机错过了修改操作,最终导致其失效。失效的副本不会再进行任何修改操作,Master服务器也不再将该数据块副本的位置信息返回给客户端。这些副本一经发现,便会被垃圾收集系统回收。

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

即使在修改操作成功执行很长时间之后,组件的失效也可能损坏或删除数据。GFS通过Master服务器和所有数据块服务器的定期通信定位失效的数据块服务器,并使用校验和来校验数据是否损坏。一旦发现问题,要尽快利用有效副本恢复数据。如果在GFS检测到并采取措施之前(一般只需要几分钟),数据块的所有副本已经全部丢失,该数据块便完全无法恢复了。不过在这种情况下,数据块也只是不可用了,而不是损坏了:应用程序会收到明确的错误信息而非损坏的数据。

2.7.2 应用程序的实现

结合一些简单的技术,GFS应用程序的弱一致性模型还能实现其它功能,包括:尽量采用追加写入而不是覆盖,Checkpoint,自验证写入,自标识记录。

在实际应用中,我们所有的应用程序都尽量采用追加而非覆盖的方式对文件进行写入操作。通常情况下,应用程序从头到尾写入数据,生成了一个文件。写入所有数据之后,应用程序自动将文件改名为永久保存的文件名;或者周期性地进行Checkpoint,记录成功写入的数据数量。Checkpoint文件可能包含程序级别的校验和。读取程序仅校验并处理上个Checkpoint之后产生的文件区域,这些文件区域为已定义状态。这个方法满足了我们除一致性和并发处理之外的需求。追加写入比随机写入效率更高,且能够更快地从应用程序失效中恢复。Checkpoint能够让写入程序不断重新开始,并且可以防止读取程序处理已经被成功写入但从应用程序的角度来看尚未写入完成的数据。

另外一种典型的应用场景是多个应用程序同时向同一个文件追加数据进行结果合并或以生产者-消费者队列的形式进行数据追加。记录追加方式中,“至少一次追加”的特性保证了写入程序的输出。读取程序通过下面的方式处理偶然填充和重复内容。写入程序的每条记录都包含了额外信息,例如用于验证有效性的验证和。读取程序可以利用验证和识别并抛弃额外的填充数据和记录片段。如果应用不能容忍偶然的重复内容(如重复数据触发了非幂等操作),可以用记录的唯一标识符进行过滤。唯一标识符通常用于命名程序处理的实体对象,如web文档。这些记录I/O功能都在程序共享代码库中,并且适用于Google内部其它文件接口的实现。这样,相同记录序列和偶然出现的重复数据都被分发到读取程序了。

3 系统交互

设计系统时,我们尽量减少所有操作与Master节点的交互。因此,本节主要介绍客户端、Master服务器以及数据块服务器如何通过交互实现数据修改、原子性记录追加操作和快照功能的。

3.1 租约与修改操作的顺序

修改操作会改变数据块的内容或元数据,包括写入操作或记录追加操作等。修改操作会在数据块的所有副本上执行。我们通过租约(lease)机制保证多个副本间修改操作顺序的一致性。Master节点为数据块的一个副本建立一份租约,我们称该数据块为主数据块。主数据块对数据块的所有修改操作进行排序。所有副本均遵循这一顺序进行修改操作。因此,修改操作的全局顺序首先由Master节点选择的租约的顺序决定,然后由租约中主数据块分配的序列号决定。

设计租约机制的目的是为了尽量减少Master节点的管理负担。租约的初始时效为60秒。不过,只要数据块被修改了,主数据块就可以申请延长租期。申请通常会得到Master节点的确认并收到延长时间。租约延长请求和批信息通常都是附加在Master节点与数据库服务器之间的心跳消息中。有时Master节点会试图提前取消租约(例如,Master节点想撤销对一个已被改名文件的修改操作)。即使与主数据块失去联系,Master节点仍然可以安全地在原有租约到期后与另外一个数据块副本签订新的租约。

图2为写入操作的控制流程。

  • 客户机向Master节点询问持有当前租约的数据块服务器以及其它副本的位置。如果尚不存在租约,则Master节点会选择其中一个副本建立租约。
  • Master节点将主数据块的标识符以及其它副本的位置信息返回给客户机。户机缓存这些数据以便后续的操作。只有在主数据块不可用或主数据块回复信息告知已不再持有租约时,客户机才需要与Master节点重新联系。
  • 客户机可以按照任意顺序把数据推送到所有副本上。数据块服务器接收到数据并保存在其内部LRU缓存中,直到数据被使用或过期。由于数据流的网络传输负载非常高,通过分离数据流和控制流,可以基于网络拓扑情况对数据流进行规划,提高系统性能,不需要关注主数据块保存在哪个数据块服务器上。
  • 所有副本都确认收到数据后,客户机会向主数据块服务器发送写入请求。请求标识了此前推送到所有副本的数据。主数据块为接收到的所有操作分配连续的序列号,这些操作可能来自不同的客户机,序列号保证操作会按顺序执行,并将操作应用到本地状态。 主数据块将写入请求传递到所有二级副本。每个二级副本依照主数据块分配的序列号执行操作。
  • 二级副本完成操作后便会回复主数据块。
  • 主数据块服务器回复客户机。任何副本产生的任何错误都会返回给客户机。出现错误时,写入操作有可能在主数据块和部分二级副本上执行成功。(如果操作在主数据块上失败了,操作就不会被分配序列号,也不会被传递。)客户端的请求被确认为失败后,被修改的区域便会处于不一致状态。客户机代码会重复执行失败的操作。重复执行操作前,客户机会先尝试重复步骤(3)到步骤(7)。

如果应用程序一次写入的数据量很大或数据跨越了多个数据块,GFS客户机代码会把数据分成多个写入操作。这些操作都遵循前述控制流程,但可能会被其他客户机上同时进行的操作打断或覆盖。

因此,共享文件区域的尾部可能包含来自不同客户机的数据片段,但由于这些分解后的写入操作在所有副本上都按照相同的顺序执行完成,因此数据块的所有副本都是一致的。这使文件区域处于一致但未定义的状态。

参考资料

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

官方网站

开源地址

UAVStack已在Github上开放源码,并提供了安装部署、架构说明和用户指南等双语文档,欢迎访问-给星-拉取~~~

扫一扫下方二维码,关注一个不会让你失望的公众号

猜你喜欢

转载自juejin.im/post/5d22a99cf265da1bd3057c72