文章目录自己通过阅读了解论文和极客时间相关讲解,并通过自己已有的框架知识,总结该文章,阅读需要有一定的大数据基础知识。
GFS的三个原则GFS是一个简单的单Master架构。依据硬件进行设计一致性(重点) GFS的三个原则
简单:使用 Linux 服务上的普通文件作为基础存储层,并且选择了最简单的单Master 设计。一旦 Master 出现故障,整个集群就无法写入数据(算不上高可用),虽然有Backup Master的存在,但是从检测到,读取最新CheckPoint,重放日志,可能是分钟级别的,这期间仍旧是不可用的。
对硬件特性进行设计取舍:
采用流水线式的数据传输,而非树形;文件复制时,直接在本地拷贝。减少数据在网络上的传输,避免网络带宽成为瓶颈。
数据一致性:
GFS在并发的随机写入中是,一致但非确定的。而对于并发的追加写入,也只是做出了“至少一次”的保证。
现在我们依次看这三个原则所描述的。
GFS是一个简单的单Master架构。Master有三种作用:相对于存储数据的 Chunkserver,Master 是一个目录服务;相对于为了灾难恢复的 Backup Master,它是一个同步复制的主从架构下的主节点;相对于为了保障读数据的可用性而设立的 Shadow Master,它是一个异步复制的主从架构下的主节点。
目录服务:
master 里面会存放三种主要的元数据:
文件和 chunk 的命名空间信息,即是路径和文件名。
这些文件被拆分成了哪几个 chunk(每一个chuck都有唯一对应的chunk handle编号),即是文件到多个chunk handle的映射。
这些 chunk 实际被存储在了哪些 chunkserver 上,也就是 chunk handle 到chunkserver 的映射关系。
通过这三种元数据,master可以找到客户端要读取的数据在哪里,返回给客户端。
HDFS中NameNode即是第一关系和第二关系。
第一关系:文件与block数据块(chuck)的关系。第二关系:数据块与数据节点的映射关系。
master的快速恢复和可用性
master接受所有客户端的查询请求,且只有一个节点,所以为保证master的性能,将master的数据都保存在内存中。
为了解决挂掉后,数据丢失的风险,master 会通过记录操作日志和定期生成对应的 Checkpoints 进行持久化。(挂掉后,重启读取Checkpoints 和 日志即可)
Backup Master:
如果master节点真的硬件出现故障,这时候需要快速恢复,即是Backup Master,它会进行同步复制。只有当数据在 master 上操作成功,对应的操作记录刷新到硬盘上,并且这几个 Backup Master 的数据也写入成功,并把操作记录刷新到硬盘上,整个操作才会被视为操作成功。当当前master挂掉后,会从Backup Master中选出一个即为新的master。
Shadow Master:
在新的master选举成功,并读取Checkpoints 和 日志时,仍旧是一个空档期,因此为解决这个问题,并诞生了异步复制的Shadow Master,尽可能保持追上 master 的最新状态。
客户端只有在该种情况下会读到过时的master信息。
1.master 挂掉了;2.是挂掉的 master 或者 Backup Master 上的 Checkpoints 和操作日志,还没
有被影子 Master 同步完;3.则是我们要读取的内容,恰恰是在没有同步完的那部分操作上。
依据硬件进行设计HDFS中为了减少NameNode的压力,设计出Secondary NameNode来帮助其合并产生新的fsimage。(并非HA)。
分离控制流和数据流
实际的数据读写都不需要通过 master,客户端无论读写都只需要拿到master的元数据即可。(具体可看HDFS)。
流水线式的网络数据传输。
如果用树形,同时对三个副本进行网络发送,master的带宽可以占满,但是三个chuckserver的数据只占用了1/3。如果用流水线式数据传输,能充分的利用带宽。
GFS中在传输时有主副本,GFS面对几百个并发的客户端,将传输过来的数据放在缓冲区,主副本进行排序,次副本以同样的顺序写入。
HDFS写入时不允许并发,因此在写入时也不用考虑太多,也无主副本之说,但是在租约恢复时会选出一个主副本,保证一致性。(下面会详细讲到)。
为什么优先选择最近的副本写入,而非主副本
同一个机架Rack上的服务器都会接入一台接入层交换机(Access Switch);
各个机架上的接入层交换机都会连接到一台汇聚层交换机(Aggregation Switch);
汇聚层交换机会再连接到核心交换机(Core Switch);
减少交换机的占用资源。
由图可以知道,如果由客户端到B再传输给A,将会比由客户端到A再到B经过的交换机更多。
Snapshot
文件的复制会直接在本地拷贝,不会进行网络传输进行拷贝。
一致性(重点)
GFS中的“ 一致性”
第一个,就指“一致的(Consistent)”:多个客户端无论是从主副本读取数据,还是从次副本读取数据,读到的数据都是一样的。
第二个,指“确定的(Defined)”:就是客户端写入的数据能够完整地被读到。即:每个客户端写入指定offset的数据 和 再从offset读出来的数据是相同的。
GFS中的一个表格
随机写入
多个客户端并发写入数据,即使写入成功了,GFS 里的数据也可能会进入一个一致但是非确定的状态
如果客户端写入GFS中指定offset,客户端A写入数据范围[50, 80],客户端B写入数据范围[70, 100],就有可能出现B覆盖A,或者A覆盖B的情况(不确定的)(写入大小是不确定的)。但是三个副本按同样的顺序写入,是一致的。
出现的原因:
数据的写入顺序并不需要通过Master来协调,而是直接发送给ChunkServer,由ChunkServer来管理数据的写入顺序;
记录追加Record Append的“至少一次”的保障。(并发)
只是进行追加将不会产生不确定的情况A、B、C各自的结尾处写入对应的数据。A客户端可以读取A的完整数据,同理BC一样。
如果副本写入失败,怎么办?
如下:
失败后,X会重新在后面进行记录追加(不止失败的副本)
记录追加使得大部分数据都是一致的,并且是确定的,但是整个文件中,会夹杂着少数不一致也不确定的数据。(保证了至少一次,但不保证顺序。可能使得客户端拿到重复的数据和空数据)(Google的网页存储并不在乎网页是存储了两遍,还是两个网页的顺序)。
但是我们可以在客户端处进行解决,比如在数据中加入校验和,加入唯一的包含时间戳的ID。这样我们可以进行进一步的去重或者排序的操作。
注:,GFS 限制了一次记录追加的数据量是16MB,而 chunkserver 里的一个 chunk 的大小是 64MB。所以,在记录追加需要在chunk 里填空数据的时候,最多也就是填入 16MB,也就是 chunkserver 的存储空间最多会浪费 1/4。
GFS的至少一次保证了高并发和高性能。
在HDFS中,不允许并发且只能追加,也就没有了原来的复杂步骤(如主副本的排序),这样同时保证了一致和确定的。
如果是客户端故障,为保证一致性,会进行租约恢复。
如果是DataNode出现问题,分为三种情况:
从 pipeline setup(准备阶段) 错误中恢复:
新写文件:Client 重新请求 NameNode 分配 block 和 DataNodes,重新设置 pipeline。
追加文件:Client 从 pipeline 中移除出错的 DataNode,然后继续。
从 close 错误中恢复:
到了 close 阶段才出错,实际数据已经全部写入了 DataNodes 中,所以影响很小了。Client 依然根据剩下正常的 DataNode 重建 pipeline,让剩下的 DataNode 继续完成 close 阶段需要做的工作。
当 pipeline 中一个 DataNode 挂了,Client 重建 pipeline 时是可以移除挂了的 DataNode,也可以使用新的 DataNode 来替换。这里有策略是可配置的,称为 DataNode Replacement Policy upon Failure,包括下面几种情况:
NEVER:从不替换,针对 Client 的行为
DISABLE:禁止替换,DataNode 服务端抛出异常,表现行为类似 Client 的 NEVER 策略
DEFAULT:默认根据副本数要求来决定,简单来说若配置的副本数为 3,如果坏了 2 个 DataNode,则会替换,否则不替换
ALWAYS:总是替换。
HDFS会每6小时进行检测,然后进行数据块的恢复。