The Google File System 翻译和理解( 八 )


3.3 原子性的记录追加GFS 提供了一种原子性的追加操作称为记录追加:

  • 在传统的写操作中,客户端指定数据写入的位置在文件中的偏移量,这样对同一个文件区域的并行写操作不能进行序列化:该区域最终可能包含来自多个客户端的数据片段 。
  • 然而,在一个记录追加操作中,客户端只需要指定数据,GFS 将数据至少一次原子性地追加到文件(如,一个连续的字节序列)的 GFS 选定的一个偏移位置,并将这个偏移位置返回给客户端 。这与在没有竞争的情况下,Uinx 下多个并发写操作向一个使用 O_APPEND 选项打开的文件中写数据相似 。
记录追加操作在我们的分布式应用中使用频繁,许多运行在不同机器上的客户端并行的向同一文件上追加数据 。如果使用传统的写操作进行并发写,客户端将需要额外复杂的、昂贵的同步机制,比如,通一个分布式锁的管理器 。在我们的工作中,这样的文件通常用于多个生产者/一个消费者队列,或者合并来自许多不同客户端的数据结果 。
记录追加操作是修改操作中的一种,遵循 3.1 中介绍的控制流程,只在 Primary 上有一些额外的逻辑 。客户端把数据推送到文件最后一个块的所有的副本上,然后将向 Primary 发送它的请求 。Primary 会检查这次追加操作是否使块的大小超过了最大尺寸(64MB) 。
  • 如果超过,它将把这个块填充满,通知所有的 Secondary 副本进行相同的操作,并回复客户端表明这个操作将在下一个块上重新执行 。(记录追加操作的数据大小严格控制在最大尺寸的 1/4 以内,以确保最坏情况下碎片的数量在一个可接受范围 。)
  • 通常情况下,如果记录不超过最大尺寸,Primary 将数据追加到它的副本上,然后通知Secondary 把数据写到与 Primary 相同的位置上,最后回复客户端操作成功 。
如果在任意一个副本上的记录追加失败,客户端将重试这个操作 。因此,在同一个块的副本上可能包含不同的数据,包括同一个记录的全部或部分的重复数据 。GFS 不保证写入的数据在字节上完全相同,它只保证作为一个原子单元至少被写入一次 。这个特性能够通过简单的观察得到:如果操作执行成功,数据肯定被写入到了某些块副本的相同位置 。此外,在这之后,所有副本至少都达到了记录尾部的长度 。因此,即使一个不同的副本成为了 Primary,以后的任何记录也都将被放置在更大的偏移位置或者是一个不同的块上 。在我们的一致性保障方面,记录追加操作成功的写入数据的区域是被定义的(因此是一致的),反之,介于中间状态的区域是不一致的(因此是未定义的) 。我们的应用使用在 2.7.2 讨论的方法处理这种不一致的区域 。
3.4 快照快照操作几乎瞬间为一个文件或一个目录树(源)创建一个拷贝,并且不会对正在进行的其它操作造成任何影响 。我们的用户使用它为一个巨大的数据集创建一个拷贝分支(而且经常递归的对拷贝进行拷贝),或者是在尝试变化之前对当前的状态创建检查点,之后可以轻松的进行提交或回滚 。
像 AFS 一样,我们使用标准的写时拷贝(Copy-On-Write)技术来实现快照 。当 Master 接收到一个快照请求时,它先取消快照相关的文件块的所有租约 。这确保了任何后面对这些块的写操作将需要与 Master 进行交互,以获取租约的持有者,这将为 Master 提供一个为块创建一个新拷贝的机会 。
写时拷贝:在被修改时才真正执行拷贝
在租约被取消或者过期后,Master 将这些操作记录到磁盘,然后以复制源文件或目录树元数据的方式来在内存上执行这些日志记录 。新创建的快照文件与源文件指向相同的块 。

经验总结扩展阅读