江湖传说永流传:谷歌技术有"三宝",GFS、MapReduce和大表(BigTable)!
谷歌在03到06年间连续发表了三篇很有影响力的文章,分别是03年SOSP的GFS,04年OSDI的MapReduce,和06年OSDI的BigTable。SOSP和OSDI都是操作系统领域的顶级会议,在计算机学会推荐会议里属于A类。SOSP在单数年举办,而OSDI在双数年举办。
那么这篇博客就来介绍一下GFS,MapReduce,BigTable。
谷歌技术"三宝"之谷歌文件系统
题记:初学分布式文件系统,写篇博客加深点印象。GFS的特点是使用一堆廉价的商用计算机支撑大规模数据处理。
虽然"The Google File System " 是03年发表的老文章了,但现在仍被广泛讨论,其对后来的分布式文件系统设计具有指导意义。然而,作者在设计GFS时,是基于过去很多实验观察的,并提出了很多假设作为前提,这等于给出了一个GFS的应用场景。所以我们自己在设计分布式系统时,一定要注意自己的应用场景是否和GFS相似,不能盲从GFS。
GFS的主要假设如下:
- GFS的服务器都是普通的商用计算机,并不那么可靠,集群出现结点故障是常态。因此必须时刻监控系统的结点状态,当结点失效时,必须能检测到,并恢复之。
- 系统存储适当数量的大文件。理想的负载是几百万个文件,文件一般都超过100MB,GB级别以上的文件是很常见的,必须进行有效管理。支持小文件,但不对其进行优化。
- 负载通常包含两种读:大型的流式读(顺序读),和小型的随机读。前者通常一次读数百KB以上,后者通常在随机位置读几个KB。
- 负载还包括很多连续的写操作,往文件追加数据(append)。文件很少会被修改,支持随机写操作,但不必进行优化。
- 系统必须实现良好定义的语义,用于多客户端并发写同一个文件。同步的开销必须保证最小。
- 高带宽比低延迟更重要,GFS的应用大多需要快速处理大量的数据,很少会严格要求单一操作的响应时间。
从这些假设基本可以看出GFS期望的应用场景应该是大文件,连续读,不修改,高并发。国内的淘宝文件系统(TFS)就不一样,专门为处理小文件进行了优化。
1 体系结构
GFS包括一个master结点(元数据服务器),多个chunkserver(数据服务器)和多个client(运行各种应用的客户端)。在可靠性要求不高的场景,client和chunkserver可以位于一个结点。图1是GFS的体系结构示意图,每一结点都是普通的Linux服务器,GFS的工作就是协调成百上千的服务器为各种应用提供服务。
- chunkserver提供存储。GFS会将文件划分为定长数据块,每个数据块都有一个全局唯一不可变的id(chunk_handle),数据块以普通Linux文件的形式存储在chunkserver上,出于可靠性考虑,每个数据块会存储多个副本,分布在不同chunkserver。
- GFS master就是GFS的元数据服务器,负责维护文件系统的元数据,包括命名空间、访问控制、文件-块映射、块地址等,以及控制系统级活动,如垃圾回收、负载均衡等。
- 应用需要链接client的代码,然后client作为代理与master和chunkserver交互。master会定期与chunkserver交流(心跳),以获取chunkserver的状态并发送指令。
图1还描述了应用读取数据的流程。1.应用指定读取某个文件的某段数据,因为数据块是定长的,client可以计算出这段数据跨越了几个数据块,client将文件名和需要的数据块索引发送给master;2.master根据文件名查找命名空间和文件-块映射表,得到需要的数据块副本所在的地址,将数据块的id和其所有副本的地址反馈给client;3.client选择一个副本,联系chunkserver索取需要的数据;4.chunkserver返回数据给client。
2 数据的布局
GFS将文件条带化,按照类似RAID0的形式进行存储,可以提高聚合带宽。事实上,大多数分布式存储系统都会采取这种策略。GFS将文件按固定长度切分为数据块,master在创建一个新数据块时,会给每个数据块分配一个全局唯一且不可变的64位id。每个数据块以Linux文件的形式存储在chunkserver的本地文件系统里。
GFS为数据块设置了一个很大的长度,64MB,这比传统文件系统的块长要大多了。大块长会带来很多好处:1.减少client和master的交互次数,因为读写同一个块只需要一次交互,在GFS假设的顺序读写负载的场景下特别有用;2.同样也减少了client和chunkserver的交互次数,降低TCP/IP连接等网络开销;3.减少了元数据的规模,因此master可以将元数据完全放在内存,这对于集中式元数据模型的GFS尤为重要。
大数据块也有缺点。最大的缺点可能就是内部碎片了,不过考虑到文件一般都相当大,所以碎片也只存在于文件的最后一个数据块。还有一个缺点不是那么容易看出来,由于小文件可能只有少量数据块,极端情况只有一个,那么当这个小文件是热点文件时,存储该文件数据块的chunkserver可能会负载过重。不过正如前面所说,小文件不在GFS的优化范围。
为了提高数据的可靠性和并发性,每一个数据块都有多个副本。当客户端请求一个数据块时,master会将所有副本的地址都通知客户端,客户端再择优(距离最短等)选择一个副本。一个典型的GFS集群可能有数百台服务器,跨越多个子网,因此在考虑副本的放置时,不仅要考虑机器级别的错误,还要考虑整个子网瘫痪了该怎么办。将副本分布到多个子网去,还可以提高系统的聚合带宽。因此创建一个数据块时,主要考虑几个因素:1.优先考虑存储利用率低于平均水平的结点;2.限制单个节点同时创建副本的数量;3.副本尽量跨子网。
3 元数据服务
GFS是典型的集中式元数据服务,所有的元数据都存放在一个master结点内。元数据主要包括三种:文件和数据块的命名空间,文件-数据块映射表,数据块的副本位置。所有的元数据都是放在内存里的。
前两种元数据会被持久化到本地磁盘中,以操作日志的形式。操作日志会记录下这两种元数据的每一次关键变化,因此当master宕机,就可以根据日志恢复到某个时间点。日志的意义还在于,它提供了一个时间线,用于定义操作的先后顺序,文件、数据块的版本都依赖于这个时间顺序。
数据块的副本位置则没有持久化,因为动辄数以百计的chunkserver是很容易出错的,因此只有chunkserver对自己存储的数据块有绝对的话语权,而master上的位置信息很容易因为结点失效等原因而过时。取而代之的方法是,master启动时询问每个chunkserver的数据块情况,而且chunkserver在定期的心跳检查中也会汇报自己存储的部分数据块情况。
GFS物理上没有目录结构,也不支持链接操作,使用一张表来映射文件路径名和元数据。
4 缓存和预取
GFS的客户端和chunkserver都不会缓存任何数据,这是因为GFS的典型应用是顺序访问大文件,不存在时间局部性。空间局部性虽然存在,但是数据集一般很大,以致没有足够的空间缓存。
我们知道集中式元数据模型的元数据服务器容易成为瓶颈,应该尽量减少客户端与元数据服务器的交互。因此GFS设计了元数据缓存。client需要访问数据时,先询问master数据在哪儿,然后将这个数据地址信息缓存起来,之后client对该数据块的操作都只需直接与chunkserver联系了,当然缓存的时间是有限的,过期作废。
master还会元数据预取。因为空间局部性是存在,master可以将逻辑上连续的几个数据块的地址信息一并发给客户端,客户端缓存这些元数据,以后需要时就可以不用找master的麻烦了。
5 出错了肿么办
引用:“We treat component failures as the norm rather than the exception."
分布式系统整体的可靠性是至关重要的。GFS集群使用的都是普通的商用计算机,而且机器的数量众多,设备故障经常出现,如何处理结点失效的问题是GFS最大的挑战。
5.1 完整性
GFS使用数以千计的磁盘,磁盘出错导致数据被破坏时有发生,我们可以用其它副本来恢复数据,但首先必须能检测出错误。chunksever会使用校验和来检测错误数据。每一个块(chunk)都被划分为64KB的单元(block),每个block对应一个32位的校验和。校验和与数据分开存储,内存有一份,然后以日志的形式在此盘备一份。
chunkserver在发送数据之前会核对数据的校验和,防止错误的数据传播出去。如果校验和与数据不匹配,就返回错误,并且向master反映情况。master会开始克隆副本的操作,完成后就命令该chunkserver删除非法副本。
5.2 一致性
一致性指的是master的元数据和chunkserver的数据是否一致,多个数据块副本之间是否一致,多个客户端看到的数据是否一致。
先来看看元数据一致性。GFS的命名空间操作是原子性的,并且用日志记录下操作顺序。虽然GFS没有目录结构,但是仍然有一颗逻辑的目录树,树的每个结点都有自己的读写锁,每个元数据操作都需要获得一系列的锁,应该是写锁会阻塞其它的锁,而读锁只阻塞写锁而不阻塞读锁。比如/home/user "目录" 正在创建快照,需要获得/home的读锁和/home/user的写锁,这时如果想创建文件/home/user/foo会被阻塞,因为需要获得/home、/home/user的读锁以及/home/user/foo的写锁,快照会阻塞创建操作获取/home/user的读锁。如果是在一个有传统目录树结构的文件系统里,创建一个文件需要修改父目录的数据,因此需要获得父目录的写锁。这种锁机只允许在一个目录里并发修改数据(如并发创建文件等),这在传统文件系统里是不允许的。