GFS:为大规模分布式应用程序设计的可扩展的分布式文件系统
1.引言
2.设计概述
-
2.1假设
- 系统由众多廉价的设备组成,他们会经常发生故障,所以系统应该有持续自我检测,故障检测,容错,以及从设备故障中恢复的能力
- 系统存储一定数量的大文件,我们期望有数十上百TB大小的文件,且系统需要对这些文件进行高效的管理
- 系统的负载主要来源于两种读操作:大规模的流式读取与小规模的随机读取,前者通常读取数百KB或者1MB以上的字节,来自同一客户端的读操作可能会连续读文件的某个区域,小规模的随机读取则是读文件的任意偏移量开始的数KB,对于性能敏感的应用程序会批量的随机读取排序后处理,这样可以读连续的文件而不是来回遍历文件
- 系统的负载同样还来源对文件的大规模追加写入,文件一旦被写入就几乎不再会发生修改,系统同样支持小规模的随机写入,但并不需要高效执行
- 数百个客户端并发向一个文件中追加数据的操作是有可能的,所以最小化原子性需要的同步开销是很重要的
- 持续的高吞吐比低延迟更加重要,我们大多数应用程序更注重处理数据,而不是对某个操作有严格的时间限制
-
2.2接口
- 提供常见的文件接口:create,delete, open, close, write, read,同时还支持快照与record append,即前面所提到的并发写入文件
-
2.3架构
- 一个GFS文件系统由一个master与多个chunkserver组成,有诸多客户端进行访问
- 文件被分为若干个大小相同的chunk,每个chunk被一个全局唯一的64位的chunk handle标记,chunk handle在chunk被创建时由master分配。chunkserver将chunk作为linux文件存储到本地磁盘中,通过chunk handle和byte range来确定需要被读写的chunk和chunk中的数据,为保证可靠性,每个chunk通常会在其他chunkserver中存有副本,通常为存储三份副本
- master维护所有的元数据:文件命名空间,文件到chunk的映射,chunk的位置信息,操作日志等
- 被链接到应用程序中的GFS client的代码实现了文件系统的API并代表应用程序与master和chunkserver通信,进行元数据的交互时,与master通信,而除了元数据之外的数据,都是直接在client和chunkserver中进行,避免master成为性能瓶颈
- 无论client还是chunkserver都不需要缓存文件数据。在client中,因为大部分应用程序需要流式地处理大文件或者数据集过大以至于无法缓存。不使用缓存就消除了缓存一致性问题,简化了client和整个系统,client需要缓存的仅有元数据,chunk作为文件存储在chunkserver的磁盘中,经常访问的chunk文件也会被linux内存放入缓存,因此也不需要额外缓存数据
-
2.4单master设计
- 简化了设计,注意最小化master在读写中的参与,避免其成为性能瓶颈
-
2.5chunk块大小
- 64MB
- 缺点:容易产生内部碎片(可使用lazy space allocation缓解)
- 优点
- 应用程序经常连续的读写大文件,减少了client与master交互的次数,对于小规模的随机读取的情况,client也可以轻松地缓存一个数TB的数据集所有的chunk位置信息
- chunk块足够大,client更有可能在这个chunk上执行更多的操作,使client与chunkserver保持更长时间的TCP连接来减少网络的开销
- 减少了master中保存的元数据的大小
-
2.6元数据
- 2.6.1基于内存的优劣
- 所有的元数据都放在master内存中的优点
- 元数据存储在内存中,可以使得master能快速对其进行操作,使master周期性的扫描整个状态变得简单,周期性的扫描可以实现chunkserver故障时的副本重做,chunkserver间因为负载均衡与磁盘空间平衡下进行chunk迁移
- 潜在的问题
- chunk的数量以及系统的容量受到master内存大小的限制
- 所有的元数据都放在master内存中的优点
- 2.6.2chunk的位置
- master并不会持久化的保存chunk的位置信息,而是在chunkserver启动时以及周期性的检测中更新chunk的位置信息,这样的处理消除了当chunkserver加入或离开集群,更改名称,故障或重启时,对master本地的chunk信息与chunkserver同步的问题
- 2.6.3操作日志
- 操作日志,用来持久化file namespace 和 file name -> chunk 的映射
- 用于在master 宕机后进行恢复
- 确定并发操作的执行顺序
- 所有的修改操作都必须先由操作日志记录后才可以写入master内存数据结构后暴露给client,否则宕机恢复时client与master的信息可能不一致
- master通过replay操作日志的方式来恢复文件系统的状态,操作日志要尽可能的小以减少replay的时间,当日志文件超过一定大小时,使用check point(持久化的保存当前的内存数据结构与需要的状态xinxi),master就可以从磁盘加载最后一个检查点并重放该检查点后的日志来恢复状态,检查点的结构为一个B树
- 一个拥有数百万文件的文件系统创建一个检查点需要一分钟的时间,为了防止阻碍新来的变更的执行,会另外开一个线程独立进行,创建完成后写入本地与远程主机,恢复时便只需要最后一个完整的检查点与后续的日志信息了
- 操作日志,用来持久化file namespace 和 file name -> chunk 的映射
- 2.7一致性模型
- 2.6.1基于内存的优劣
3.系统交互
- 3.1 Leases and Mutation Order(租约与变更顺序)
- 3.2 Data Flow (数据流)
- 为了高效地利用网络,对数据流与控制流进行了解耦。在控制流从client向primary再向所有secondary推送的同时,数据流沿着一条精心挑选的chunkserver链以流水线的方式线性推送。我们的目标是充分利用每台机器的网络带宽,避免网络瓶颈和高延迟的链路,并最小化推送完所有数据的时延
- 每台机器会将数据传递给在网络拓扑中最近的的且还没有收到数据的机器
- 通过流水线的方式通过TCP连接传输数据,当chunkserver收到一部分数据时,它会立刻开始将数据传递给其他chunkserver,以最小化时延,理论上将B个字节传输给R个副本所需的时间为B/T+RL,其中T是网络的吞吐量,L是两台机器间的传输时延
- 3.3 Atomic Record Appends(原子性record append)
- 3.4 Snapshot(快照)