GFS [Q&A]

date
Jul 13, 2022
slug
gfs-qa
status
Published
tags
GFS
Q&A
Distributed
summary
Google File System
type
Post

Q1. GFS 是什么?

一个可拓展的文件系统,用于大型分布式数据密集型应用。它可以运行在廉价的商用硬件上,提供容错机制,而且能为大量客户端提供高聚合的性能。
设计前提:
  1. 该文件系统是由许多廉价的机器构建的,这些集群经常出错
  1. 该文件系统储存少量的大文件,通常是 100MB 往上,XGB 的文件大小是常见的。该文件系统能高效的处理这些大文件,也要对小文件支持,但不需要对小文件进行优化
  1. 该文件系统工作主要负载:大的流式读取、小的随机读取、大量的顺序写入(追加数据到文件)
  1. 该文件系统在多客户端并发追加写入同一个文件时,提供良好的语义
  1. 延时不重要,网络带宽正常比较重要

Q2. GFS 的架构?

GFS 集群由一个 master 、多个 chunkserver 和 多个 client 组成。储存在集群中的文件被分成大小固定的 chunk。
master 非常重要,它维持文件系统所有的 metadata,这些 metadata 包括命名空间、访问控制信息、文件到 chunk 的映射和当前所有 chunk 的位置信息。而且 master 还控制系统范围的活动,比如 lease 管理,孤立 chunk 的垃圾回收和在不同 chunkserver 之间进行的迁移。
但是单 master 的架构可能在后续成为系统的瓶颈。
notion image
master 起到一个“领导”的作用。client 询问 master 应该访问哪个 chunkserver,master 返回后,client 缓存一会信息,在之后的一段时间内就不需要再与 master 进行通信,而是直接与 chunkserver 进行操作。

Q3. client 和 chunkserver 需要缓存文件数据吗?

client 缓存文件数据基本没什么好处,大多数应用程序需要处理许多巨大的文件,内存难以将这些数据缓存下来。而且 client 缓存了也可能会出现缓存不一致性的问题。
chunk 在 chunkserver 上作为本地文件储存,Linux 的缓存已经能让 chunkserver 频繁地在内存中访问数据。所以 chunkserver 也不需要缓存文件数据。
(client 和 chunkserver 缓存文件数据,脱裤子放屁——多此一举)

Q4. chunk 的大小?

一般是 64MB,这比传统文件系统的块要大得多。chunk 大小偏大有以下几种好处:
第一,减少 client 与 master 交互的需求。第二,因为 chunk 大了,后续的许多操作可能都在这个 chunk 上进行,减少了 client 与 chunkserver 保持 TCP 连接的网络开销。第三,减少了储存在 master 上的 metadata 大小。
但是也有一些坏处,如果一个文件只有一个 chunk,那么这个 chunk 可能会成为一个“热点”。但“热点”在 GFS 并不是一个问题,因为 GFS 许多应用程序都是按顺序读取大型的、多 chunk 的文件。如果非要解决“热点”问题,可以让 client 之间互相可读,也可以提高复制因子,也可以错峰读取这些“热点” chunk。

Q5. master 的 metadata ?(metadata)

master 的 metadata,储存 chunk 的命名空间、文件到 chunk 的映射和每一个 chunk 副本的位置。
master 将 metadata 储存在内存中,因此,master 可以高效简单地在后台定期地扫描它的整个状态。但是,将 metadata 储存在内存中有一个潜在的问题:文件系统中 chunk 的数量受到 master 的内存大小的限制。不过这种限制在实践中不是一个严重的问题,每一个 64MB 大小的 chunk, metadata 比 64B 还小
master 不会持久记录哪个 chunkserver 具有某个 chunk 的副本。master 在启动时就会简单地轮询 chunkserver 获取这些信息。因为后续 chunk 的复制和 chunkserver 状态的监听都会通过 master 定期发送的心跳包,master 能保证这些信息是最新的。
上述 metadata 的前两种由操作日志(operation log)维护,操作日志非常重要,是 metadata 中唯一持久化的记录。GFS 在多个远程机器上复制它,在相应的 log 记录写入本地和远程的存储后,master 才会回复客户端的操作。master 可以 replay 这些操作日志恢复它的文件系统状态。
为了防止操作日志过大,还涉及了一个检查点机制:在操作日志过大时,通过恢复旧检查点的状态,创建新检查点,达到减少操作日志大小的效果。

Q6. GFS 的一致性模型?

notion image
  • consistent 和 defined 的定义
如果任意 client 从任意副本读取,总是看到相同的数据,则该文件区域是 consistent 的。
如果 client 看到 mutation 完整写入内容,且该文件区域是 consistent 的,则该区域是 defined 的。
serial success write:理想的写入
concurrent success write:所有 client 看到的数据是相同的,但是并发导致写入的内容混一起了,即 consistent 但 undefined。
success record append:它会原子地 append 数据至少一次。GFS 可能会在那一段写入的文件区域插入了空白或是写入了多个相同记录。在这些区域内,有些是 inconsistent 的,但是整体是 defined 的。(更多 record append 的信息看 3.3)
failure operation:不同的 client 可能在不同时间看到的数据不一致,是 inconsistent 。

Q7. lease 和 mutation 有什么关系?

chunk 的内容或 metadata 的一次改变,可视为一次 mutation。每一个 mutation 会在所有 chunk 的副本上执行。
master 为了让所有 mutation 执行的顺序一致,首先在拥有这些 chunk 的副本中选择一个,授予 chunk lease 作为 primary chunk。primary chunk 执行 mutation 的顺序,所有 secondary chunk 的副本都要和它一样。
一个 lease 的初始时间为 60s,如果 primary 在 lease 未失效前失联了,master 必须要等到 lease 失效后才能赋予新的 lease,否则会出现“脑裂”现象。

Q8. GFS 一次 write 的过程是怎么样的?

notion image
首先,client 向 master 询问 primary 是哪个?该 chunk 的其他副本在哪?如果 master 当前 chunk 的副本都没有被授予 lease,则 master 选择一个 chunk 作为 primary 之后再返回。client 获得返回的信息后,缓存这些信息一会,直到当前的 primary lease 失效。
client 拥有了所有 chunk 副本的位置,现在将写入的数据推送至所有拥有该 chunk 副本的 chunkserver(secondary)。secondary 会将这些数据缓存一会,直到数据被使用或是过旧。
在所有 secondary 收到数据后,client 才会发送写入请求给 primary。primary 选择一个 mutation 的顺序执行,接着把这个顺序推送给其他的 secondary。这样所有的 chunk 副本上的 mutation 顺序就一致了。
所有 secondary 执行完后,回复给 primary,代表所有操作已经完成,此时 primary 也可以响应 client 的写入请求。如果 secondary 其中有一个错误,primary 也会返回给 client。
如果 primary 响应 client 请求的结果是错误的,就让 client 继续重试上面的几步操作。

Q9. GFS 数据流向是怎样的?

数据在 chunkserver 中以管道的方式被线性地推送。每一个机器推送数据至在网络拓扑图中距离它最近的且没有收到过该数据的一台机器。

Q10. Record Appends 是怎样的一种写入方式?

并发 write 不是线性的,写入相同的区域会导致多个写入混在一起。而 record append 不一样,client 只需要给定写入的数据,record append 会至少原子地写入一次,写入的偏移量(offset)是 GFS 选择的,写入成功后会返回给 client。
record append 和 write 的流程差不多,需要一些额外的逻辑处理:如果当前 append 这个 chunk 不够容量了,则 GFS 自动将这个块填满,告诉 client 再发送一次 append 请求,写入别的 chunk。如果当前 append 这个 chunk 足够容量,则 GFS 正常写入,primary 告知其他 secondary 此次写入的偏移量。
GFS 不能保证所有的副本都逐字节相等,但是如果成功的 record append 之后,GFS 保证写入的偏移量是相等的。

Q11. GFS 的快照机制(snapshot)?

快照机制能快速地创建一个文件或者目录的拷贝,尽量减少对正在执行 mutation 的影响。一般用来使用创建一个大数据集的副本分支或是创建一个当前状态的检查点,以便后续能迅速地回滚至这个状态。
当 master 收到 snapshot 请求后,它将回收有关这个 snapshot 有关文件的 chunk 的 lease。之后便将此次操作写入操作日志,通过复制源文件或目录树的 metadata 应用该操作。新创建的快照文件指向与源文件相同的 chunk。后续 client 请求该文件或目录时,master 会注意到该 chunk C 的引用超过了 1,则让所有 chunk C 包括其副本都创建一个相同的 chunk C’。master 直接将该 chunk C’ 返回给 client,client 认为自己读的是 chunk C,但实际上已经读的是创建快照过后的 chunk C’ 了。

Q12. GFS master 的锁?

举个栗子:当操作 /d1/d2/…/dn/leaf 时
获取 /d1、/d1/d2、….、/d1/d2/…/dn,的 read 锁。
获取 /d1/d2/…/dn/leaf 的 write 锁。
对父文件加 read 锁足够了,可以保证在操作的过程中父文件不会被删除,也运行并发的操作一个文件夹下不同的文件。

Q13. GFS 的chunk 和其副本存放策略?

两个目的:最大限度地提高数据的可靠性和可用性,最大限度地提高网络带宽的利用率。
当 master 创建了一个新的 chunk 时。
(1)我们想要新的副本在磁盘空闲率较高的 chunkserver 上存储。(2)限制一下每个 chunkserver 一段时间内能创建的副本数,否则后续许多请求都会走向这个连续创建过多 chunk 的 chunkserver。(3)尽可能的将 chunk 跨机架存储,以免有清洁工踢断网线。
默认的复制因子是 3,如果用户修改了复制因子或是因为 chunkserver 失联导致某些 chunk 数目过低,master 会启动复制流程,将这些不满足数目的 chunk 复制。
定期地, master 也会平衡一下 GFS 集群内的存储空间,如果某个 chunkserver 负载过大,GFS 会选择性地移动上面的 chunk 至负载较小的 chunkserver。

Q14. GFS 的垃圾回收策略?

当应用进行删除操作时,master 日志会立即记录该操作,但不会立即回收该文件占用的资源,仅仅只是将该文件重新命名隐藏起来,这个操作会包含删除的时间戳。master 会定期地扫描文件系统的命名空间,如果有某个像上面那样的隐藏文件存在超过了三天,master 才会真正的删除它。(在三天冷静期内,还能通过给定特殊的名字去访问它或是重命名它使之成为一个正常的文件)
在块命名空间的类似常规扫描中,master 会识别出孤立的 chunk(没有引用的 chunk,即无法访问),然后删除这些 chunk 的 metadata。

Q15. 如何检测陈旧的 chunk 副本?

如果一个 chunk 的 chunkserver 出错或是少执行了一些 mutation,master 可以通过给 chunk 维护的 chunk version number 识别出来。
当一个 chunk 获得了 lease,chunk 会自动增加它的 version number,然后通知其他保持最新的副本。master 和这些副本都在进行 write 或 record append 之前将这个 version number 持久化。简单的对比一下就可以知道哪个 chunk 是旧的。
如果 master 发现一个 version number 比自己的维护的 version number 要高,则 master 自己认为授予 lease 的时候出错了,接着将较高的 version number 设为当前的 version number。
作为一种防护措施,master 响应 client 请求时也带上 chunk version number,让 client 读的时候永远访问的是最新的数据。

Q16. GFS 的高可用性怎么实现的?

主要是两种简单且高效的策略:快恢复和复制
每一个 master 和 chunkserver,不管怎么被中断时,它们都会在一段时间内快速启动,然后恢复它们的状态。每一个 chunk 都会被复制在不同机架的多个机器上。
master 的状态也被复制在多个机器上。一个 mutation 被认为 committed 仅当 master 的 log 写入了本地磁盘或远程副本上。当 master 出错时,它能立即重启。如果 master 因为机器或磁盘的损坏,无法启动,GFS 外部的基础架构监控会启动新的 master 进程,通过改变 DNS 别名,client 能与重新分配在另一台机器上的 master 进行通信。
当最初的 master 挂掉时,影子 master 除了只提供对文件系统的只读访问服务,其他功能与 master 相似,例如发送心跳包,确认 chunkserver 状态等。

Q17. GFS 怎么校验数据完整性?

每一个 chunkserver 都使用校验和检验自己的数据是否损坏。我们可以通过其他 chunkserver 上的副本来恢复一个损坏的 chunk,但是通过比较其他 chunkserver 上的校验和是否损坏很不实用。每个 chunkserver 必须维护独立地自己副本的 chunkserer,并独自校验它们的完整性。
每一个chunk 64MB,对应校验和大小是 32 bit。他就像其它 metadata 一样储存在内存中,并和 log 一样进行持久化。
每一次进行读取时, chunkserver 校验与读取区域相同范围的数据的校验和。如果出错了,chunkserver 会返回一个错误,然后报告给 master 说我这个 chunk 不匹配。master 就从其它副本复制该 chunk 给它,然后告知 chunkserver 删除那个损坏的 chunk。
在空闲的时期,chunkserver 可以扫描并且验证活动度较低的 chunk 的校验和,以便能发现这些很少不用但是损毁的 chunk,进行垃圾回收及时腾出空间。

Q18. GFS 的诊断日志能干什么?

GFS 服务会生成包含重要事件日志和全部 RPC 请求的诊断日志,这些细致的日志能在针对一些无法复现的问题、调试和性能分析时,能极大地帮助我们而不需要花费多大的代价。
 

© shallrise 2023