GFS简介

GFS是Google在2003年提出的一个分布式文件存储系统,是Google三剑客之一。GFS主要适用于大文件的顺序读取以及追加写。

GFS由一个master和多个chunck server构成。master负责维护文件和块命名空间、文件到块的映射和每个块副本的位置,以及对块租约、chunck server和块回收和迁移等进行管理。chunck server负责保存块的副本。

日志

master会将对文件和块命名空间以及文件到块的映射的操作以日志的形式保存在磁盘中,用于故障恢复。而每个块副本的位置会在启动后由chunck server上报。只有当日志写入成功后操作才会返回给客户端,GFS会将多个日志合并批量写入来加快速度。

master会通过回放操作日志来进行恢复,而为了避免恢复时间过长,当日志增长到一定程度后master就会设置checkpoint,checkpoint以B树的形式保存,下一次恢复就可以直接从checkpoint开始。checkpoint之前的日志理论上是可以丢弃的,但为了容灾,还是会保留一定量的之前的日志。

之所以使用日志而不是数据库等来保存数据,是因为数据库的写入是磁盘随机写入,而日志追加是磁盘顺序写入,两者的性能相差是很大的。

一致性

  • 对于串行写入来说,GFS的行为是确定的。
  • 对于并行写入来说,GFS是一致的但是结果是未定义的,例如同时写入偏移量为50~80和60~100的位置,那么60~80这一段的结果是未定义的,可能是第一个写入也可能是第二个,但是GFS是能保证所有副本的结果是一致的。
  • 对于追加操作来说,不论是串行还是并行都是确定的。
  • 当发生故障时,所有操作的结果都不能保证一致性。

读操作

读操作即客户端根据文件名以及偏移量读取数据的过程,主要有以下几步:

  1. 发送文件名和偏移量到master
  2. master根据文件名和偏移量查找到对应的块
  3. master根据chunck号查找到对应的chunck server,将chunck号以及server列表返回给客户端
  4. 客户端发送chunck号和偏移量到对应的chunck server,读取数据。客户端会对第三步的结果进行缓存,当再次读取相同chunck就不用请求master了

之所以要发送整个server列表是因为客户端可以选择距离最近的server请求数据,同时如果当一个server不可用时,客户端也可以直接请求其他server。

写操作

当没有主副本时,master找到所有具有最新副本的server,选择一个作为主副本,增加版本号,通知所有副本更新版本号,master将版本号写入磁盘。master选出主副本后,会提供一个租约给主副本,当租约过期后就不是主副本了。

客户端向所有副本发送要写入的数据(客户端发送到最近的副本,最近的副本再链式转发到其他副本),数据此时只是保存在缓存中;当收到所有副本的ACK之后,客户端发送写请求到主副本,主副本将选择一个偏移量并通知所有二级副本进行写入;当主副本收到所有二级副本ACK之后,主副本返回成功给客户端,否则主副本就会返回失败,客户端将进行重试。

写入操作

在写入过程中,就可能会出现某些副本上写入成功,某些写入失败的情况,此时整个追加操作是失败的,客户端会进行重试直到得到一个一致的结果。但是,失败的追加操作在某些副本上的成功写入就会导致数据的重复出现,也就是说GFS实现的语义是最少一次(at least once),当需要精确一次语义时就需要客户端的处理了。

脑裂

当master无法连接主副本时,就需要重新选择一个新的主副本。但是此时旧副本可能是仍然存活的,仅仅是因为网络分区的原因而无法连通;那么就会导致两个主副本的出现,不同的客户端可能会同时在两个主副本上执行写操作,破坏系统的一致性。这个问题就称为脑裂(split brain)。

GFS通过租约来解决脑裂问题,当master选出主副本时,会提供一个租约时间(60s),master和主副本都知道租约的过期时间。当主副本发现租约过期时,就不再处理客户端的请求;master必须等到租约过期之后才能选择一个新的主副本,保证旧副本已经停止工作。

posted @ 2021-02-27 11:40  星見遥  阅读(1587)  评论(0编辑  收藏  举报