作者:李小翠
Motivation
- meet the rapidly growing demands of Google's data processing needs
- 目标:高性能、高可扩、高可用
- 背景: 元器件失效是常事、大文件(Multi-GB files are common)、大多数文件为追加(appending over than overwriting)、应用程序和文件系统的API协同设计,不遵循POSIX规范(co-designing the application and the file system API)
- 使用场景:生产者-消费者队列
Workload
- big data(tipically 100MB/multi-GB files/growing data sets of many TBs comprising billions of objects)
- small files support but not optimize
- append rather than overwriting
- detect、tolerant and recover promptly from component failures
- large streaming reads(1M or more) and small random reads
- large sequential writes that append data to files
- concurrently append to the same file
- high sustained bandwidth more important than low latency
Interface
creat delete open close read write snapshot record append
snapshot :creates a copy of a file or directory tree at low cost [copy-on-write]record append:allowmutiple clients to append data to the same file concurrently [producer-consumer queues]
Architecture

组成
- sigle master
- mutiple chunkservers
- accessed by mutiple clients
chunk: 文件被分解成固定大小的chunks——由全局唯一的64bit chunk handle标识(在创建文件的时候由master分配)
chunkserver:
- 把chunk以linux文件的形式存储在磁盘上
- 通过chunk handle 和 byte range来读取文件
- 每个chunk备份在不同的chunkserver中(默认三备份)
master:
- 存储文件系统的所有元数据[命名空间(kept persistent by logging mutations to a operation log stored on the masters local disk),控制信息,文件和chunk的映射信息(log)、chunk副本存放信息]
- 系统控制[chunk租约管理、垃圾回收、chunckserver之间chunk的迁移]
- 定期和chunkserver进行心跳[give insturctions and collect state]
client:
- 以库的形式被连接到程序中
- 实现了GFS系统的API函数
- 应用程序通过client完成与master节点和chunkserver的通信,以及对数据的读写操作
- 客户端从master获取元数据,从chunkserver中获取数据
tips: client和chunkserver都不会缓存文件数据
reason:
- 大部分程序以流的方式读取一个巨大的文件,或者工作集太大无法缓存
- chunk是保存在本地文件中,Linux系统的文件系统缓存会把进场访问到的数据放在内存中
读取流程:
- 应用程序指定文件名和字节偏移量
- 客户端把根据chunk的大小,把应用程序指定的文件转换成文件的chunk index;并把文件名和chunk index发送给master节点
- master将相应的chunk handle和副本位置信息返还给客户端
- 客户端用文件名和chunk索引作为key缓存master发送过来的信息
- 客户端发送请求到副本(一般选择最近的),请求包含[chunk handle和字节范围]
操作日志:
- 包含关键元数据的变更历史(元数据唯一持久化的存储记录)
- 这里运用的就是WAL,把相应的日志记录写到硬盘之后,才会响应客户端的操作请求
一致性模型
写 记录追加
串行成功 已定义 已定义
并行成功 一致但未定义 部分不一致
失败 不一致 不一致
已定义:对文件修改之后,各副本是一致的,并且客户端能够看到写入操作的全部内容(隐含了一致性)
一致:无论从哪个副本读取,读到的数据都是一样的
一致未定义:所有客户端看到同样的数据,但是无法读到任何一次写入操作写入的数据
不一致:不同客户端在不同的时间看到不同的数据(也是未定义的)
数据修改操作包括:
写入:把数据写在应用程序指定的文件偏移位置上。
追加:并行执行时,记录追加操作至少可以把数据原子性的追加到文件中一次,偏移位置由GFS返回
GFS追加流程的特色: 链式复制 + 分离数据流与控制流(如下图所示)
链式复制:减少延迟
分离数据流与控制流:前提是每次追加的数据都比较大
系统交互
重要原则:最小化所有操作和Master节点的交互
客户端、Master服务器、chunk服务器之间的交互,以实现数据修改操作、原子的记录追加操作、快照功能
1. 租约机制
GFS的追加操作每次为几十KB到几MB不等,每次追加都请求Master的话会使Master成为系统性能瓶颈,GFS通过lease机制将chunk的写操作授权给chunk,在租约有效期内,对该chunk的写操作都由主chunk负责,减轻master的负载,主chunk对chunk的所有更改操作进行序列化,所有副本都遵从这个序列进行修改操作。
总的来说,对于修改操作,首先由master节点选择的租约的顺序决定,然后由租约中主chunk分配的序列号决定!
上面的追加流程为:
- client询问Master持有租约的chunk server及其副本位置。如果没有chunk server持有租约,master会按照一定的策略将chunk租约授权给其中一台chunk server
- master返回客户端主副本和备副本所在的chunk server的位置信息,client缓存这些信息供以后使用。如果没有故障,客户端以后读写该chunk都不需要再次请求master
- client将需要追加的记录发送到每一个副本(GFS采用的是数据流和控制流分离的方法)
- 副本确认都收到了数据,client发起写请求到主chunk server。这个请求标识了早前推送到所有副本的数据,主chunk为接收到的所有操作分配连续的序列号,保证操作的顺序执行。它以序列号的新婚徐把操作应用到自己本地状态机上,RSM.
- 主chunk把请求传递到所有secondaries,secondaries依照主chunk分配的序列号以相同的顺序执行这些操作
- secondaries发送消息给主副本告知操作完成
- 主chunk回复客户机。任何副本产生的任何错误都会返回给client,client会进行重试等处理
如果应用程序一次写入的数据量很大,或者跨越了多个chunk,client会把它们分成多个写操作。这就可能会被其他client同时进行的操作打断或者覆盖。因此共享文件可能包含来自不同client的数据。但是这些分解后的写入操作是以相同的顺序在chunk上执行的,chunk所有副本都是一致的,这就使得文件处于一致的、但是未定义的状态。
2. snapshot
snapshot操作是对源文件/目录进行snapshot,生成该时刻源文件/目录的一个瞬间状态存放在目标文件/目录中。GFS使用copy on write技术(只增加GFS中chunk的引用技术,表示这个chunk被快照文件引用了,等到客户端修改这个chunk时,才需要在chunkserver中拷贝chunk的数据生成新的chunk,后续的修改操作落到新生成的chunk上)
对某个文件做快照:
- 通过租约机制收回对文件每个chunk的写权限,停止对文件的写服务
- master拷贝文件名等元数据生成一个新的快照文件
- 对执行快照的文件的所有chunk增加引用技术
Master的操作
1. namespace management and locking
逻辑上,GFS的namespace是一个全路径和元数据映射关系的查找表。利用前缀压缩这个表可以高效的存储在内存中。
每个绝对路径的文件名或绝对路径的目录名都有一个关联的读写锁。
2. 副本位置的选择
策略目标:最大化数据可靠性和可用性,最大化网络带宽利用率
3. 创建、重新复制、负载均衡
creation:把chunk副本分布在多个机架之间(考虑硬盘的使用率,限制每台chunk上“最近”的创建操作次数)
re-replication:chunk的有效副本数量少于用户指定复制因数的时候,master节点重新复制它
rebalance:周期性地对副本进行重新负载均衡
4. GC
GC采用延迟删除机制。删除文件后,GFS不要求立即归还物理内存,在元数据中将文件改名为一个隐藏的名字,并且包含一个删除时间戳。
GC一般在服务低峰期执行
master定期检查,发现删除文件超过一段时间:
- 先把文件从内存元数据中删除
- 在chunk server和master的心跳消息中,master回复元数据已经不存在该chunk信息
- chunk server释放chunk副本
容错
1. Master容错
- 操作日志加checkpoint,定期将内存中的数据以checkpoint文件的形式转存储到磁盘中,从而减少日志的回放量
- shadow master 实时热备
2. chunk server容错
- 复制多个副本,确保副本保持一定的个数
- 对存储的数据维持校验和,以block(64KB)为单位,每个block对应32位校验和。
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者李小翠授权发布。