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


  • 客户端将数据推送到所有的副本 。一个客户端能够以任意顺序进行推送 。每个块服务器将数据保存在内部的 LRU 缓存中,直到数据被使用或者过期被替换掉 。
    通过对数据流和控制流的解耦,不管哪个块服务器为 Primary,我们都能够通过基于网络拓扑来调度数据流,以此提高性能 。3.2节将进一步讨论 。
  • 一旦所有的副本都确认接收到了数据,客户端将向 Primary 发送一个写请求 。这个请求确定了之前的数据被推送到了所有副本 。Primary 为接收到的所有修改操作分配连续的序列号,这些操作可能来自多个客户端,序列号提供了严格的序列化,应用按序列号顺序执行修改操作,进而改变自己的状态 。
    前面只是推送了数据到块服务器的缓存中,此时才正式请求执行写入
  • Primary 将写请求发送到所有的 Secondary 副本上 。每个 Secondary 副本按照 Primary 分配的相同的序列号顺序执行这些修改操作 。
  • Secondary 副本回复 Primary,表示它们已经完成了所有的操作 。
  • Primary 回复客户端 。任意副本上的任意错误都将报告给客户端 。在一些错误情况下,可能部分写操作已经在 Primary 和一些 Secondary 副本上执行成功 。(如果失败发生在 Primary,它将不会分片一个序列号,并且不会被传递 。)
    此时客户端的请求将被视为已经失败,而那些被修改的区域停留在不一致的状态上 。我们的客户端代码通过重试失败的修改操作来处理这种错误 。在从头开始重复执行之前,它将在第3步到第7步上做几次重做的尝试 。
  • 如果一个应用的写操作数据很大或者跨越了块边界,GFS 客户端会将这个操作分割成几个写操作 。这些操作都遵循上面描述的控制流,但是可能会被其它客户端上的请求打断或覆盖 。因此,一块共享的文件区域可能最终包含不同客户端的数据碎片 。尽管如此,一个快服务器内的所有的副本的对应文件区域都是完全相同的,因为这些独立的写操作在所有副本上一定都按着相同的顺序成功执行 。如 2.7 节所提到的那样,这使文件区域处于一个一致但未定义的状态 。
    3.2 数据流为了有效的利用网络,我们将数据流和控制流分开 。控制流从客户端到 Primary 上,再到所有的Secondary 上,而数据则以管道形式、线性的沿一个精心设计的块服务器链进行推送 。我们的目标是最大限度的使用每台服务器的网络带宽,避免网络瓶颈和高延迟,最小化推送所有数据的时间延迟 。
    为了有效利用每台机器的网络带宽,数据被线性的沿一个块服务器组成的链进行推送,而不是按着其它拓扑进行分发(如,树) 。因此每台机器的出口带宽都用于以最快的速度专注地传输数据,而不是分配给多个接收者 。
    为了尽可能的避免网络瓶颈和高延迟链路,每台机器只将数据推送给网络拓扑中最近的没有接收到数据的机器 。假设客户端将数据推送给块服务器 S1 到 S4 。它将数据发送给最近的块服务器,我们称之为 S1,S1 将数据推送给 S2 到 S4 中最近的块服务器,我们称之为 S2,类似的,S2 将数据推送到 S3 或 S4 中距离 S2 较近的块服务器等等 。我们的网络拓扑足够简单,可以通过IP地址来精确的估计距离 。
    最后,我们通过在 TCP 连接上使用管道传输数据来最小化时间延迟 。一旦一个块服务器接收到数据,则马上开始进行数据推送 。管道对我们的帮助很大,因为我们采用了全双工的交换网络 。立刻推送数据不会降低数据的接收速率 。在没有网络拥塞的情况下,将 B 个字节传输到 R 个副本的理想时间消耗为 B/T+RL,这里 T 是网络的吞吐量,L 是两台机器间的传输延迟 。我们的网络链路通常为100Mbps(T),并且 L 远小于1ms,因此,在理想情况下,1MB 的数据能够在 80ms 内分发完成 。

    经验总结扩展阅读