1.
GFS集群包括一个Master节点,多个chunkserver及多个client。
这里的一个Master节点应该是个概念上的东西,具体实施分布时会有两个或更多个Master机器(但职责不同于Master,原则上我们依然认为只有一个master),如“shadow master”。
chunkserver就是普通的linux机器运行着chunkserver进程,文件存储采用linux 文件系统如ext3,ext4。
client看作是GFS的接口,负责应用程序与GFS的沟通。
文件划分成固定大小的chunk,每个chunk由一个64bit的chunk handle唯一标识,由master创建时分配。
各自职责:
Master维护系统的元数据(命名空间,访问控制信息,文件到chunk的映射,当前chunks的位置信息),管理系统范围的活动,如chunk的租用,孤儿chunk的回收,chunk在chunkserver间的迁移。master与每个chunkserver间使用心跳信息周期地通信,发送指令到chunkserver并接收chunkserver的状态信息。
Chunkserver存储chunk,根据client提供的chunk handle和byte range读写chunk数据。周期性地向master报告本地存储的chunk状态信息。
Client与master进行元数据的交互,与chunkserver进行的是数据通信。根据文件名和读写的字节偏移量锁定chunk index(chunk大小固定),将file name与chunk index发给master,master根据file与chunk的映射关系,将对应chunk的handle和location回复给client。
2.
所有的元数据(三种)存于master的内存中,其中,命名空间与file-chunk映射会被记录变更日志存储于master本地磁盘并在远程master服务器上备份;对于chunk位置信息的更新需要chunkserver的配合。Master启动时轮询chunkserver(论文里面有个词是轮询,但是理解起来是Master主动轮询,其实不然,Master始终处于一个被动提供服务的角色,chunkserver的状态应该是chunkserver主动汇报的),另外周期性与chunkserver进行心跳交互时捎带chunk的位置和状态。
命名空间——我的理解就是一棵前缀压缩的目录树,叶节点可能是文件也可能是目录。对树上每个节点的操作之前都要获得读/写锁。
3.
4.
5.
操作日志记录元数据的变更历史,同时规定了一种逻辑顺序。我的理解是日志中的序号可以作为操作的逻辑时间,这样,日志在全局上定义了一种操作顺序,包括并发行为的操作。要达到这种效果,就要保证日志记录的完整性和一致性(日志在每个master上一个副本)。
Master如果崩溃了就可以借助操作日志进行恢复。日志文件超过一定大小时master就对系统状态做一次checkpoint(紧凑的B-tree),存于本地磁盘【checkpoint文件是否需要备份?当然了,应该也要写入远程的master机器上】
之所以要有checkpoint,目的是为了让系统恢复时需要的日志文件少一些,系统恢复重启能够更快,因为系统恢复时只需读取checkpoint及checkpoint之后的有限个日志记录即可。
6.
7.
记录追加操作:论文中是这样定义的,即使有多个修改操作并行执行,记录追加操作至少可以把数据原子性地追加到文件中一次,但是偏移位置是由GFS选择的。很费解是不是?其实也不难理解,如果记录追加在任何一个副本上失败了,这样同chunk的不同副本上包含不同的数据。然而GFS不保证所有的副本在字节级完全一致,也就是说,副本并不是完全一样的,只要能保证数据至少一次作为一个原子单元被写入然后返回正确的偏移即可。至于文件中有些区域可能是坏的那就由另外的机制去解决了。
GFS通过两种机制确保修改的文件区域是已定义的:租约机制和检测chunk版本号是否陈旧。
记录追加成功之后出现的chunkserver失效或数据损坏问题,GFS的解决方案是,通过master和所有chunkserver的定期握手来找到失效的chunkserver,使用Checksum来校验数据是否损坏。
租约机制用来协同chunk的所有副本的修改操作,使用相同的操作顺序。Master选一个副本的chunk为主chunk,维护一个lease,主chunk规定了对该chunk的所有修改的顺序,所有副本按照此顺序执行修改操作。
8.
原子的记录追加也是按照上图7的流程,客户机把数据推送给文件最后一个chunk的所有副本,之后发送请求给主chunk。主chunk要检查本次追加的记录是否会使chunk超过最大值,是则先填满本chunk,通知副本同样操作,然后通知client在下一个chunk上继续追加.图7步骤5中,主chunk将写请求转发给其他副本,并按照规定的序列执行写操作,但是主chunk怎么知道其他副本的位置?这个信息可以由master告诉它。
9.
10.
快照的作用备份当前状态以便回滚。写时复制技术实现快照。Master收到快照请求时先取消租约,后续对该chunk的写操作需先与master交互找到主chunk,master就趁此创建chunk的一个拷贝。
(快照创建完成之后client写chunk C,master发现chunk C的引用计数大于1,这里没理解肿么回事?)
11.
每个chunkserver使用校验和检查数据是否损坏,每个Chunk分成64KB大小的块,每个块都对应一个32位的Checksum。和其它元数据一样,Checksum保存在内存和硬盘上,同时也记录操作日志。
读操作:校验读取操作涉及范围内的块的Checksum
追加写操作:只更新最后一个不完整块的Checksum,然后用所有的追加来的新块来计算新的Checksum
覆盖写操作:读取和校验覆盖范围内的第一个和最后一个块,然后再执行写操作;操作完成之后再重新计算和写入新的Checksum
Chunkserver空闲时,扫描并校验每个不活动的chunk的内容,检测很少被读取的chunk是否完整。
其他:
Chunk副本创建(创建完放哪),重新复制(多个需要复制时先复制哪个,新副本的位置选择),和重新负载均衡(检查副本分布,需要移动哪个)。
垃圾回收:删除操作记录日志,不立即删除文件而是把文件名改为一个包含删除时间戳的隐藏的名字,超过一定时间限制才会删除。重改文件名可以取消删除。
如何发现孤儿chunk?扫描file-chunk映射表,没有file关联的chunk删除其元数据,chunkserver向master report它的chunk信息,master回复它哪些chunk已经不存在元数据chunkserver就可以删除了。
副本检测:每个chunk一个版本号,master和chunk签订一个租约时增加版本号,并通知其他副本。