大数据组件 HDFS 即 GFS 开源实现,用于存储非结构化数据 。上层还有 HBase(Big Table)用于存储结构化数据。再上层就是 MapReduce 计算框架。
背景需求
- 硬件故障率高
- 文件大、数量不多
- 主要用于读取,多生产者原子性追加连续写入
- 带宽需求高,延迟需求不高
接口
- 分层组织目录:
- 增删、打开、关闭、读写文件
- 快照:秒级别创建文件副本
- 原子追加
架构
Master
-
单节点存储元数据信息:
维护所有的文件系统元数据,控制全系统的活动。尽量减少其读写操作防止成为瓶颈。
例如实现分层目录,就需要维护目录表和指向数据的指针。
可以直接放在内存中提高访问速度。
单节点是指元数据都在同一节点,一般还会有备用节点保存元数据副本。
-
元数据信息
- 名称空间:即层次目录的路径,value 为指向文件位置的指针/句柄。还需考虑目录读写锁的并发问题。
- 文件分为固定大小64 M 的chunk块,每块一个不可变的唯一的64位块句柄。
- 3种主要类型的元数据:文件和Chunk的命名空间、文件和Chunk的对应关系、每个Chunk副本的存放地点
- 操作日志:元数据唯一的持久化存储记录,记录元数据的变化,只有变化先被持久化后,才能对客户端可见。日志到一定大小后做 checkpoint。
-
Matser 行为
- 检查 chunk server 状态:Master 端不持久化保存chunk位置信息,而是通过HeartBeat消息与每个 chunkserver进行周期性通信,向其发出指令并收集其状态。如果存储节点失效及时替换。
- chunk 的检查、清理、复制。用校验码例如MD5检验文件是否失真,失效及时恢复。
- 要支持并发操作,保证移动改动文件时不会产生影响。
- 客户端询问 Master 应该访问哪些 chunks ervers,直接与块服务器交互。
客户端
- sdk 的形式内嵌
- 不缓存数据,但缓存元数据:可降低 Master 单点故障问题。
- 封装 Master 与 chunck server 的交互
- 客户端询问 Master 应该访问哪些 chunks ervers,之后直接与 chunk server 交互,减少 Master IO操作。
chunck server
- 多个 chunk servers,多个客户端。chunck 默认储存三个副本在多个 chunk servers 上,且副本距离在空间上越远容错性越大,GFS 有副本位置调度策略。
- 接收 Master 调度信息,接收客户端的请求。
- 客户端和chunkserver都不对文件数据进行缓存,消除缓存的一致性问题。
一致性模型
// TODO
系统交互
租约与变更
-
目的:尽量减少与Master的交互,同时要保证写入数据的一致性。
-
Master 接到客户端请求后,选择一个为主 chunk ,用于之后一段时间协调副本间的一致性,后续不再由 Master 协调,相当于租用权限。并且不需要心跳机制,一段时间后会重新分配主 chunk。
-
返回给客户端主 chunk 标记和其他副本位置。
-
客户端缓存这些数据,直到租约的时间到期变为无效数据,之后重新向 Master 提交请求。
-
数据流同步给chunk 服务器,LRU缓存此数据
流式写入,一个节点接收到数据流立即转发给另一个节点,将同步变为并行,减少同步延迟,增加吞吐量。同步给主 chunk 后根据网络拓扑规划下一个更近的 chunk。
每一个 chunk 都先缓存数据到自己内存中,不会马上写入。
-
客户端把自己发送的数据告诉主 chunk
所有数据发送完后,主 chunk 对每一个数据块写入分配序列号,行成一个序列。
-
主 chunk 把写请求发送给所有副本,副本返回ACK。
-
所有副本根据序列顺序将数据落盘。
-
副本回复主 chunk 完成情况,主 chunk 回复客户端。
-
出现错误,或者大雨 chunk 大小,则填充后通知客户端重试。
至少写入一次?
数据流
- 控制流与数据流分离,降低延迟提高吞吐量。
- 数据流采用管道模式降低延迟
- 给予 IP 最邻近选择,链式复制,提高吞吐
原子追加
- 支持并发客户端的共同写入与消费。
- 数据会追加到文件最后的 chunk 上
- 当数据大于当前 chunk 大小,会填充后通知客户端写入新 chunk
- GFS 只保证数据至少被一次写入
快照
- 支持快速创建一个大规模数据集合备份:假创建、惰性创建
- 首先取消文件所有 chunk 的租约
- master 记录操作到磁盘后创建拷贝文件的元数据,其与原文件指向相同 chunk。即只创建了一个元数据指针。此时对原文件和副本的读实际都是同一个 chunk。
- 一旦发生写操作,无论原文件还是拷贝文件的修改都会导致在本地机器创建一个新chunk,并修改变更文件的元数据信息。
Master节点的操作
名称空间操作(即目录树路径映射关系)
-
支持并发操作
-
对路径节点上读锁,对文件节点上读写锁
读锁可以并发上读锁后读,但上读锁的时候不能写。上读写锁就只有当前进程能读和写。
-
获取锁的顺序按层级-字典排序,以防止死锁
副本管理
-
最大化可靠性和网络带宽利用率
-
在磁盘使用率低,最近创建次数,放置距离三者的权衡。有一套公式。
-
复制时会考虑频率控制,因为复制时会占用网络带宽,空闲时复制。
-
周期扫描,心跳机制,交换信息,对未达复制数的副本进行复制 。
-
对分配不合理的副本进行再平衡,迁移负载较高的 chunck server
垃圾收集
-
失败但已经写入的数据不会删除,数据只会追加写入,即可能存在脏数据,或者由于硬件问题导致数据不一致了。这些失效部分问题就需要周期性垃圾清理。
-
惰性删除简单可靠。
-
删除机制
- Master 记录操作,除了读以外的事务性操作都要记录 log,方便数据恢复。
- 修改文件名,追加删除时间戳后缀。
- Master 在定时任务处理遍历文件,删除其元数据信息,实际上块并未被删除。
- Master 周期统计孤儿chuck并通过心跳发送给chunk server。
- chuck server 自由决定何时真正的删除chuck 数据(一个周期性线程)。
-
不能有效的利用存储空间
-
但简化了分布式垃圾回收的实现
失效副本的检查
-
为防止副本错过某些修改而失效,并被客户端读取到一个失效副本,所以需要定时清理。
-
master创建租约后会通知所有其他副本版号加一,用于标识副本失效。
-
当master心跳检查进行获得chuck server数据时会检查每个chuck的版本信息
如果版本号小于则更新租约,如果大于则标记此副本为失效副本
-
客户端在与chuck通信时每次都先检查版本号以保证不丢错失变更。
容错和诊断
运行时候保证可靠,崩溃时保证恢复。
高可用性
- 快速恢复
- 检查点快速重启:Master 会写恢复日志到磁盘,创建快照到硬盘后即为检查点,只需要存检查点之后的日志。同时还会同步到备份 Master节点。
- 冗余存储
-
chunk的复制
-
master的复制
有许多有完整操作日志的备份Master,可以快速恢复。还有一些更新慢不到一秒的影子Master,读取操作日志完成和 Master 同样的操作。
-
- 数据完整性
- 读写时检查checksum:例如纠错码,写时每一块算一次校验和,读的时候再算一次进行比较。
诊断工具
- 尽量保持详尽的RPC日志,用于监控与分析。