分布式文件系统GFS
0.简介
文件系统应该具有的接口:
-
基本接口:创建(Create)、删除(Delete)、打开(Open)、关闭(Close)、读取(Read)、写入(Write)
对于打开和关闭我们可以把它理解成读取与写入的前置和后置动作,在GFS中不必太多关注它。 -
拓展的接口:生成快照(Snapshot)、修改(Update)、追加(Append)。GFS不支持修改,这样的设计原因就是追加操作更易保证一致性。
1.GFS整体架构
FS中有三种节点:GFS client,GFS master,GFS chunkserver。
- GFS client:向应用提供接口,与应用交互。
- GFS master:维护元数据,统一管理chunk位置与租约。元数据:文件位置等信息
- GFS chunkserver:存储数据的节点,每个chunkserver中有很多包含数据的chunk
GFS整体架构图:

GFS整体架构描述:
2.GFS的存储设计:chunk
chunk:考虑到文件可能非常大,并且大小不均。GFS没有选择直接以文件为单位进行存储,而是把文件分为一个个chunk来存储。GFS把每个chunk设为64MB。
64MB这个值是偏大的。为什么GFS会这么设计呢?:
-
使用GFS的系统需要存储的文件都偏大(几GB),所以较大的chunk可以有效减少系统内部的寻址和交互次数,即找一个chunk是需要时间的,较大的chunk可以减少查找次数。
-
大的chunk意味着client可能在一个chunk上执行多次操作,这可以复用TCP连接,节省网络开销;
-
更大的chunk可以减少chunk数量,从而节省元数据存储开销,相当于节省了系统内最珍贵的内存资源,这对GFS来讲是非常关键的。
3.GFS的master设计
GFS中将管理元数据节点设计为一个单点,元数据的服务尽可能简单,来保证单个中心节点也能支持整个系统的服务。GFS设计了单个master节点,用来存储整个文件系统的三类元数据:
-
所有文件和chunk的namespace【持久化】,即所有文件的文件名和每个chunk的编号。
-
文件到chunk的映射【持久化】,即一个文件名到chunk编号的对应关系。
-
每个chunk的位置【不持久化】,即每个chunk编号到具体chunkserver中位置的映射。
不做持久化的原因:因为master在重启的时候,可以从各个chunkserver处收集chunk的位置信息,并且master宕机不经常发生,所以不需要将此信息持久化在master中。
GFS读取一个文件的基本逻辑:文件名→获取文件对应的所有chunk名→获取所有chunk的位置→依次到对应的chunkserver中读取chunk。
GFS采用了一系列措施来确保master不会成为整个系统的瓶颈,这些措施主要体现为减轻master的压力:
- GFS所有的数据流都不经过master,而是直接由client和chunkserver交互。GFS把控制流和数据流分离,只有控制流才会经过master。
- GFS的client会缓存master中的元数据,在大部分情况下,都无需访问master;
- GFS还希望可以把所有的元数据都装在master的内存中,从而让元数据服务特别的高效。
- 为了避免master的内存成为系统的瓶颈,从而让元数据服务特别的高效。所以GFS采用了一些手段来节省master的内存,包括增大chunk的大小以节省chunk的数量、对元数据进行定制化的压缩等。
4.GFS的高可用设计
- GFS借鉴了主备的思想:高可用问题现在比较通用的做法是共识算法,比如Paxos和Raft。但GFS诞生的时候,共识算法不像现在这么成熟,所以GFS借鉴了主备的思想,为系统的元数据和文件数据都单独设计了高可用方案。
- 自动切换主备:因为Google的文件量很大,所以GFS的机器总数可能非常的多,从而个别机器宕机的发生会十分频繁。所以面对节点宕机之类的小问题,GFS应能自动解决,即自动切换主备
系统的元数据和文件数据都单独设计了高可用方案,下面进行分别介绍。
4.1 master的高可用设计:
master的高可用设计:
- shadow master:GFS在正在使用的master称为primary master。在primary master之外,GFS还维持一个shadow master作为备份。
- 日志:Master在正常运行时,对元数据做的所有修改操作,都要先记录日志(WAL),再真正去修改内存中的元数据。这类日志,我们称之为WAL,write ahead log。
- primary master会实时向shadow master同步WAL,只有shadow master同步日志完成,元数据修改操作才算成功。
WAL的两个优势:
-
可以以顺序的日志落盘代替乱序的数据落盘,速度更快。在GFS中,就是可以让元数据的修改不用等待实时落盘,只要日志写入了就可以认为元数据落盘成功了。因为这样哪怕宕机导致内存中的数据丢失,也可以通过回放日志来恢复。
-
我们可以同步WAL代替真正的数据块。这样主机同步更便捷可控,备机回放逻辑也更简单。
新增元数据的过程:生成新增元数据的日志并写入本地磁盘 → 把WAL传输给shadow master → 得到反馈后再正式修改primary master的内存。
宕机后的自动切换:如果master宕机,会通过Google的Chubby(本质上是共识算法)来识别并切换到shadowmaster,这个切换是秒级的。
4.2 chunk的高可用设计:文件是被拆为一个个chunk来进行存储的,每个chunk都有三个副本。
GFS保证chunk高可用性的思路:
- 在GFS中,对一个chunk的每次写入,必须确保在三个副本中的写入都完成,才视为写入完成 →
- 一个chunk的所有副本都会具有完整的数据。如果一个chunkserver宕机,它上面的所有chunk都有另外两个副本依旧可以保存这个chunk的数据 →
- 如果这个宕机的副本在一段时间之后还没有恢复,那么master就可以在另一个chunkserver重建一个副本,从而始终把chunk的副本数目维持在3个(可以设置)。
保持chunk具有多个副本(高可用)的最优解决思路是使用共识算法,而不是使用上述方法。这是由于GFS年代共识算法并不成熟。
chunk的校验和:GFS维持每个chunk的校验和,读取时可以通过校验和进行数据的校验。如果校验和不匹配,chunkserver会反馈给master处理,master会选择其他副本进行读取,并重建此chunk副本。
租约(Lease)机制:为了减少对master的压力,GFS采用了一种租约(Lease)机制,把文件的读写权限下放给某一个chunk副本。Master可以把租约授权给某个chunk副本,我们把这个chunk副本称为primary,在租约生效的一段时间内,对这个chunk的写操作直接由这个副本负责,租约的有效期一般为60秒。
【注】租约的主备只决定控制流走向,不影响数据流。
【问题】租约(Lease)机制完全没看懂
什么时候会创建chunk副本:GFS中有三种情况需要master发起创建chunk副本,分别是新chunk创建、chunk副本复制(re-replication)和负载均衡(rebalancing)。
- 副本复制则是指因为某些原因,比如一个副本所在的chunkserver宕机,导致chunk副本数小于预期值(一般为3)后,新增一个chunk副本;
- 负载均衡则发生在master定期对chunkserver的监测,如果发现某个chunkserver的负载过高,就会执行负载均衡操作,把chunk副本搬到另外的chunkserver上。当然,这里的“搬迁”操作,实际上就是新建chunk和删除原chunk的操作。
创建chunk副本时,master对副本位置的选择策略要遵循以下三点:
- 新副本所在的chunkserver的资源利用率较低;
- 新副本所在的chunkserver最近创建的chunk副本不多。这里是为了防止某个chunkserver瞬间增加大量副本,成为热点;
- chunk的其他副本不能在同一机架。这里是为了保证机架或机房级别的高可用
5.GFS的读写流程
GFS
会先收到数据,然后等待写入命令后再进行写入。
这里我理解写入流程是传输数据和写入数据两部分,传输数据是数据流采用流水线,写入数据是由主chunkserver控制,是控制流!