HDFS 读写数据流程以及 NameNode + 2NN + DataNode 工作机制
刚刚分享了 HDFS 的相关技术,写一篇博客记录一下。
Hadoop 是什么?
HDFS 是 Hadoop 生态圈的一个组件。因此在介绍 HDFS 之前先来回顾一下 Hadoop。
Hadoop是一个由 Apache 基金会所开发的分布式系统基础架构。主要解决,海量数据的存储和分析计算问题。
广义上来说,Hadoop通常是指一个更广泛的概念 —— Hadoop 生态圈。
Hadoop 优势
- 高可靠性
Hadoop底层维护多个数据副本,所以即使Hadoop某个计算元素或者存储出现故障,也不会导致数据的丢失。 - 高扩展性
在集群间分配任务数据,可方便的扩展数以千计的节点。 - 高效性
在MapReduce 的思想下,Hadoop是并行工作的,以加快任务处理速度。 - 高容错性
能够自动将失败的任务重新分配。
Hadoop 组成
区别:
- 在Hadoop 1.x 时代,Hadoop 中的MapReduce 同时处理业务逻辑运算和资源的调度,耦合性较大。
- 在Hadoop 2.x 时代,增加了Yarn。Yarn 只负责资源的调度,MapReduce 只负责运算。
HDFS 概述
HDFS 产生的背景
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。
HDFS 定义
HDFS就是分布式文件管理系统中的其中一种。
HDFS 用于存储文件,通过目录树来定位文件;其次它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS 优劣点
优点
(1)高容错性
- 数据自动保存多个副本。它通过增加副本的形式,提供容错性。
- 某一个副本丢失以后,它可以自动恢复。
(2)适合处理大数据
- 能够处理数据规模达到GB、TB,甚至PB级别的数据。
- 能够处理百万规模以上的文件数量,数量相当之大。
(3)可构建在廉价的机器上,通过多副本机制,提高可靠性。
缺点
(1)不合适低延时数据访问,比如毫秒级的存储数据,是做不到的。
(2)无法高效的对大量小文件进行存储。
- 存储大量小文件的话,会占用NameNode大量的内存来存储文件的目录和块信息。
- 小文件存储的寻址时间会超过读取时间,违反了HDFS的设计目标。
(3)不支持并发写入、文件随机修改。
- 一个文件只能有一个写,不允许多个线程同时写。
- 仅支持数据append,不支持文件的随机修改。
HDFS 组成架构
HDFS是master和slave的主从结构。它的主要角色是Namenode 和 Datanodes。
Namenode是master节点,主要负责元数据管理,维护HDFS的名称空间,以及文件分块的位置信息。
Datanodes是slave节点。Namenode下达命令,由datanode来执行实际的操作。包括存储实际的数据块,执行数据块的读/写操作。
图中的client就是客户端,它与namenode进行交互获取文件的位置信息;与datanode交互,读取或写入数据。
图中的rack指的是放服务器的机架。
HDFS 写数据流程
解释:
比如客户端想上传200m 的一个文件,它首先对文件做一个分块的处理,将200m的文件分成两块,一块大小是128m 另外一块大小是 72m。
接下来客户端创建一个Distributed File System,通过FS模块向 NameNode 请求上传文件,NameNode 检查目标文件是否存在,父目录是否存在。返回是否可以上传。如果可以上传,客户端请求第一个block上传到哪几个Datanode的服务器上。NameNode 检测datanode 信息池,返回可用的3个datanode。这3个datamode是按照网络拓扑排序的,离客户端越近的会有优先级。
接下来客户端通过 FSDataOutputStream 模块与 dn1 建立连接,请求数据传输,并建立Pipeline 管道。在dn1与dn2;dn2 与 dn3之间建立通道。建立管道的意义是说如果没有管道需要上传3次给dn1 dn2 和 dn3。 pipeline 建立完毕后会返回成功信息。
接下来第7步,建立信息传输流,客户端开始往 dn1上传第一个block,以packet 为单位传输数据,大小为 64k。dn1 接收到渊源不断的数据包会复制保存,然后不做拦截,数据包通过pipeline 管道流向dn2,复制保存,再到dn3。
数据保存成功后,客户端会再次请求namenode上传第二个block。
HDFS 读数据流程
读数据流程相比于写会更简单一些。
客户端依然需要通过 DistributedFilesystem 向NameNode 请求下载文件,NameNode通过查询元数据,找到目标文件块所在的DataNode 地址。并返回给客户端。
客户端会按照就近原则,然后选一台Datanode 服务器,建立连接,请求读取数据。然后DataNode 开始传输数据给客户端(先从磁盘里读取数据输入流,以Packet为单位来做检验)
客户端以packet为单位接收,先在本地缓存,然后写入目标文件。
SecondaryNameNode介绍
问题产生:NameNode中的元数据存储在内存中,存在断电后,元数据丢失的问题。
解决方案:在磁盘中产生FsImage备份元数据。
新的问题:当在内存中的元数据更新时,若同时更新 FsImage,会让效率降低,不更新会产生不一致问题。
解决方案:引入 Edits 文件(只进行追加操作,效率很高)。每当元数据有更新或添加元数据时,修改内存中的元数据并追加到 Edits 中。当 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合并元数据。
新的问题:长时间添加数据到 Edits 中,会导致文件数据过大,效率降低,断电恢复元数据的时间过长。因此需要的定期进行 FsImage 和 Edits 的合并。若由 NameNode 节点来完成该操作,效率又会降低。
解决方案:引入新的节点 SecondaryNameNode,专门用于 FsImage 和 Edits 的合并。
Fsimage:NameNode 内存中元数据序列化后形成的文件。
Edits:记录客户端更新元数据信息的每一步操作(可通过 Edits 运算出元数据)。
NameNode 和 SecondaryNameNode 工作机制
NameNode 启动时,先滚动 Edits 并生成一个空的 edits.inprogress,然后加载 Edits 和 Fsimage 到内存中,此时 NameNode 内存就持有最新的元数据信息。
Client 开始对 NameNode 发送元数据的增删改的请求,这些请求的操作首先会被记录到 edits.inprogress 中(查询元数据 的操作不会被记录在 Edits 中,因为查询操作不会更改元数据信息),如果此时 NameNode 挂掉,重启后会从 Edits 中读取元数据的信息。然后,NameNode 会在内存中执行元数据的增删改的操作。
由于 Edits 中记录的操作会越来越多,Edits 文件会越来越大,导致 NameNode 在启动加载 Edits 时会很慢,所以需要对 Edits 和 Fsimage 进行合并(所谓合并,就是将 Edits 和 Fsimage 加载到内存中,照着 Edits 中的操作一步步执行,最终形成新的 Fsimage)。 SecondaryNameNode 的作用就是帮助 NameNode 进行 Edits 和 Fsimage 的合并工作。
SecondaryNameNode 首先会询问 NameNode 是否需要 CheckPoint(触发 CheckPoint 需要 满足两个条件中的任意一个,定时时间到和 Edits 中数据写满了)。直接带回 NameNode 是否检查结果。SecondaryNameNode 执行 CheckPoint 操作,首先会让 NameNode 滚动 Edits 并生成一个空的 edits.inprogress,滚动 Edits 的目的是给 Edits 打个标记,以后所有新的操 作都写入 edits.inprogress,其他未合并的 Edits 和 Fsimage 会拷贝到 SecondaryNameNode 的本地,然后将拷贝的 Edits 和 Fsimage 加载到内存中进行合并,生成 fsimage.chkpoint, 然后将 fsimage.chkpoint 拷贝给 NameNode,重命名为 Fsimage 后替换掉原来的 Fsimage。 NameNode 在启动时就只需要加载之前未合并的 Edits 和 Fsimage 即可,因为合并过的 Edits 中的元数据信息已经被记录在 Fsimage 中。
DataNode 工作机制
- 一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本 身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
- DataNode 启动后向 NameNode 注册,通过后,周期性(1 小时)的向 NameNode 上 报所有的块信息。
- 心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数 据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则 认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器。