简介
首先讲出了设计目标
- 组件失效定义文件系统的常态,而不是意外事件。
- 对于数据量巨大的数以亿计的小文件,重现考虑IO操作和Block块的定义。
- 对于绝大多数文件的修改是在追加文件,而不是做覆盖,采用原子性的追加操作。
- 应用程序和文件系统的API采用协同工作的方式,提高效率
设计概述
1.设计预期
- 因为组件失效是常态,所以我们需要持续监控自身状态
- 主要存储100M作于大小的大块数据,也支持小数据的存储,但是不针对小文件系统做优化
- 读取分为大规模的流式读取和小规模的随机读取。对于小规模随机读取,优化方式一般是,对读取操作按照规律排序,之后按照顺序批量读取,避免在文件系统前后来回移动读取。
- 大规模批量导入和小规模随机写入。小规模随机读取性能不佳
- 使用“生产者–消费者队列”
- 更注重网络带宽的稳定,而不是响应延迟。
接口
- 文件以目录树的形式存在,支持对文件的增删改查,读取写入的操作。
- 快照:快速对文件过着目录树进行拷贝
- 追加:允许多个客户端对同一个文件进行追加,同时保证每个可用户端的操作都是原子性的,。这对于实现多路的结果合并,以及生产者–消费者队列非常有用,多个客户端在不需要额外的同步锁的情况下,同时对一个文件的数据进行追加。这对于构建大型的分布式应用是非常重要的。
架构
- chunk系统切割文件的数据块
- master管理所有节点的元数据,系统范围内的活动。
这些元数据包括名字空间、访问控制信息、文件和 Chunk 的映射信息、以及当前 Chunk 的位置信息。 Master 节点还管理着系统范围内的活动,比如,Chunk 租用管理4、孤儿 Chunk5的回收、以及 Chunk 在 Chunk 服务器之间的迁移。 Master 节点使用心跳信息周期地和每个 Chunk服务器通讯,发送指令到各个 Chunk 服务器并接收 Chunk 服务器的状态信息。 - 客户端通过API来访问Master节点,控制文件系统
- 无论是客户端还是 Chunk 服务器都不需要缓存文件数据
单一Master节点
执行流程
- 客户端把文件名和程序指定的字节偏移,根据固定的 Chunk 大小,转换成文件的 Chunk 索引。
- 它把文件名和 Chunk 索引发送给 Master 节点。 Master 节点将相应的 Chunk 标识和副本的位置信息发还给客户端。客户端用文件名和 Chunk 索引作为 key 缓存这些信息。
- 之后客户端发送请求到其中的一个副本处,一般会选择最近的。请求信息包含了 Chunk 的标识和字节范围。
- 在对这个 Chunk 的后续读取操作中,客户端不必再和 Master 节点通讯了,除非缓存的元数据信息过期或者文件被重新打开。
Chunk的尺寸
才用较大的数据chunk有下面的优势:
- 减少客户端于master节点的通讯需求,在master上获取的节点信息会在客户端进行缓存一段时间。
- 客户端对于master的节点信息,客户端可以对一块数据进行多次的读写操作。
- 减少master节点的数据信息的存储量。
大文件的问题是:
小文件包含较少的 Chunk,甚至只有一个 Chunk。当有许多的客户端对同一个小文件进行多次的访问时,存储这些 Chunk 的 Chunk 服务器就会变成热点。在实际应用中,由于我们的程序通常是连续的读取包含多个 Chunk 的大文件,热点还不是主要的问题。
然而,当我们第一次把 GFS 用于批处理队列系统的时候,热点的问题还是产生了:一个可执行文件在GFS 上保存为 single-chunk 文件,之后这个可执行文件在数百台机器上同时启动。存放这个可执行文件的几个 Chunk 服务器被数百个客户端的并发请求访问导致系统局部过载。我们通过使用更大的复制参数来保存可执行文件,以及错开批处理队列系统程序的启动时间的方法解决了这个问题。一个可能的长效解决方案是,在这种的情况下,允许客户端从其它客户端读取数据。
元数据
- 文件和chunk的命名空间----作为日志在磁盘中存储,在其他机器备份
- 文件和chunk的对应关系----作为日志在磁盘中存储,在其他机器备份
- 每个chunk的副本存放地点—这个信息由各个节点向master做心跳汇报
内存中的数据结构
需要使用大的内存对master信息进行管理,而且内存拓展容易实现
Chunk的位置信息
通过定期轮询的方式向master节点汇报状态信息