5.2 数据完整性
每一个chunkserver都是用checksum来检查保存数据的完整性。通常一个GFS集群都有好几百台机器以及几千块硬盘,磁盘损坏是很经常的事情,在数据的读写中经常出现数据损坏(7节讲了一种原因)。我们可以通过别的chunk副本来解决这个问题,但是如果跨越chunkserver比较这个chunk的内容来决定是否损坏就很不实际。进一步说,允许不同副本的存在;在GFS更改操作的语义上,特别是早先讨论过的原子纪录增加的情况下,并不保证byte级别的副本相同。因此,每一个chunkserver上必须独立的效验自己的副本的完整性,并且自己管理checksum。
我们把一个chunk分成64k的块。每一个都有相对应的32位的checksum。就像其他的元数据一样,checksum是在内存中保存的,并且通过分别记录用户数据来持久化保存。
对于读操作来说,在给客户端或者chunkserver读者返回数据之前,chunkserver效验要被读取的数据所在块的checksum。因此chunkserver不会把错误带给其他设备。如果一个块的checksum不正确,chunkserver会给请求者一个错误,并且告知master这个错误。收到这个应答之后,请求者应当从其他副本读取这个数据,master也会安排从其他副本来做克隆。当一个新的副本就绪后,master会指挥刚才报错的chunkserver删掉它刚才错误的副本。
checksum对于读取性能来说,在几方面有点影响。因为大部分的读取操作都分布在好几个block上,我们只需要额外的多读取一小部分相关数据进行checksum检查。GFS客户端代码通过每次把读取操作都对齐在block边界上,来进一步减少了这些额外的读取。此外,在chunkserver上的chunksum的查找和比较不需要附加的I/O,checksum的计算可以和I/O操作同时进行。
checksum的计算是针对添加到chunk尾部的写入操作作了高强度的优化(和改写现有数据不同),因为它们显然占据主要工作任务。我们增量更新关于最后block的checksum部分,并且计算添加操作导致的新的checksum block部分。即使是某一个checksum块已经损坏了,但是我们在写得时候并不立刻检查,新的checksum值也不会和已有数据吻合,下次对这个block的读取的时候,会检查出这个损坏的block。
另一方面,如果写操作基于一个已有的chunk(而不是在最后追加),我们必须读取和效验被写得第一个和最后一个block,然后再作写操作,最后计算和写入新的checksum。如果我们不效验第一个和最后一个被写得block,那么新的checksum可能会隐藏没有改写区域的损坏部分。
在chunkserver空闲的时候,他扫描和效验每一个非活动的chunk的内容。这使得我们能够检查不常用的chunk块的完整性。一旦发现这样的块有损坏,master可以创建一个新的正确的副本,然后把这个损坏的副本删除。这个机制防止了非活动的块损坏的时候,master还以为这些非活动块都已经有了足够多的副本。
5.3 诊断工具
详细的扩展诊断日志对于问题的发现和调试解决,以及性能分析来说,有着不可估量的作用,并且记录详细的扩展诊断日志只需要一点小小的开销。如果没有日志,很难理解偶发的,不能重现的机器间的交互作用。GFS服务器产生诊断日志,记录下很多关键时间(比如chunkserver启动和停止等等),以及所有的RPC请求和应答。这些诊断日志可以在不影响系统正确性的前提下删除。不过,如果磁盘空间允许,我们希望尽量保留这些日志信息。
RPC日志包括了在网络上传输的除了被操作的文件数据以外的请求和应答细节。通过匹配和比较不同机器上的RPC请求和应答,我们可以重构整个的交互历史,这样可以诊断问题。这些日志同样用于追踪负载测试以及性能分析。
记录日志对于性能的影响来说是比较小的(相比较而言产生的效果却是巨大的),因为日志是顺序的并且是异步的。最新的时间是在内存中保留,并且可以作持续的在线监控。
6 度量
在本节,我们通过几个小型的bechmark来演示GFS架构和实现上的性能瓶颈,并且展示了一些再GOOGLE内使用的真实地集群的性能数据。
6.1 小型benchmark
我们在一个有一个master,两个master副本,16个chunkserver,16个客户端的GFS集群上进行的性能测试。这个配置是用于便于测试使用的。实际上的集群通常有好几百台chunkserver和几百台客户端组成。
所有的机器都是有双1.4G PIII处理器,2GB内存,两个80GB 5400转硬盘,一个100M全双工网卡(连接到HP2524交换机)组成。全部19台GFS服务器都是连接到一个交换机上的,16台客户端连接到另一个交换机。两台交换机之间是用的1G链路连接的。
6.1.1 读取
N个客户端并行从文件系统读取。每一个客户端从320GB文件集合中,读取随机选取的4M区域。重复读取256次,每一个客户端最终读取1GB数据。chunkserver总共有32GB内存,这样我们预期有最多10%的Linux buffer cache命中率。我们的结果应当和冷cache的结果一致。
图三(a)展示了Nge客户端合计读取速度,以及它的理论上限。合计的理论上限是两个交换机之间的1GB链路饱和的情况下达到,就是125MB/s的速度,或者当客户端的100M网卡饱和的情况下的每客户端12.5MB/s的速度。当只有一个客户端读取的时候,观测到的读取速度是10MB/s,或者80%客户端的限制。16个客户端的合计读取速度达到了94MB/s,大约是75%的125MB/s的理论限制。由80%降低到75%的原因是由于读取者的增多,导致多个读取者同时从一个相同chunkserver读取得可能性增加,导致的读取性能下降。
6.1.2 写入
N个客户端同时向N个不同的文件写入。每一个客户端每次写入1MB,总共写入1GB的数据到一个新的文件。合计写入速度以及它的理论上限在图三(b)中展示。理论限制是67MB/s,是因为我们需要把每一个字节写入3个chunkserver,每个都有12.5MB/s的输入连接。
每一个客户端的写入速度是6.3MB/s,差不多是一般的限制主要原因是我们的网络协议栈。它和我们使用的推送数据到chunk副本的流水线机制的交互并不是很好。再把数据从一个副本传输到另一个副本的延时导致了整个写入速度的降低。16个客户端的合计写入速度差不多是35MB/s(或者2.2MB/s每客户端),差不多是理论极限的一般。和读取情况比较类似,这样的情况多半发生于多个客户端同步写入同一个chunkserver时导致的性能下降。此外,由于16个写者要比16个读者更容易产生冲突,这是因为每一个写入要写三份副本的原因。
写入速度比我们预期的要慢一点。在实际情况下,这并不是一个大问题,因为即使在单个客户端上能够感受到延时,他也不会对大量客户端的情况下,对整个写入带宽造成明显的影响。
6.1.3 记录增加
图三(c)展示了记录增加的性能。N各客户端同时对一个文件进行增加记录。性能是受到保存文件的最后一个chunk的chunkserver的带宽限制,而与客户端的数量无关。他从单个客户端的6.0MB/s降低到16个客户端的4.8MB/s,主要是由于不同客户端的网络拥塞以及网络传输速度的不同导致的。
我们的应用多属于同步产生多个这样的文件。换句话说,N个客户端对M个共享文件同步增加,N和M都是数十或者数百。因此,在我们实验中出现的chunkserver网络拥塞就在实际的情况下就不是一个问题,因为一个客户端可以在chunkserver对另一个文件忙得时候进行写入文件的操作。
6.2 实际的集群
我们现在通过Google的两个有代表性的集群来检查一下。集群A用于上百个工程师的研发。通常这个集群上的任务都是由人工发起的,运行好几个小时的任务。读取范围从好几M到好几TB数据,分析和处理数据,并且向集群写回结果。集群B是当前的生产数据处理集群。它上面的应用通常需要持续处理,并且产生和处理上TB的数据集,很少需要人工干预。在两个集群下,单个“task”意味着包含在很多机器上进行的很多读取和写入多个文件的并发进程。
Cluster
A
B
Chunkservers
342
227
可用硬盘空间
已用硬盘空间
72TB
55TB
180TB
155TB
文件数量
死文件数量
Chunk数量
735k
22k
992k
737k
232k
1550k
chunkserver元数据
master元数据
13GB
48MB
21GB
60MB
表2:两个GFS集群特性
6.2.1 存储
如同上表中描述的,两个集群都有上百台chunkserver,支持很多TB的硬盘空间,几乎不会满。”已用空间”包含了所有的chunk副本。一般来说所有的文件都有三个副本。因此,集群实际上各存储了18TB和52TB的文件数据。
两个集群都有相近的文件数目,虽然集群B有着很大的死文件数量,也就是说文件被删掉了或者用新版本代替了,而集群还没有来得及清理。并且应为文件比较大,集群B也有比较多的chunk数目。
6.2.2 元数据
chunkserver一共保存了十几个GB的元数据,主要是用户数据的64KB block的checksum数据。其他在chunkserver上保存的元数据是chunk的版本号,在4.5节有讲述。
在master上保存的元数据就小多了,只有数十MB,或者说平均每个文件100字节。这和我们的预期的一样,master的内存在实际上并不会是系统容量的限制瓶颈。大部分的文件的元数据都是文件名,而且是用的前缀压缩模式保存的。其他的元数据包括了文件的所有者和权限,以及文件到chunk的应设关系,以及每一个chunk的当前版本号。此外,每一个chunk我们都保存当前的副本位置以及对其的引用数字,用于实现写时拷贝[copy-on-write,3.4]。
每一个单独的服务器,chunkserver或者master,都只有50到100MB的元数据。因此恢复时很快:只需要几秒钟时间从磁盘读取这些数据就可以了响应请求了。不过,master会慢一点-通常30-60秒-它需要从所有的chunkserver获取当前chunk位置信息。
6.2.3 读写速率
表三显示了不同时段的读写速率。两个集群都采样了一周的时间。(集群最近因为升级新版本的GFS而重新启动了)。重新启动后,平均写入速率小雨30MB/s。当我们在采样期间,集群B在峰值写入速度达到了100MB/s,并且因为产生三个副本的原因,它产生了300MB/s的网络负载。
图三:合计吞吐量:上边的曲线显示了我们网络拓扑下的合计理论吞吐量上限。下边的曲线显示了观测到的吞吐量。这个曲线有着95%的可靠性,因为有时候测量会不够精确。
集群
A
B
读速率(最后一分钟)
读取率(最后一小时)
读速率(自从重启动)
583MB/s
562MB/s
589MB/s
380MB/s
384MB/s
49MB/s
写速率(最后一分钟)
写取率(最后一小时)
写速率(自从重启动)
1MB/s
1MB/s
25MB/s
101MB/s
117MB/s
13MB/s
master操作(最后一分钟)
master操作(最后一小时)
master操作(自从重启动)
325Ops/s
381Ops/s
202Ops/s
533Ops/s
518Ops/s
347Ops/s
表三:两个GFS集群的性能表
读取速率要比写入速率高很多。总共的负载包含的读取要远大于包含的写入,这符合我们的预期。两个集群都处于中等的读取压力。特别是,集群1在一周内都维持了580MB/s的读取速度。他的网络支持750MB/s,因此它很有效的利用了资源。集群B可以支持峰值读取速度是1300MB/s,它的应用只用到了380MB/s
6.2.4 master的负载
表三也包括了对master的操作率,大概是每秒200到500个操作。master可以轻松应付这样的访问速率,因此这不是主要的负载瓶颈。
在早期版本的GFS,master偶然会成为负载瓶颈。它花费了大量的时间顺序扫描大型目录(包含了数十万文件)来查找某一个文件。因此我们改了一下master的数据结构,这样支持高效的二进制的namespace检索。现在它可以支持每秒很多个上千个文件的访问。如果需要,我们还可以使用名字查找cache在namespace的数据结构来进一步提高性能。
6.2.5 恢复时间
在某一个chunkserver失效以后,其上的chunk可能会低于副本数量,这样于是就需要把这些chunk进行复制来达到相应的副本级别。这个操作所花的时间取决于资源的数量。在我们一个试验中,我们把集群B上编的一个chunkserver删掉。这个chunkserver上有大概15000个chunk,共计600GB数据。为了减少对正在运行的应用程序的影响,以及修正调度决策,我们缺省参数是限制这个集群中的并发克隆数量是91个(总chunkserver数量的40%),每一个克隆操作可以展到6.25MB/s(50mbps)的带宽。所有的chunk在23.2分钟内恢复了,大约有效复制速率是440MB/s。
在另外一个是严重,我们杀掉了两个chunkserver,每个chunkserver大概有16000个chunk并且包含大概660GB数据。这种双重故障导致了266个chunk只有单个副本。这些266个chunk于是克隆操作就提升到比较高的优先级,并且至少要在2分钟内恢复到起码两个副本,这样就可以能让系统恢复到容错另一个chunkserver失效的情况。
6.3 处理能力细目
在本节中,我们对比展示了两个GFS集群的工作量的细目情况。这两个集群和6.2中应用的集群不同。集群X是用于研发部分的,集群Y是生产数据处理的。
6.3.1 方法论和注意事项
我们考虑得处理能力只包含客户端发起的原始请求,这些请求代表了整个我们应用程序产生的对文件系统的工作量。处理能力中不包括处理客户请求所引起的中间请求,以及内部的后台应用,比如转发写请求或者重新均衡chunk分布等等。
I/O操作的统计是基于GFS服务器的实际RPC请求log重构的。例如,GFS客户端代码可能把一个读操作分解成为多个RPC调用,这样来增加并发度,我们从这些RPC来推断原始的读取请求。因为我们的操作模式是高度程式化的,所以我们可以把任何不符合的数据认为是误差。应用程序记录的日志可能会稍微对数据的精确性有点帮助,但是基本上不可能在上千个客户端上重新编译和重新运行应用程序,并且从这些机器上获得这些日志结果也是很麻烦的事情。
我们应当避免从我们的负载中进行过度归纳和推广。因为Google完全控制GFS和其上的应用程序,并且应用程序也是因为GFS而特意做调优,并且反过来说,GFS也是特意为这些应用而设计的。这些相互影响也可能在通用的应用和文件系统中,但是在我们的例子中更显著而已。
6.3.2 chunkserver的负载
表4显示了操作大小的分布。读取操作的大小体现了一个双峰分布。小型的读取请求(小于64KB),是从面向查找的客户端发起的,用于在巨量文件中查找小块数据的。大型的读取请求(大于512KB)是来自于对整个文件的序列读取。
在集群Y上,没有读到任何数据的请求占了相当的一部分。在我们的应用中,尤其是在生产系统中,经常使用文件作为生产者-消费者队列。生产者并行添加到文件,同时消费者从文件读取。某些情况下,消费者超过了生产者的速度的时候,就会出现没有读到任何数据的情况。集群X这样的情况出现的比较少见,这是因为通常集群X用于短期的数据分析任务,而不是长期的分布是应用。
写请求的大小也同样体现了双峰分布。大型写入(超过256KB)通常由写入者的重要缓存操作产生。写入者缓存较小的数据,checkpoint或者同步点,或者小型写入产生的小数据(小于64KB)。至于记录增加操作来说,集群Y看起来再大型记录增加方面要比集群X占百分比多,这是因为我们的实用集群Y的生产系统,是为GFS做了更极端的调优。
表5显示了不同大小的操作请求中的数据传输总数。多于所有操作来说,较大的操作(超过256KB)占据了主要的传输量,较小的读取(小于64KB)占据的传输量比较小,但是却是读取操作的相当一部分,这是因为随即寻找的工作量导致的。
操作
读
写
纪录增加
集群
X
Y
X
Y
X
Y
0K
0.4
2.6
0
0
0
0
1B…1K
0.1
4.1
6.6
4.9
0.2
9.2
1K…8K
65.2
38.5
0.4
1.0
18.9
15.2
8K…64K
29.9
45.1
17.8
43.0
78.0
2.8
64K…128K
0.1
0.7
2.3
1.9
<.1
4.3
128K…256K
0.2
0.3
31.6
0.4
<.1
10.6
256K…512K
0.1
0.1
4.2
7.7
<.1
31.2
512K…1M
3.9
6.9
35.5
28.7
2.2
25.5
1M…inf
0.1
1.8
1.5
12.3
0.7
2.2
表4:操作大小百分比细目(%)。对于读操作,大小是实际读取的数据和传送的数据,而不是请求的数据量。
6.3.3 增加纪录与写操作
纪录增加是在我们的应用系统中大量使用的。对于集群X来说,增加纪录写操作和普通写操作的比例按照字节比试108:1,按照操作比试8:1。对于集群Y来说,我们的生产系统的比例是3.7:1和2.5:1。进一步说,这个比例说明在我们的两个集群上,纪录增加都比写操作要大。对于集群X来说,在测量过程中,整体纪录增加占据的比率相对算小的,因此结果受到一个或者两个应用的某些特定的buffer大小的影响。
如同我们预期的,我们数据操作负载是受到纪录增加的影像而不是是改写的影响。我们测量第一个副本的数据改写情况。这近似于一个客户端故意覆盖刚刚写入的数据情况,而不是增加新数据的情况。对于集群X来说,改写操作在所占据字节上小于0.0001%,并且在所占据操作上小于0.0003%。对于集群Y,这个比率都是0.05%。虽然这只是某一片断的情况,依旧是高于我们的预期。这是由于大部分这些覆盖写,是因为客户端发生错误或者超时以后重试的情况。这本质上不算作负载量,而是重试机制的一个结果。
操作
读
写
纪录增加
集群
X
Y
X
Y
X
Y
1B..1K
<.1
<.1
<.1
<.1
<.1
<.1
1K…8K
13.8
3.9
<.1
<.1
<.1
0.1
8k…64k
11.4
9.3
2.4
5.9
2.3
0.3
64k…128k
0.3
0.7
0.3
0.3
22.7
1.2
128k…256k
0.8
0.6
16.5
0.2
<.1
5.8
256k…512k
1.4
0.3
3.4
7.7
<.1
38.4
512k…1M
65.9
55.1
74.1
58.0
0.1
46.8
1M…inf
6.4
30.1
3.3
28.0
53.9
7.4
表5:操作大小字节传输细目表(%)。对于读取来说,这个大小是实际读取的并且传输的,而不是请求读取的数量。两个不同点是如果读取尝试读超过文件结束的大小,那么实际读取大小就不是试图读取的大小,尝试读取超过文件结束的大小这样的操作在我们的负载中并不常见。
6.3.4 master的负载
表6显示了master上的请求类型区分的明细表。大部分的请求都是询问chunk位置的(FindLocation)和对读取和颁布令牌信息(FindLease-Locker)以及对数据更新的。
集群X和Y在删除请求上有着显著的不同,因为集群Y存储了生产数据集,会定义重新产生和用新的版本替换。这些不同点也在Open请求中有所体现,因为一个文件的旧版本可能随着新打开改写而默认删除(如同unix的open操作中的”w”模式)。
FindMatchingFiles是一个模式匹配请求,支持”ls”以及类似文件系统的操作。它不同于其他master上的请求,他可能会检索namespace的大部分内容,因此可能会非常耗时。集群Y这种操作要多一些音位自动化数据处理进程需要尝试检查文件系统的各个部分来试图理解整体的进程状态。与之不同的是,集群X的应用程序更加倾向于单独的用户控制,通常预先知道自己所需要使用的全部文件名。
集群
X
Y
Open
26.1
16.3
Delete
0.7
1.5
FindLocation
64.3
65.8
FindLeaseHolder
7.8
13.4
FindMatchingFiles
0.6
2.2
其他
0.5
0.8
表6:master请求类型明细(%)
7 经验
在建造和部署GFS的过程中,我们经历了不少问题,某些是操作上的,某些是技术上的
起初,我们构思GFS用于我们生产系统的后端文件系统。随着时间推移,增加了对研发任务的支持。于是开始增加一些小的功能比如权限和配额,到现在全面支持了这些内容。因为我们生产系统是严格受控的,但是用户层却不是这样的。于是我们研发了更多的架构支持用于防止用户间的干扰。
我们最大的问题是磁盘和linux相关的问题。很多磁盘都声称他们支持只要是IDE的linux驱动都可以,但是实际上却不是,实际上他们只支持最新的驱动。因为协议版本很接近,所以大部分磁盘都可以用,但是偶尔也会由于这些不匹配导致驱动和核心对于驱动器的状态误判。这会导致kernel无知觉的丢失数据。这些问题促使我们是用checksum来检查数据的损坏,同时我们也修改了核心来处理这些协议上的不匹配。
早先情况下,我们在linux2.2核心上有些问题,出在fsync()的效率问题。它的效率与文件的大小有关而不是和文件修改部分的大小有关。这在我们的操作log过长的时候就会有问题,尤其是在我们尚未实现checkpoint的时候。我们费了很大的力气用同步写操作解决这个问题,最后移植到linux2.4核心上。
另一个linux问题时单个写者-读者锁,就是说在某一个地址空间的任意一个线程都必须在从磁盘载入(page in读者锁)的时候先hold住,或者在mmap()调用(写者锁)的时候改写地址空间。我们发现在我们系统负载很轻的情况下有偶尔超时的情况,并且费了好大的力气去寻找资源的瓶颈或者硬件的问题。终于,我们发现这是单个lock,在磁盘线程交换以前的映射数据到磁盘的时候,锁住了当前的网络线程把新数据map到内存。因为我们主要受限于网络接口,而不是内存copy的带宽,所以,我们用pread()替换掉mmap,用了一个额外的copy动作来解决这个问题。
尽管偶尔还是有问题,linux的源代码还是使得沃恩能够迅速定位并且理解系统的行为。在适当的时候,我们会改进内核并且和公开源码组织共享这些改动。
8 相关工作
如同其他大型分布式文件系统比如AFS[5]一样,GFS提供了一个与位置无关的namespace,使得数据可以根据负载或者容错的原因在不同位置进行移动。但是不同于AFS的是,GFS把文件的数据分布到存储服务器上的方式,更类似Xfs[1]和Swift[3],这是为了提高整体性能以及增强容错能力。
由于磁盘相对来说比较便宜,以及副本方式比传统的RAID[9]简单许多,GFS目前只使用副本方式来进行冗余,因此要比xFS或者Swift花费更多的存储。
与AFS,xFS,Frangipani[12],以及Intermezzo[6]不同的是,GFS并没有在文件系统层面提供cache机制。我们的主要工作量在单个应用执行的时候几乎不会有重用的可能,因为他们无论是流式读取还是随机寻找,都是对大型数据集的操作。
某些分布式文件系统比如Frangipani,xFS,Minnesota’s GFS[11],GPFS[10],去掉了中心服务器,并且依赖于分布式算法来保证一致性和管理性。我们选择了采用中心服务器的做法是为了简化设计,增加可靠性和扩展能力。尤其是,一个中心master,由于它已经有了几乎所有的相关chunk信息以及控制chunk信息的能力,它可以非常简化实现传统的chunk分布和副本机制。我们通过减少master的状态量大小(元数据大小)以及全面分布master的状态到不同的机器上来保证容错能力。扩展能力和高可用性(对于读取)目前是通过我们的影子master机制来保证的。对master的状态更改是通过增加到一个往前写的log中持久化。因此我们可以在使用如同在Harp[7]中使用的primary-copy机制来保证高可用性以及对我们机制的一个强有效的一致性保证。
我们用类似Lustre[8]的方法来提供针对大量客户端的整体性能。不过,我们通过面向我们的应用的方式简化了问题的解决方法,而不是面向提供兼容POSIX文件系统的方式。此外,GFS假设我们大量使用了非可靠节点,所以容错处理是我们设计的核心。
GFS很类似NASD架构[4]。NASD架构是基于网络磁盘的。GFS用的是普通计算机作为chunkserver,如同NASD原形中一样。所不同的是,我们的chunkserver是滞后分配固定大小的chunk而不是用一个变长的结构。此外,GFS实现了诸如重新负载均衡,副本,恢复机制等等在生产环境中需要的特性。
与Minnesota’s GFS和NASD不同,我们并不改变存储设备的访问方式。我们集中于解决用普通计算机来解决日常的分布式系统所需要的数据处理。生产者消费者队列是通过原子的纪录增加来解决的,类似在River[2]中的分布式队列。River使用的是分布在机器组的基于内存的队列,并且仔细控制数据流。GFS用的是持久化文件,可以由很多生产者并发增加的方式。River模式支持m-到-n的分布式队列但是缺少用持久化存储的容错机制,GFS只支持m-到-1的队列。多个消费者可以同时读取一个文件,但是他们输入流的区间必须是对齐的。
9 结束语
Google 文件系统展示了使用常规硬件支持大规模数据处理的质量属性。虽然很多设计要素都是针对我们的特殊需要而定制的,但是很多都可以适用于基于成本考虑的类似规模的数据处理任务。首先我们依据现在和预期的应用负载和技术环境来审视传统的文件系统约定。我们的审视引导我们使用设计领域完全不同的思路来设计。我们在设计上认为部件失效属于常态而不是异常,通过面向巨型文件的主要追加模式进行优化(并发优化)并且读取优化(通常序列化读取),以及扩展和放松了标准文件系统接口来改进整个系统。
我们系统使用持续监控,复制关键数据,快速自动恢复来提供了容错处理。chunk复制使得我们可以对chunkserver的失效进行容错。这些失效的经常发生使得在线修复机制变得很有必要,使得需要尽快修复和补偿丢失的副本。此外,我们使用checksum来检查磁盘或者IDE系统级别的数据损坏,因为在这样大的一个系统中,磁盘数量惊人,所以损坏率也很高。
我们的设计要求对不同任务的大并发读取和写入有一个很高的合计吞吐量。我们通过分离文件系统控制和文件数据传输的设计来实现,我们通过master来进行文件系统的控制,通过chunkserver和客户端来进行文件数据的传输。master包括了常用的操作,并且通过大块的chunk大小进行元数据的缩小,以及通过chunklease令牌减少数据量,chunk令牌是授权给第一个副本以数据变更操作。这些使得一个简单,中心master不再成为一个瓶颈。我们相信我们对网络协议栈的优化可以提升对于每个客户端的当前的写入吞吐量限制。
GFS成功的实现了我们的存储要求以及在Google内部广泛应用于研发部门和生产数据处理的存储平台。它是我们持续创新和解决整个web范围的一个有力工具。
致谢
在这里我们想感谢对GFS和本论文做出贡献的人们。Brain Bershad(我们的领头人)以及其他阅读这给了我们有用的意见和建议。Anurag Acharya,Jeff Dean,David desJardins 建立了早期的设计。Fay Chang 在对比chunserver之间的副本作了重要工作。Guy Edjiali在存储部分作主要工作。Markus Gutschke在测试框架和提高安全性。David Karmer在性能提高上作工作。Fay Chang,Urs Hoelzle,Max Lbel,Sharon Perl,Rob Pike, Debby Wallach 对本文早期版本提出了建议。Google的很多同僚都很勇敢的信任我们的新系统,把他们的数据放上来,并且给了我们很有用的反馈。Yoshka在早期测试工作中作了贡献。
参考资料
[1] Thomas Anderson, Michael Dahlin, Jeanna Neefe,David Patterson, Drew Roselli, and Randolph Wang. Serverless networkfil e systems. In Proceedings of the 15th ACM Symposium on Operating System Principles, pages 109–126, Copper Mountain Resort, Colorado, December 1995.
[2] Remzi H. Arpaci-Dusseau, Eric Anderson, Noah Treuhaft, David E. Culler, Joseph M. Hellerstein, David Patterson, and Kathy Yelick. Cluster I/O with River: Making the fast case common. In Proceedings of the Sixth Workshop on Input/Output in Parallel and Distributed Systems (IOPADS ’99), pages 10–22, Atlanta, Georgia, May 1999.
[3] Luis-Felipe Cabrera and Darrell D. E. Long. Swift: Using distributed disks triping to provide high I/O data rates. Computer Systems, 4(4):405–436, 1991.
[4] Garth A. Gibson, David F. Nagle, Khalil Amiri, Jeff Butler, Fay W. Chang, Howard Gobioff, Charles Hardin, ErikR iedel, David Rochberg, and Jim Zelenka. A cost-effective, high-bandwidth storage architecture. In Proceedings of the 8th Architectural Support for Programming Languages and Operating Systems, pages 92–103, San Jose, California, October 1998.
[5] John Howard, Michael Kazar, Sherri Menees, David Nichols, Mahadev Satyanarayanan, Robert Sidebotham, and Michael West. Scale and performance in a distributed file system. ACM Transactions on Computer Systems, 6(1):51–81, February 1988.
[6] InterMezzo. http://www.inter-mezzo.org, 203.
[7] Barbara Liskov, Sanjay Ghemawat, Robert Gruber, Paul Johnson, Liuba Shrira, and Michael Williams. Replication in the Harp file system. In 13th Symposium on Operating System Principles, pages 226–238, Pacific Grove, CA, October 1991.
[8] Lustre. http://www.lustreorg, 2003.
[9] David A. Patterson, Garth A. Gibson, and Randy H. Katz. A case for redundant arrays of inexpensive disks (RAID). In Proceedings of the 1988 ACM SIGMOD International Conference on Management of Data, pages 109–116, Chicago, Illinois, September 1988.
[10] FrankS chmuck and Roger Haskin. GPFS: A shared-diskfi le system for large computing clusters. In Proceedings of the First USENIX Conference on File and Storage Technologies, pages 231–244, Monterey, California, January 2002.
[11] Steven R. Soltis, Thomas M. Ruwart, and Matthew T. O’Keefe. The Gobal File System. In Proceedings of the Fifth NASA Goddard Space Flight Center Conference on Mass Storage Systems and Technologies, College Park, Maryland, September 1996.
[12] Chandramohan A. Thekkath, Timothy Mann, and Edward K. Lee. Frangipani: A scalable distributed file system. In Proceedings of the 16th ACM Symposium on Operating System Principles, pages 224–237, Saint-Malo, France, October 1997.