MIT 6.824 分布式系统课程第三课:GFS

Posted by 启示录 Blog on March 14, 2020

笔记:GFS

视频:Lecture 3: GFS

论文地址:The Google File System

课程概要

主要讨论Google第一代文件系统GFS。

正文

这篇论文的价值?

  • 分布式存储系统是分布式系统的关键

    接口和语义化应该如何定义、内部是如何工作的

  • GFS 涵盖的内容在6.824中有很多相关知识的涉及

    并行性能、容错、复制、一致性

  • 这篇论文属于分布式系统的标志性论文之一,从应用程序到网络。并且得到工业界的验证

构建分布式存储的难点在哪儿?

  • 高性能:跨服务器的数据文件分片获取
  • 多服务器:标志着更多的故障
  • 容错:多副本
  • 复制:潜在的不一致
  • 一致性:导致性能降低

我们究竟想要如何样的一致性?

  • 理想模型:所有的操作就像单机一样
  • 服务端使用磁盘存储
  • 服务端一次只执行一次客户端操作(即使并发)
  • 读始终是最新的写入结果(即使服务器重启或崩溃)

因此,假设有几个场景c1和c2是并发写。在写完成后,发起C3和C4读取。那么会得到什么结果?

答案:可能是1或者是2,但是两个读都应该是相同的值返回(强一致性模型),但是单机无法做到好的容错。在现实分布式系统中肯定存在副本。

为了容错而产生的复制,让强一致性变得棘手。多副本同步写入,势必带来的是性能影响。性能/一致性之间需要取舍

一个简单的场景:两台副本服务器、S1和S2,客户端先发起并行写操作,然后立即读取。

GFS

论文概要

Big & Fast:Google的很多服务都需要统一的存储系统,Mapreduce、爬虫、索引、日志存储、分析、YouTube(?)、相册等等

Global:跨多个数据中心访问,任何客户端可以读取任何数据中心的文件。

sharding:一个文件可能跨多个服务器/磁盘。并行性能和磁盘利用

automatic recovery:出现故障能自动恢复

一个数据中心一次部署

暂时只供内部使用

大文件顺序访问:读/追加。而GFS又不是DB(事务)

在2003年,GFS是凭借什么获得了SOSP最佳论文?

文中的分布式、分区、错误容忍已经在分布式领域出现很久并不是第一次,主要的原因是:大规模在工业界,真实的世界中应用。对弱一致性和单master的实践。

GFS架构

客户端(library,RPC — 这个被使用者隐藏了起来)

每个文件被切分到独立的64MB块中

chunk server:每个块都有三份副本,所有的文件都可以迁移到其他chunk 服务器。支持并行读/写(MapReduce)

也可以存储大文件

分工独立:master负责读写分发,chunkserver负责具体数据

Master的数据

内存(容量小,速度快):

  • file name table:文件名和chunkserver的映射map (写磁盘 Non-Volatile)
  • chunk table: 文件版本(Non-Volatile)、chunkserver列表(Non-Volatile)、租约时间(Volatile)、primary信息,它负责写数据,然后派发副本(Volatile)

磁盘:log(日志,每次写操作)、checkpoint(快照恢复,当重启时能快速恢复到保存的最新状态)

客户端如何读取一个文件?

  1. 发送一个请求<filename,offset> 到master
  2. master根据offset查询chunk server(无缓存时)
  3. Master响应最新的chunkserver table给客户端
  4. 客户端缓存chunk handle 和chunkserver服务器列表
  5. 客户端发送请求<chunk handle,offset>到最近的chunkserver
  6. chunkserver从磁盘读取文件并响应给客户端(客户端接收的是buffer,library会合并为真正文件)

master如何知道chunk是在哪个chunkserver? 每次写都会经过master

客户端如果是追加一条记录需要经过哪些步骤?

  1. 客户端询问master最新的chunk offset
  2. 如果master没有找到primary chunk(租约过期)
    1. 当没有chunkserver可写,并且最新的版本号 丢失时直接返回错误
    2. 从其他的副本选举出新的primary chunkserver,以及文件的最新版本
    3. 增加版本号,并写日志到磁盘
    4. 告诉primary和secondary最新的版本号是多少
    5. 副本写新的版本到磁盘,并且响应结果给新的Primary
  3. Master告诉client 主副节点,client会对响应结果缓存。只有当Primary访问不到时才重新请求
  4. Client发送文件到所有的chunkserver(存内存)
  5. Client通知Primary进行append
  6. Primary检查当前租约是否过期,chunkserver是否有足够的存储空间
  7. Primary根据offset重新计算新的偏移位置
  8. Primary写chunk 文件(64MB)
  9. Primary通知secondary 新的offset,并且append 文件到chunk file
  10. Primary等待所有的副本响应(包括错误的响应,譬如空间不足、超时等)
  11. Primary通知客户端成功或者失败
  12. 客户端可以从第一步开始重试

GFS是如何保证一致性的?

GFS只 保证一次原子写入,数据已经在一个副本落盘。在经过一定时间后,所有的副本数据会一致。

假设出现网络分区,导致脑裂(split brain,存在两个primary)。出现这种情况,GFS引入60秒的租约时间,出现primary不能连通,就必须等待超时(剩余的时间client可以通过cache的primary信息计算)。

当Primary响应客户端已经成功append 记录,随后客户端立即进行读取,看到的应是最新的文件。(注意:不是所有的客户端都能看到最新的文件,GFS是弱一致性。需要等待时间同步到其他节点,通过“就近”复制.)

GFS 如何容错?

错误情况:机器崩溃,崩溃后重启、崩溃后被其他机器替换、消息丢失、分区。

假设设计的GFS是强一致性,需要处理什么问题?

e.g 保证所有的客户端看到的文件内容相同

  1. Primary应能识别重复写入的请求(保持幂等性),或者是客户端应该处理重复发送
  2. 所有的副本要不全部成功,要不全部失败。(必须全部副本写入才能响应成功)
  3. Primary崩溃,有些操作可能会被丢失。新的Primary需要与副本通信找回记录
  4. 避免读取到旧的数据,所有的读必须去Primary获取最新的记录。或者是在租约期内的副本。

GFS性能

  1. 读取吞吐量大(94MB/sec/16台chunkserver),平均每台6MB/sec(机械磁盘顺序查找的速度是30MB/sec、每个网卡大约10MB/sec的速度)交换机的连接接近饱和。因此每台机器的性能还是比较低,得益于可扩展性不错,在生产环境中单个GFS集群可以达到500MB/sec。但当遇到大量文件写入时,也会因为网络瓶颈而导致受限。
  2. 对文件进行append追加时,其最大的限制是最后一块chunk的追加,因为主 Chunk 会检查这次记录追 加操作是否会使 Chunk 超过最大尺寸(64MB)。如果超过了最大尺寸,主 Chunk 首先将当前 Chunk 填充到最大尺寸,之后通知所有其他副本做同样的操作,然后通知client要求其对下一个 Chunk 重新进行记录追加操作。

值得思考的问题

  • 为了更好的支持小文件存储,需要些什么?
  • 如何支持上亿的文件?
  • 能否把GFS用作通用的文件存储系统?
  • 跨异地复制如何优雅?
  • 现在的部署是一个GFS部署一个数据中心,那么数据中心容灾如何考虑?
  • GFS如何应对缓慢的chunk服务器?

关于GFS工程师采访反馈: GFS: Evolution on Fast-forward

  • 文件数量的增加是一个大问题
  • Master的内存是有上限的
  • 文件数量增加,Master的GC就会慢下来
  • master所能承载的客户端连接有限
  • 应用程序需要按照GFS改造
  • master的故障转移需要手动处理(10s)

在后面使用BigTable解决小文件存储,并且开发的第二代GFS——Colossus正是为了解决单点master问题

总结

GFS的论文阐述了性能、错误容忍、一致性相关的设计和评价。GFS是MapReduce中的基础设施。

亮点:

  • 集群式文件系统演变为基础设施
  • 存储与管理的分离标志(name管理在master,文件存储在chunkserver)
  • 并行吞吐
  • 大文件分块存储减少开销
  • 主chunk顺序写设计
  • 利用租期来解决“脑分裂”问题

不足:

  • 单master的限制:内存和CPU
  • 对小文件存储不够友好
  • master的故障转移不够好
  • 弱一致性

参考文献