百种弊病,皆从懒生

GFS notes

2016.11.19

看了下很久前 google 的 GFS 论文, 做点笔记。

设计目标

一上来就看架构,看性能是不合适的,讨论GFS前,先看看它的设计是为了解决什么问题。

  • 用于存储中等大小的文件, 通常是100MB或更大,上GB的文件也很常见,需要高效得支持,小文件需要支持,但不用特别优化
  • 系统中主要有两种读:
    • large streaming read (单次操作几百KB, 1MB或更多, 来自一个client的操作通常位于一个文件的连续区域)
    • small random read (发生在一个文件的任意位置,通常就几KB的量)
  • 可能有大量连续的写操作,操作大小和读操作差不多,一旦写入,文件很少会修改。在文件的任意位置进行小写操作,需要支持,但不用很高效。
  • 支持对同一文件的并发写入,支持原子性,同步开销尽可能小。
  • throughput 优先级高于 latency

接口

  • 没有实现posix
  • 支持 create, delete, open, close, read, write 操作
  • 支持 snapshot 和 record append

架构

single master + multiple chunkservers

chunk: 每个文件会被分割成等长的chunk, 每个chunk 会在创建的时候由 master分配一个 全局唯一的64位长的标识符(chunk handle) .

Chunkserver: chunk 存储在 chunkserver 本地磁盘,通过chunk handle 和 byte range 读写文件。每个chunk默认在3副本,可配置。

Master:

  • 存储所有的文件系统元数据, 包括:namespace, 访问控制信息,文件到chunk的mapping, chunk的当前位置。
  • 管理chunkd lease(后详)
  • 回收 orphan chunk
  • 在chunk server 之间迁移chunk.
  • Master 定期和所有的chunk server 做heatbeat, 发送指令,收集状态。

Gfs 的client 代码实现了文件系统api,和master 做metadata操作,文件的读写直接和chunk server交互,

Chunk Size: 64MB, 每个chunk作为一个普通linux文件存在chunk server 上,

好处:

  • 减少和master的通讯
  • Chunk 设置得比较大的话,client有比较高的可能性只需要和一个chunk server通讯(开头说过大部分文件是100MB左右的),这样就只需要一个tcp connection.
  • 减少了master存储的metadata

坏处:一个文件只有一个chunk的话,如果这个文件成为热点,那就会造成少部分chunk server成为热点,带来瓶颈。 解决办法是为这种可能成为热点的文件设置更多的replication数目,让client从不同的chunk server处读取。

Metadata:

所有metdata存在 master 内存里,主要有三种,文件和chunk的namespace, 文件到chunk的mapping,每个chunk 副本的位置。

前两种会做持久化,通过记录下operation log, 先存在master的本地磁盘,然后复制到远端机器。使用log可以避免master crash的时候造成的数据不一致。

第三种数据,master不存,master在启动的时候问一次所有 chunk server它们的chunk信息,在新chunk server加入的时候也问一次

Operation log: 记录metadata的历史变化,是GFS的中心,只有当operation log成功写入master的本地磁盘,和远端机器之后,master才对client作出反应。当log 文件超过一定大小的时候,master会对log对checkpoint,checkpoint是一种紧凑的B 树结构,可以直接映射进内存来用于namespace的查找,不需要额外的parse. master恢复的时候只需要加载最新的chekpoint 文件, 和在checkpoint之后生成的新log文件。

Chunk lease:

当对一个file chunk进行修改(mutation)时, 会在所有的副本上同时执行。master会从拥有该文件副本的所有chunk server中挑选出一个临时master, 该master会得到临时的租约(lease,初始为60s), 它被称为primiary, 由primiary来决定对chunk的修改顺序, 所有的chunk遵从primiary决定的顺序执行修改。 (master -> primiary, primiary decide order during lease ).

使用租约机制可以最小化master的压力。在chunk的修改过程中,primiary可以向master申请延长租约(通过heartbeat)。如果master和primiary失去通信,它可以在lease过期后再挑选一个primiary.

Snapshot

使用 copy-on-write 实现snapshot。 master受到对某个file 的snapshot 请求时,会取消该文件所有chunk正在执行的lease. lease全部取消或过期后,master将log写入磁盘,并为原文件复制一份metadata, 新的snapshot文件指向原文件相同的chunk。

当client第一次要对该文件某个chunk执行写操作时,先从master处得到当前获取lease的primiary,master发现对chunk的引用计数 > 1, master会让当前持有该chunk副本的所有replica在本地复制一份chunk, 因此副本的复制发生在本地,不需要跨网络传输。

文件的删除

执行删除时, master立刻将删除操作log下来,文件会被重命名为一个隐藏文件名+删除时间戳,master会定期扫描namespace, 发现有这样的文件存在超过三天,就会将它真正删除,在真正删除前,仍可以用新名字访问待删除文件,想取消删除只要将文件重命名回去就行。

检测 stale replica

如果 chunk server 宕机, 错过了master对chunk的修改,那上面存储的chunk就是脏数据(stale).

master 为每个chunk 维护一个version number, 来区分up-to-date 的 replicas 和 state 的replicas.

每次master将lease 授予一个primiary的时候,会将chunk的version number 加1,并通知所有的replicas.如果此时有chunk server 宕机,就会错过version的bump , master 下次看到这个chunk 的版本不是最新的就会将它回收。

HA

fast recovery 和 replication.

无论service以什么样的方式终止,master 和 chunk server 都被设计成可以在几秒内恢复状态并启动. 并不区分正常终止和异常终止。如果某一台server shutdown或restart,client的请求就会超时,接着client 就会进行重试。

chunk server 的replication 通过多副本实现(其他可能方式, parity or erasure codes? )

master 的replication 称为shadows, 是read only 的, 当master宕机时, master 的dns 会被切换到shadows。

数据一致性

每个 chunk server 使用checksum检测数据一致性,checksum和其他metadata一样,存在内存中,通过log做持久化。

read的时候,chunkserver会检查数据的一致性,发现和checksum不符,会对client报错,client就会向其他的replicas请求chunk,同时master会进行调度,从数据完整的chunk server上复制正确的chunk来覆盖错误的数据。

comments powered by Disqus