【分布式】GFS(Google File System)论文解读

1.背景

1
当时的应用场景和设计需求:

  • 分布式组件的故障时常发生,机器容易发生故障;
  • 文件十分巨大;
  • 大部分文件修改操作只是追加(append)而不是覆盖;
  • 协同设计文件系统和应用可以增加系统的灵活性。

2.系统概览

2.1 架构

2

  • 集群的组成
    GFS集群由一个主服务器(master)和多个块服务器(chunkserver)组成;
    每个文件由文件块(Chunk)组成,文件块有一个块句柄(chunk handle)是它的唯一标识
    • 主服务器
    保存了整个文件系统的元数据(命名空间、访问控制信息、文件到块的映射和每个文件块的位置),并且要负责文件块租借管理(chunk lease)、垃圾回收、文件块迁移,在运行过程中通过心跳包和块服务器交换信息。
    • 块服务器
    保存文件块并向主服务器报告状态。
    • 客户端
    从主服务器获取元数据,然后再从块服务器读写文件数据。

文件以本地文件的形式保存在Chunk Server,不在client或Chunk Server进行缓存。

  • API
    GFS提供了一套API,文件以分层目录的形式组织,用路径名来标识。有创建、删除、打开、关闭、读写文件以及快照和记录追加操作。

  • 各部分的工作关系
    存储文件时,文件会被分成若干个固定大小的chunk(默认64MB)进行存储。每个Chunk会有一个唯一的64位的Handle,Handle会被交给Chunk Server。所有的chunk都存储在Chunk server的本地磁盘中。并且为了保证chunk的可用性,GFS会把每个chunk备份若干存到其他的chunkserver上。
    Master服务器负责维护整个集群的元数据,并且和Chunkserver保持联系,收集它们的状态和发送指令。
    客户端和GFS集群通信时,从Master服务器获取元数据(并且客户端会在一定时间内缓存得到的元数据),但实际的文件访问是与chunkserver进行的,这也避免了单个Master可能造成的数据传输瓶颈。

设计思想:文件分块、数据映射、冗余备份、控制与数据分离

2.2 文件分块

分块时将文件分为较大的块。

  • 为什么要分成较大块?
    1.减少了存储在主服务器上的元数据的大小
    2.减少了客户端向主服务器访问的次数,降低了主服务器的负载;
    3.对单个文件的操作增加,使客户端和块服务器的交互减少,降低了网络负载;
    4.文件分块还有个好处是可以并行操作
  • 问题:一些小文件存在大文件块中,可能会导致频繁对某个文件块写入,导致某几台块服务器的负载过大,解决的办法是增加小文件的副本数量

2.3 元数据

  • 元数据的存储
    GFS的集群所有的元数据都保存在Master服务器的内存中。
    缺点:Master的内存大小限制着存储的元数据大小,从而限制着这个集群能够拥有的chunk数量。

  • 元数据主要包含三类信息:
    • 文件与chunk的NameSpace
    • 文件与chunk的映射关系
    • 每个chunk replica的位置

  • 元数据的可用性保证
    为保证元数据的可用性,Master在对元数据做任何操作之前都会先写日志再进行实际操作
    Chunk Replica的位置不会持久化到日志中,它是在Master启动时询问每个chunkserver获取的。(简化了日志持久化的工作,避免了Master与chunkserver的数据同步成本(副本数据发生变化,可能位置会变))。

2.4 数据一致性

3

  • 文件被修改后可能会有三种状态:不一致(inconsistent),一致(consistent),确定(defined,所有客户端都能看到上一次修改的所有完整内容,且这部分文件是一致的)。
    上表展示了修改后文件的状态,它取决于修改的类型(写入和追加)是否成功

  • GFS支持的文件数据修改有两种:
    1.指定偏移值的数据写入(Write);
    2.数据追加(Record Append);
    对于Write,GFS并没有对写入操作提供太多的一致性保证,可能会多个并发的客户端写到了同一块区域,导致覆盖了数据,进入到不确定的状态(undefined)。
    对于Record Append,GFS保证了在并发的情况下数据追加也是原子的且至少一次的。操作完成后,GFS会返回写入的实际偏移值给客户端,这个偏移值代表了所写入数据在文件区域中的具体的起始位置。

  • 由于数据追加操作是 at least once 的,GFS 有可能会在文件中写入填充(padding)或是重复数据,但出现的概率不高。

  • 在读取数据时,为了避免读入填充数据或是损坏的数据,数据在写入前往往会放入一些如校验和等元信息以用于验证其可用性,如此一来 GFS 的客户端 library 便可以在读取时自动跳过填充和损坏的数据。不过,鉴于数据追加操作的 at lease once 特性,客户端仍有可能读入重复的数据,此时只能由上层应用通过鉴别记录的唯一 ID 等信息来过滤重复数据了。

3.GFS集群常见的操作

3.1 Master NameSpace管理

  • NameSpace的管理
    NameSpace存在于Master服务器的内存中,它不是根据目录的分层结构进行管理的,它是利用文件完整路径名和文件元数据映射表来管理数据,并且会在路径名上用前缀压缩减少内存占用。

  • 读写锁
    为满足客户端的并发要求,Master服务器会给NameSpace中的每个文件和目录都分配一个读写锁。
    由于大量的读写锁可能占用过多内存,所以这些锁是在需要时才创建,不用时销毁。

  • 访问NameSpace
    所有Master操作执行前都需先获取一系列锁:如/d1/d2/…/dn/leaf 时,Master 会需要先获取从 /d1、/d1/d2 到 /d1/d2/…/dn 的读锁,然后再根据操作的类型获取 /d1/d2/…/dn/lead 的读锁或写锁 。
    获取父目录的读锁是为了避免父目录在此次操作执行的过程中被重命名或删除
    锁的获取操作会按照一个相同的顺序进行,以避免发生死锁。(锁首先按照NameSpace树的层级排列,同层级则以路径名字典序排列)

3.2 读取文件

  • 客户端从GFS集群读取文件的流程:
    1.根据文件名和读取位置偏移值,客户端可以利用固定的chunk大小来算出这个位置在该文件的哪个chunk中;
    2.客户端向Master服务器发送请求(文件名+chunk索引值);
    3.Master响应返回chunk的handle和所有的Replica所在的位置,客户端会缓存这些数据;
    4.客户端选取一个Replica并访问Chunk Server,并且会指定handle和要访问的范围。

3.3 Chunk Lease

  • 租约的作用
    选取中心节点的根据。在Chunk Server中选择一个赋予Chunk Lease,被称为Primary。那么在这个租约期间所有的操作序列都是由这个Primary安排的,保证了操作的一致性。若没有这个Lease可能出现一个Primary宕机,又有一个Primary,导致出现了两个安排顺序就会出现问题,而有了Lease后,一个Lease没有结束或失效之前,不会有新的Primary,保证了操作序列的一致性。
    租约默认超时是60s。

  • Primary
    GFS为处理不同的并发修改,会把Chunk Lease交给一个Replica,它就成为了Primary。
    Primary会负责对要修改Chunk的操作安排一个执行顺序,然后其他的Replica按照相同的顺序执行这些操作。

3.4 文件写入

4

  • 流程:
    1.客户端询问Master,哪个chunk server持有对应的chunk的Lease;
    2.Master向客户端返回Primary和其他Replica的位置;
    3.客户端将要写入的数据推送到所有的Replica上,并且Chunk Server会把这些数据保存在缓冲区以待使用;
    4.所有的Replica收到数据后,客户端发送写请求给Primary。Primary为来自各个客户端的修改操作安排连续的执行序列号,并按照顺序执行操作其本地存储的数据;
    5.Primary将写请求转发给Secondary Replica,其他Replica按照相同的操作顺序进行数据修改;
    6.Secondary Replica响应Primary,示意已完成操作;
    7.Primary响应客户端,若有错误,返回过程中发生的错误。

可以清楚地看到数据流和控制流是分开的。客户端先向Chunk Server提交数据,再将写请求发到Primary。
由上图传输数据的线路可以看出,客户端实际会先把数据传到离自己最近(通过IP来判断的)的Replica,然后Replica再依次找最近的Replica传递。

3.5 文件追加

  • 流程:
    1.客户端将数据推送到每个Replica,然后将请求发往Primary;
    2.Primary首先判断将数据追加到chunk后会不会超过上限,

  • 若会超过则Primary会为该块写入填充至其大小达到上限,并通知其他Replica执行同样的操作,然后响应客户端,让它在下一chunk重试;
    若不会超过上限,即能够放入当前块,则Primary把数据追加到自己的Replica中,并返回偏移值,然后通知其他Replica将数据写入到该偏移值位置,最后相应客户端。

  • 当追加操作在部分Replica上失败时,Primary会响应客户端,并通知此次操作已经失败,客户端会重试操作。但是有些Replica已经写入了,所以会导致这部分Replica出现重复数据,由于它是at least once的操作,没有保证每个Replica完全一致,所以会出现的情况是,新的操作可能使一些Replica上出现重复数据,或者这些数据被分配到了新的块上。

3.6 文件快照

  • 快照操作可以为指定的文件或目录创建一个副本。
  • 快照操作采用了写时复制(Copy on Write)的思想:
    1.Master收到快照请求后,首先撤回这些Chunk的Lease,这样可以防止快照期间这些Chunk收到更改;
    2.当Chunk Lease撤回或失效后,Master会先写入日志(因为要增加快照数据的元数据,修改元数据就要写日志),然后对NameSpace进行复制(在内存中对设计的file和chunk的元数据拷贝),产生的新记录指向原来的Chunk(这里是对元数据进行拷贝,而不是拷贝实际的数据,然后使用指针指向同一份原始数据);
    3.当快照结束后,要对某个文件做修改,再拷贝该文件设计的Chunk数据,然后进行修改。

3.7 Replica管理

  • 目标:最大化数据的可用性;最大化网络带宽的利用率。
    Relica需要被放在不同的机器上,不同的机架上。这样不同的客户端对同一个Chunk进行读取就可以利用不同的机架的出口带宽。

Replica的生命周期转换只有两个:创建删除

  • 创建
    Replica的创建可能源于三种事件:创建Chunk、为Chunk重备份、Replica均衡。
    Master创建新的Chunk时,首先会考虑将新的Replica放在哪里,有如下因素需考虑:
    1.Master倾向于把新的Replica放在磁盘使用率较低的Chunk Server上;
    2.Master倾向于确保每个Chunk Server上“较新”的Replica不会太多,因为新Chunk的创建意味着会有大量的写入,若一个Chunk Server中新的Chunk Replica太多,写操作压力就太大;
    3.Master倾向把Replica放在不同的机架上。

  • Chunk重备份
    若某个Chunk的Replica数量低于用户指定的阈值,Master就会对该Chunk进行重备份。
    Master会首先为每个需要重备份的Chunk安排优先级,考虑因素如下:
    1.Chunk的Replica数和用户指定的Replica阈值的差值;
    2.优先为未删除的文件的Chunk进行重备份;
    3.Master会提高正在阻塞用户操作的Chunk的优先级。

  • Master会选取优先级最高的Chunk,让指定让若干Chunk Server直接从现有的Replica上复制数据。
    Master指定哪些Chunk Server会考虑上述创建的因素。
    为了减少重备份对用户使用的影响,Master会限制整个集群正在进行复制操作的数量,同时Chunk Server也会限制复制操作所使用的带宽。

  • Replica均衡
    Master会周期性地检查每个Chunk当前在集群的分布情况,并会在必要时迁移Replica以均衡各节点的磁盘利用率负载
    Master倾向选择移除磁盘占用率较高的Chunk Server上的Replica,新Replica的位置选取策略同样考虑创建的那几个因素。

3.8 删除文件

  • 删除的两种情况
    1.当用户对某个文件删除时,GFS不会立刻删除,而是在文件和Chunk都采用Lazy地对数据进行移除,下面详述。
    2.若用户在此指定GFS删除该文件,则NameSpace层会移除该文件。

  • Lazy删除
    当用户删除某个文件,GFS会将NameSpace上的文件记录加上一个删除的时间戳并重命名隐藏。在Master周期扫描NameSpace时,它根据时间戳可以判断出那些“删除”时间较长的文件,这时候才真正的从NameSpace上移除。但是,在此期间客户端依然可以使用隐藏名称读取文件,也可以再次重命名撤销删除,这也是防止误删的一种操作。
    当NameSpace上的记录删除后,Master在元数据的文件与Chunk之间的映射中,对应的Chunk的引用计数会自动减1。Master周期性地扫描元数据时,发现引用计数为0的Chunk时,就会从内存中移除与这些Chunk有关的元数据。
    ChunkServer和Master周期性心跳通信中,CS会汇报持有的Chunk Replica,Master会告知CS哪些Chunk已经不存在于元数据中,CS就会自行删除对应的Replica。

  • Lazy删除机制的优势
    1.对于大规模的分布式系统来说,Chunk Server自行删除Replica的操作更为可靠。因为Master Server发送的创建操作可能是只有部分成功,可能还有Master不知道的Replica,那么发送的删除操作也可能只有部分成功,所以让Master来主动请求删除CS上的Chunk可能会出现问题。因此,将任务交给有对应的Chunk的CS自行处理是一种更为统一可靠的办法;
    2.删除机制将存储回收和Master周期扫描合并在一起,使得这些操作可以进行批处理,以减少资源损耗;此外还可以让Master在相对空闲的时候完成这些操作;
    3.避免用户误操作。

此外,GFS可让用户为NameSpace的不同区域指定不同的备份和删除策略,如限制GFS不对某个目录下的文件进行备份。

4.高可用性(容错机制)

4.1 Master

  • 写日志
    Master在实际执行请求之前,会先写日志,以此将集群的元数据持久化。在完成日志写出(写入本地和远端备份的持久化存储中)之前,Master不会对客户端的请求进行响应。

  • CheckPoint
    为保证Master能够快速完成恢复,Master会在日志达到一定的大小后为自身的当前状态创建CheckPoint,并删除CheckPoint之前的日志。在重启时,从最近一次创建的CheckPoint开始恢复。
    Checkpoint 文件的内容会以 B 树的形式进行组织,且在被映射到内存后便能够在不做其他额外的解析操作的情况下检索其所存储的 Namespace,这便进一步减少了 Master 恢复所需的时间。

  • Master选举
    论文中没有提及具体怎么选举,但是查阅资料是说使用了Chubby进行选举。

  • Shadow Master
    集群中会提供只有只读功能的Shadow Master,主要是为了分担Master处理读操作的压力。Shadow Master会同步Master的状态变更,它会读取Master操作日志的某个备份来让自己的状态与Master同步。同时,它也会在启动时像Master一样询问每个Chunk Server获得它们持有的Chunk Replica信息,并监视它们的状态。
    所以,在Master失效后,其实GFS仍可通过Shadow Master获取读功能。

4.2 Chunk Server

  • 首先一个情况是Chunk Server失效的几率比Master大得多。Master会为每个Chunk维持一个版本号,当CS失效的情况发生,可能其内部的所有Chunk都已经是旧数据了,那么就可以通过这个版本号知道恢复的CS中的Chunk是否是旧数据。这样就能够区分新旧Replica。
  • 当Mater将Chunk Lease分配给一个Chunk Server时,Master便会提高Chunk的版本号,并通知其他最新的Replica更新自己的版本号。
  • Chunk Server重启时,会向Master汇报自己持有的Replica和版本号,若版本号过低,Master会认为这个Replica失效,过期的Replica会在下次的Replica回收中被移除。此外,Master向客户端返回Replica位置信息时也会返回Chunk的版本号,这样客户端就不会读到旧数据。

4.3 数据完整性

  • 校验和
    每个Chunk Server以校验和(checksum)的形式来检测自己保存的数据是否有损坏。在有损坏的情况下,Chunk Server利用其它的Replica来恢复数据。

  • 首先,Chunk Server会将每个Chunk Replica切分成若干个64KB大小的块,并为每个块计算32位校验和。这些校验和会被保存在Chunk Server的内存中,每次修改前都会先写日志来保证可用性。
    当CS收到读请求时,CS首先利用校验和检查所需读取的数据是否有损坏。若发现损坏,CS会为请求发送者发送一个错误,并向Master告知数据损坏时间。接到错误后,请求发送者会选择另一个CS重新发送请求,而Master则会利用另一个CS位该Chunk进行重备份。新的Replica创建完成后,Master会通知该CS删除这个损坏的Replica。

  • 当追加数据时,对Chunk尾部的校验和进行增量式更新,增量更新后的校验和依然会无法与实际的数据相匹配,在下一次读取时依然能够检测到数据的损坏。
    在进行数据写入操作时,Chunk Server 必须读取并校验包含写入范围起始点和结束点的校验和块,然后进行写入,最后再重新计算校验和。

  • 此外,在空闲时CS会周期性扫描检验不活跃的Chunk Replica,以确保这些数据的损坏也能在不被读取的情况下检测到。

结语

  • 在强一致性面前,GFS 选择了更高的吞吐性能以及自身架构的简洁。高性能与强一致性之间的矛盾是分布式系统领域经久不衰的话题,源于它们通常是不可兼得的。此外,为了实现理想的一致性,系统也可能面临来自并发操作、机器失效、网络隔离等问题所带来的挑战。

参考

[1] 经典分布式论文阅读:GFS
[2] Google File System 论文详析
[3] Ghemawat, Sanjay, Howard Gobioff, and Shun-Tak Leung. “The Google file system.” (2003).

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kaimar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值