本文是读GFS论文的总结,收录在个人github中papers项目,papers项目旨在学习和总结分布式系统相关的论文。git
全文主要分为如下几方面:github
google对现有系统的运行状态以及应用系统进行总结,抽象出对文件系统的需求,主要分为如下几个方面。后端
本部分讨论gfs的整体架构,以及在此架构上须要考虑的一些问题。缓存
GFS的总体架构以下图:微信
(图片来源:gfs论文)网络
GFS中有四类角色,分别是数据结构
在GFS chunkserver中,文件都是分红固定大小的chunk来存储的,每一个chunk经过全局惟一的64位的chunk handle来标识,chunk handle在chunk建立的时候由GFS master分配。GFS chunkserver把文件存储在本地磁盘中,读或写的时候须要指定文件名和字节范围,而后定位到对应的chunk。为了保证数据的可靠性,一个chunk通常会在多台GFS chunkserver上存储,默认为3份,但用户也能够根据本身的须要修改这个值。架构
GFS master管理全部的元数据信息,包括namespaces,访问控制信息,文件到chunk的映射信息,以及chunk的地址信息(即chunk存放在哪台GFS chunkserver上)。并发
GFS client是GFS应用端使用的API接口,client和GFS master交互来获取元数据信息,可是全部和数据相关的信息都是直接和GFS chunkserver来交互的。app
Application为使用gfs的应用,应用经过GFS client于gfs后端(GFS master和GFS chunkserver)打交道。
GFS架构中只有单个GFS master,这种架构的好处是设计和实现简单,例如,实现负载均衡时能够利用master上存储的全局的信息来作决策。可是,在这种架构下,要避免的一个问题是,应用读和写请求时,要弱化GFS master的参与度,防止它成为整个系统架构中的瓶颈。
从一个请求的流程来讨论上面的问题。首先,应用把文件名和偏移量信息传递给GFS client,GFS client转换成(文件名,chunk index)信息传递给GFS master,GFS master把(chunk handle, chunk位置信息)返回给客户端,客户端会把这个信息缓存起来,这样,下次再读这个chunk的时候,就不须要去GFS master拉取chunk位置信息了。
另外一方面,GFS支持在一个请求中同时读取多个chunk的位置信息,这样更进一步的减小了GFS client和GFS master的交互次数,避免GFS master成为整个系统的瓶颈。
对于GFS来讲,chunk size的默认大小是64MB,比通常文件系统的要大。
优势
缺点
对于热点问题,google给出的解决方案是应用层避免高频地同时读写同一个chunk。还提出了一个可能的解决方案是,GFS client找其余的GFS client来读数据。
64MB应该是google得出的一个比较好的权衡优缺点的经验值。
GFS master存储三种metadata,包括文件和chunk namespace,文件到chunk的映射以及chunk的位置信息。这些metadata都是存储在GFS master的内存中的。对于前两种metadata,还会经过记操做日志的方式持久化存储,操做日志会同步到包括GFS master在内的多台机器上。GFS master不持久化存储chunk的位置信息,每次GFS master重启或者有新的GFS chunkserver加入时,GFS master会要求对应GFS chunkserver把chunk的位置信息汇报给它。
使用内存存储metadata的好处是读取metadata速度快,方便GFS master作一些全局扫描metadata相关信息的操做,例如负载均衡等。
可是,之内存存储的的话,须要考虑的是GFS master的内存空间大小是否是整个系统能存储的chunk数量的瓶颈所在。在GFS实际使用过程当中,这通常不会成为限制所在,由于GFS中一个64MBchunk的metadata大小不超过64B,而且,对于大部分chunk来说都是使用的所有的空间的,只有文件的最后一个chunk会存储在部分空间没有使用,所以,GFS master的内存空间在实际上不多会成为限制系统容量的因素。即便真的是现有的存储文件的chunk数量超过了GFS master内存空间大小的限制,也能够经过加内存的方式,来获取内存存储设计带来的性能、可靠性等多种好处。
GFS master不持久化存储chunk位置信息的缘由是,GFS chunkserver很容易出现宕机,重启等行为,这样GFS master在每次发生这些事件的时候,都要修改持久化存储里面的位置信息的数据。
operation log的做用
怎么存
operation log会存储在GFS master和多台远程机器上,只有当operation log在GFS master和多台远程机器都写入成功后,GFS master才会向GFS client返回成功。为了减小operation log在多台机器落盘对吞吐量的影响,能够将一批的operation log造成一个请求,而后写入到GFS master和其余远程机器上。
check point
当operation log达到必定大小时,GFS master会作checkpoint,至关于把内存的B-Tree格式的信息dump到磁盘中。当master须要重启时,能够读最近一次的checkpoint,而后replay它以后的operation log,加快恢复的时间。
作checkpoint的时候,GFS master会先切换到新的operation log,而后开新线程作checkpoint,因此,对新来的请求是基本是不会有影响的。
本部分讨论GFS的系统交互流程。
GFS master对后续的数据流程是不作控制的,因此,须要一个机制来保证,全部副本是按照一样的操做顺序写入对应的数据的。GFS采用lease方式来解决这个问题,GFS对一个chunk会选择一个GFS chunkserver,发放lease,称做primary,由primary chunkserver来控制写入的顺序。
Lease的过时时间默认是60s,能够经过心跳信息来续时间,若是一个primary chunkserver是正常状态的话,这个时间通常是无限续下去的。当primary chunkserver和GFS master心跳断了后,GFS master也能够方便的把其余chunk副本所在的chunkserver设置成primary。
(图片来源:gfs论文)
这里,写数据若是发生错误可能会产生不一致的状况,会在consistency model中讨论。
4.1中第三步的Data Flow采用的是pipe line方式,目标是为了充分利用每台机器的网络带宽。假设一台机器总共有三个副本S1-S3。整个的Data Flow为:
不断重复上述流程,直到全部的chunkserver都收到client的全部数据。
以上述方式来传送B字节数据到R个副本,并假设网络吞吐量为T,机器之间的时延为L,那么,整个数据的传输时间为B/T+RL。
Append操做流程和写差很少,主要区别在如下
这里须要讨论的是,若是append操做在部分副本失败的状况下,会发生什么?
例如,写操做要追加到S1-S3,可是,仅仅是S1,S2成功了,S3失败了,GFS client会重试操做,假如第二次成功了,那么S1,S2写了两次,S3写了一次,目前的理解是GFS会先把失败的记录进行padding对齐到primary的记录,而后再继续append。
Snapshot的整个流程以下:
当snapshot操做完成后,client写snapshot中涉及到的chunk C的流程以下:
(图片来源:gfs论文)
GFS中consistent、defined的定义以下:
下面分析表格中出现的几种状况。
GFS用version来标记一个chunkserver挂掉的期间,是否有client进行了write或者append操做。每进行一次write或者append,version会增长。
须要考虑的点是client会缓存chunk的位置信息,有可能其中某些chunkserver已经挂掉又起来了,这个时候chunkserver的数据多是老的数据,读到的数据是会不一致的。读流程中,好像没有看到要带version信息来读的。这个论文中没看到避免的措施,目前尚未结果。
应用层须要采用的机制:用append而不是write,作checkpoint,writing self-validating和self-identifying records。具体地,以下:
GFS master的功能包括,namespace Management, Replica Placement,Chunk Creation,Re-replication and Rebalancing以及Garbage Collection。
每一个master操做都须要得到一系列的锁。若是一个操做涉及到/d1/d2/.../dn/leaf,那么须要得到/d1,/d1/d2,/d1/d2/.../dn的读锁,而后,根据操做类型,得到/d1/d2/.../dn/leaf的读锁或者写锁,其中leaf多是文件或者路径。
一个例子,当/home/user被快照到/save/user的时候,/home/user/foo的建立是被禁止的。
对于快照,须要得到/home和/save的读锁,/home/user和/save/user的写锁。对于建立操做,会得到/home,/home/user的读锁,而后/home/user/foo的写锁。其中,/home/user的锁产生冲突,/home/user/foo建立会被禁止。
这种加锁机制的好处是对于同一个目录下,能够并行的操做文件,例如,同一个目录下并行的建立文件。
GFS的Replica Placement的两个目标:最大化数据可靠性和可用性,最大化网络带宽的使用率。所以,把每一个chunk的副本分散在不一样的机架上,这样一方面,能够抵御机架级的故障,另外一方面,能够把读写数据的带宽分配在机架级,重复利用多个机架的带宽。
GFS在建立chunk的时候,选择chunkserver时考虑的因素包括:
当一个chunk的副本数量少于预设定的数量时,须要作复制的操做,例如,chunkserver宕机,副本数据出错,磁盘损坏,或者设定的副本数量增长。
chunk的复制的优先级是按照下面的因素来肯定的:
chunk复制的时候,选择新chunkserver要考虑的点:
周期性地检查副本分布状况,而后调整到更好的磁盘使用状况和负载均衡。GFS master对于新加入的chunkserver,逐渐地迁移副本到上面,防止新chunkserver带宽打满。
在GFS删除一个文件后,并不会立刻就对文件物理删除,而是在后面的按期清理的过程当中才真正的删除。
具体地,对于一个删除操做,GFS仅仅是写一条日志记录,而后把文件命名成一个对外部不可见的名称,这个名称会包含删除的时间戳。GFS master会按期的扫描,当这些文件存在超过3天后,这些文件会从namespace中删掉,而且内存的中metadata会被删除。
在对chunk namespace的按期扫描时,会扫描到这些文件已经被删除的chunk,而后会把metadata从磁盘中删除。
在与chunkserver的heartbeat的交互过程当中,GFS master会把不在metadata中的chunk告诉chunkserver,而后chunkserver就能够删除这些chunk了。
采用这种方式删除的好处:
坏处:
当一台chunkserver挂掉的时候,有新的写入操做到chunk副本,会致使chunkserve的数据不是最新的。
当master分配lease到一个chunk时,它会更新chunk version number,而后其余的副本都会更新该值。这个操做是在返回给客户端以前完成的,若是有一个chunkserver当前是宕机的,那么它的version number就不会增长。当chunkserver重启后,会汇报它的chunk以及version number,对于version number落后的chunk,master就认为这个chunk的数据是落后的。
GFS master会把落后的chunk当垃圾来清理掉,而且不会把落后的chunkserver的位置信息传给client。
备注:
1. GFS master把落后的chunk看成垃圾清理,那么,是不是走re-replication的逻辑来生成新的副本呢?没有,是走当即复制的逻辑。
为了实现高可用性,GFS在经过两方面来解决,一是fast recovery,二是replication
master和chunkserver都被设计成都能在秒级别重启
每一个chunk在多个机架上有副本,副本数量由用户来指定。当chunkserver不可用时,GFS master会自动的复制副本,保证副本数量和用户指定的一致。
master的operation log和checkpoint都会复制到多台机器上,要保证这些机器的写都成功了,才认为是成功。只有一台master在来作garbage collection等后台操做。当master挂掉后,它能在不少时间内重启;当master所在的机器挂掉后,监控会在其余具备operation log的机器上重启启动master。
新启动的master只提供读服务,由于可能在挂掉的一瞬间,有些日志记录到primary master上,而没有记录到secondary master上(这里GFS没有具体说同步的流程)。
每一个chunkserver都会经过checksum来验证数据是否损坏的。
每一个chunk被分红多个64KB的block,每一个block有32位的checksum,checksum在内存中和磁盘的log中都有记录。
对于读请求,chunkserver会检查读操做所涉及block的全部checksum值是否正确,若是有一个block的checksum不对,那么会报错给client和master。client这时会从其余副本读数据,而master会clone一个新副本,当新副本clone好后,master会删除掉这个checksum出错的副本。
主要是经过log,包括重要事件的log(chunkserver上下线),RPC请求,RPC响应等。
本部分主要讨论大规模分布式系统一书上,列出的关于gfs的一些问题,具体以下。
优势
缺点
64MB应该是google得出的一个比较好的权衡优缺点的经验值。
主要是为了更有效地利用网络带宽。把数据流分开,能够更好地优化数据流的网络带宽使用。
若是不分开,须要讨论下。
padding出现场景:
重复记录出现场景:
lease是gfs master把控制写入顺序的权限下放给chunkserver的机制,以减小gfs master在读写流程中的参与度,防止其成为系统瓶颈。心跳是gfs master检测chunkserver是否可用的标志。
namespace、文件到chunk的映射以及chunk的位置信息
namespace采用的是B-Tree,对于名称采用前缀压缩的方法,节省空间;(文件名,chunk index)到chunk的映射,能够经过hashmap;chunk到chunk的位置信息,能够用multi_hashmap,由于是一对多的映射。
1GB/64MB = 1024 / 64 = 16。总共须要16 10000000 64 B = 10GB
主要是考虑CPU、内存、网络和I/O,但如何综合这些参数并计算仍是得看具体的场景,每部分的权重随场景的不一样而不一样。
如何选择chunkserver
如何避免同时迁移
经过限制单个chunkserver的clone操做的个数,以及clone使用的带宽来限制,即从源chunkserver度数据的频率作控制。
由于是过一会,因此假设chunk re-replication尚未执行,那么在这期间,可能这台chunkserver上有些chunk的数据已经处于落后状态了,client读数据的时候或者chunkserver按期扫描的时候会把这些状态告诉给master,master告诉上线后的chunkserver从其余机器复制该chunk,而后master会把这个chunk看成是垃圾清理掉。
对于没有落后的chunk副本,能够直接用于使用。
Snapshot的整个流程以下:
当snapshot操做完成后,client写snapshot中涉及到的chunk C的流程以下:
chunkserver主要是存储64KB block的checksum信息,须要由chunk+offset,可以快速定位到checksum,能够用hashmap。
利用checksum机制,分读和写两种状况来讨论:
chunkserver重启后,会汇报chunk及其version number,master根据version number来判断是否过时。若是过时了,那么会作如下操做:
问题:若是chunkserver拷贝数据的过程过程当中,以前拷贝的数据备份又发生了变化,而后分为两种状况讨论:
PS:
本博客更新会在第一时间推送到微信公众号,欢迎你们关注。