作者:Sanjay Ghemawat
          Howard Gobioff
          Shun-Tak Leung
翻译:tinyfool

3.1 租约和变更顺序

变更就是一个会改变块内容或者元数据的操作,例如写入或者记录追加。每个变更执行在块的所有副本上。我们使用租约来保持多个副本间变更顺序的一致性。主服务器为其中一个副本签署一个块租约,我们把这个副本叫做主块。主块选择对块所有操作的一系列顺序。进行操作的时候所有的副本遵从这个顺序。这样全局的操作顺序首先由主服务器选择的租约生成顺序决定,然后由租约中主块分配的序列号决定。

租约机制的设计是为了最小化主服务器的管理负载。租约的初始超时是60秒。然而一旦块被修改过,主块可以请求更长的租期,通常可以通过主服务器的确认收到额外的时间。这些额外时间的请求和批准都通过服务器和块服务器之间的心跳信息来传递。有时候,主服务器会在租约到期前取消它(例如,当服务器想取消施加在一个已经被改名的文件上的操作。)。即使主服务器和主块失去联系,它仍旧可以安全地在老租约到期后产生一个加诸于其他的副本的租约。

在图2中,我们将用如下这些数字步骤,展现写入操作的控制流程。

写的控制和数据流程

图2:写的控制和数据流程

  1. 客户机向主服务器询问哪一个块服务器保存了当前的租约,以及其他副本的位置。如果没有一个块服务器有租约,主服务器就选择一个副本给它一个租约(没有被显示出来)。
  2. 主服务器回复主块的标识符以及其他副本的位置。客户机为了后续的操作缓存这个数据。只有主块不可用,或者主块回复说它已经不在拥有租约的时候,客户机才需要重新跟主服务器联络。
  3. 客户机把数据推送到所有的副本上。客户机可以用任意的顺序推送。每个块服务器会把这些数据保存在它的内部LRU缓冲内,直到数据被使用或者过期。通过把数据流和控制流分离,我们可以基于网络负载状况对昂贵的数据流进行规划,以提高性能,而不用去管哪个块服务器是主块。3.2章节会更详细地讨论这点。
  4. 所有的副本都被确认已经得到数据后,客户机发送写请求到主块。这个请求标识了早前推送到所有副本的数据。主块为收到的所有操作分配连续的序列号,这些可能来自不同的客户机。它依照序列号的顺序把这些操作应用到它自己的本地状态中。
  5. 主块把写请求传递到所有的二级副本。每个二级副本依照主块分配的序列号的顺序应用这些操作。
  6. 所有二级副本回复主块说明他们已经完成操作。
  7. 主块回复客户机。任何副本产生的错误都会报告给客户机。错误的情况下,主块和一些二级副本可能成功的写入了数据。(如果主块写入失败,操作就不会被分配序列号,也不会被传递。)客户端请求被确认为失败,已经修改的区域保持不一致的状态。我们的客户机代码通过重复失败的操作来处理这样的错误。在完全从头开始写入之前,可能会先从步骤3到步骤7进行几次尝试。

如果应用程序的写入量很大或者包含多个块,GFS客户机代码会把他们分成多个写操作。他们都遵循前面描述的控制流程,但是他们可能会被来自其他客户机的同步操作插入或者覆盖。所以,共享的文件范围的尾部可能包含来自不同客户机的片段,虽然这些副本是一致的,因为这些分别的操作在所有的副本都按照相同的顺序成功完成了。这使文件范围处于2.7章描述过的一致但是未定义的状态。


<< 3. 系统交互 | 3.2 数据流 >>