打怪升级之小白的大数据之旅(四十六)<HDFS各模块的原理>

Posted GaryLea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打怪升级之小白的大数据之旅(四十六)<HDFS各模块的原理>相关的知识,希望对你有一定的参考价值。

打怪升级之小白的大数据之旅(四十六)

HDFS各模块的原理

上次回顾

上一章,我们学习了HDFS的基本知识以及一些常用的操作,本章,我们对HDFS各模块的原理进行讲解,了解清楚这些,可以更好的辅助我们理解HDFS

HDFS的数据流

HDFS是以流的方式对数据进行存储与读取的,下面我们就根据它的底层原理来认识HDFS的写入与读取逻辑

HDFS写数据流程

写数据的流程分为三块:文件写入、网络拓扑以及机架感知,下面我来详细为大家介绍

HDFS文件写入的原理

首先,我先放一个整体的写数据流程图
在这里插入图片描述

  1. 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
  2. NameNode返回是否可以上传。
  3. 客户端请求第一个 Block上传到哪几个DataNode服务器上。
  4. NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
  5. 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
  6. dn1、dn2、dn3逐级应答客户端。
  7. 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
  8. 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)

接下来我就使用通俗的语言来解释这个原理:

  • 首先我有一个客户端,一个NameNode,以及三台存数据的节点DataNode,还有我要上传到HDFS的数据 ss.avi,它的大小是200MB,所以我们的这个ss.avi文件就会被切割为2个块,分别是128m和72m,我们要知道,数据的传输是单线程的,当第一个块传输完毕才会传输第二个块的
    在这里插入图片描述

  • 客户端通过DistributedFileSystem这个模块向NameNode请求需要上传文件

  • NameNode会翻看一下自己的目录(元数据),看看里面有没有ss.avi这个文件,发现没有,于是告诉客户端,可以进行数据的上传。

  • 客户端收到消息后,进行切割操作,将数据切割成两块,然后请求上传第一个块(block)数据,并询问NameNode,它需要向上传到哪几个DataNode服务器上

  • NameNode将可以上传的数据节点dn1,dn2,dn3告诉客户端
    在这里插入图片描述

  • 客户端开始通过FSDataOutputStream模块进行数据的上传第一个块(block)前,它会向DataNode1请求,建立块(block的传输通道),然后将数据从磁盘中读取放到本地内存中进行缓存

  • 与DataNode1的传输通道建立后,DataNode1就会向它后面的节点DataNode2进行请求通道建立,DataNode2会向后面的DataNode3请求建立通道
    在这里插入图片描述

  • DataNode3会告诉DataNode2,通道建立成功,DataNode2会告诉DataNode1,通道建立成功,DataNode1会告诉客户端通道建立成功
    在这里插入图片描述

  • 客户端收到应答后,就会将块数据以包(Packet)的形式进行传输(就像图中的小圆点)

  • 每一个数据包在到达节点时会进行校验(Byetbuffer),查看是否丢失数据(丢包)

  • 确认数据包正常时就会写入到DataNode1的磁盘中(这个过程叫落盘),然后这个数据包通过前面建立的通道进入下一个节点…直到整个块的数据传输完成
    在这里插入图片描述

  • 当第一个块数据传输完成后,就会重复上面的动作继续进行第二个块的传输

  • 整个数据传输完成后,客户端会告诉NameNode,然后关闭资源
    在这里插入图片描述

好了,这就是整个的HDFS的文件存储逻辑,我们需要的注意以下几点:
- 客户端只会向一个节点进行通道的建立,即我上面所演示的DataNode1,其他的通道建立是由HDFS自己建立的
- 为什么要建立三台节点?因为我们前面学习了,HDFS默认是建立了三个副本,所以我们在传输数据时,建立了通道,通过数据包落盘的方式,可以完成数据的副本操作

网络拓扑-节点距离计算原理

  • 在上面的数据写入流程中,不知道大家有没有一个疑问:前面我的示例中,为什么不是直接与中间的节点建立通道而是与第一个dn1建立通道呢?
  • NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
  • 这里有一个公式:节点距离=两个节点到达最近的共同祖先的距离总和
  • 举个例子来说明:我有一个数据中心,里面有两个集群,d1和d2,另外每个节点有三个机架,里面存放了三个节点(服务器)
  • 我们知道集群、节点之间的连接都是通过网络进行通信的(交换机或者路由器来实现),所以几点距离选择最近的原因就距离越短,它所消耗的网络资源就越少
    在这里插入图片描述
    找节点的方式举例:
  • 同一节点上的进程之间寻找
    • 同一个节点中,找到自己的其他进程,直接通过网络端口号就可以找到
    • (d1/r1/n0,/d1/r1/n0)=0
  • 同一机架上的不同节点
    • 当n-0找自己机架上的n-1节点时,首先,它会先找自己机架的交换机/路由器,然后通过它寻找n-1节点,所以,n-0到n-1节点的距离就是
    • (d1/r1/n0,d1/r1/n1)=2
  • 同一集群中不同机架上的节点
    • 首先机架会先通过机架上的路由找到它的集群路由,然后通过集群路由找到所需要找寻的机架路由,再通过机架的路由找到所需要的节点
    • (d1/r2/n0,d1/r3/n2)=4
  • 不同集群中的节点
    • 就和上面的逻辑一样,不同集群中的节点链接,需要先找到根的路由,然后再找到它下面的路由,最后找到对应的节点
    • (d1/r2/n1,d2/r4/n1)=6
      在这里插入图片描述

HDFS的机架感知原理(副本存储的节点选择)

机架感知的官方的说明:http://hadoop.apache.org/docs/r3.1.3/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication

举个例子,我有一个集群d1,里面有三个机架,每个机架有三个节点
在这里插入图片描述
副本的存储有两种情况

  • 客户端不在我们的集群节点中、
    • 客户端不在我们的集群节点中,副本是随机进行选择的
  • 客户端在我们的集群节点中
    • 客户端在我们的集群节点中时,第一个副本在客户端(client)所处的节点上在这里插入图片描述
    • 第二个副本在最近的一个机架的随机一个节点上
      在这里插入图片描述
    • 第三个副本在第二个副本所在的机架的随机节点上
      在这里插入图片描述
  • 大家不免会有疑问,为什么第三个副本不在第三个机架上呢?这是因为第一个副本所在的机架离第三个机架的距离太远了。在前面我们刚学习了网络拓扑,每一个节点间的连接都需要占用网络资源
  • 那么为什么三个副本都不在第一个机架上呢?很简单,假设我们存储第一个副本的机架r1坏掉了,那么数据就没了,所以为了安全考虑就这么选择的

HDFS读数据流程

同样的,我先放一个读数据的整体流程,示例还是以前面存储的ss.avi举例
在这里插入图片描述

  1. 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
  2. 挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
  3. DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
  4. 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件

跟写数据一样,下面来详细解释一下读数据的流程

  • 首先我有一个客户端,一个NameNode,三个节点;NameNode中存储了前面我们写入的数据ss.avi的元数据(三个副本,两个块,文件的名称、大小等信息)
    在这里插入图片描述
  • 客户端创建一个DistributedFileSystem流,向NameNode发送请求,需要下载ss.avi文件,NameNode接收请求后,会发送该文件的元数据
    在这里插入图片描述
  • 客户端接收到元数据后,知道了这个数据有两块,接着它会创建FSDataInputStream流,用于读取数据,然后它会根据我们前面学到的网络拓扑以及机架感知就近的原则,随机选择一个节点请求数据的第一个块
    在这里插入图片描述
  • 该节点会将块数据进行传输,同样的,使用的是数据包方式进行传输
  • 客户端在接收过程中也会进行Byetbuffer校验,查看是否丢包,确认数据无误,然后进行落盘
  • 传输完成了第一个块数据后,再次请求第二个块数据,同样是随机选择一个节点,该节点接到请求后进行第二个块的数据传输
    在这里插入图片描述
  • 两个数据块都接收完成后,客户端会将数据进行拼接,然后关闭资源
    在这里插入图片描述

NameNode和SecondaryNameNode

NN和2NN工作机制

NN和2NN的关系

  • 我们前面写入、读取数据的都讲了,接下来就是介绍NameNode和SecondaryNameNode的原理了,在前面的数据传输过程中,不知道大家有没有想过一个问题:NameNode的元数据是存储在哪里的?
  • 假设元数据存储在NameNode所在的节点磁盘中呢?我们知道,磁盘的读写远远不如内存,存储在磁盘中必然效率很低
  • 那么元数据存储在内存中呢?内存虽然运行速度快,但是它无法持久保存,如果断电或其他情况导致节点或集群关闭,那么元数据就丢失了,所以它会在运行过程中,将产生过的数据写入进磁盘中,这就是备份元数据的FsImage,但内存中的数据并不能实时进行备份,实时备份太占用资源了
  • HDFS为了解决这个问题,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据
  • 它所产生的问题大家想必知道了,长时间添加数据到Edits中,文件数据会很大,效率就会降低,如果断电等情况需要数据恢复时。就会特别的慢
  • 能不能定期进行Edit与fsimage进行合并呢?这样问题不就解决了,但这个功能不能让NameNode来做,这样效率太低了,于是NameNode雇佣了一个秘书,它就是2NN节点(SecondaryNameNode)
  • 还记得我们集群搭建时说过,NameNode不要和SecondaryNameNode在同一个节点上部署么,这就是原因,我们将SecondaryNameNode单独放到一个节点中。这样就可以大大提高HDFS的工作效率

NN和2NN的工作原理

在这里插入图片描述
第一阶段:NameNode启动

  1. 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
  2. 客户端对元数据进行增删改的请求。
  3. NameNode记录操作日志,更新滚动日志。
  4. NameNode在内存中对元数据进行增删改。

第二阶段:Secondary NameNode工作

  1. Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
  2. Secondary NameNode请求执行CheckPoint。
  3. NameNode滚动正在写的Edits日志。
  4. 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
  5. Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
  6. 生成新的镜像文件fsimage.chkpoint。
  7. 拷贝fsimage.chkpoint到NameNode。
  8. NameNode将fsimage.chkpoint重新命名成fsimage。

Fsimage与Edits工作原理

工作原理

还记得当我们第一次部署集群时,需要格式化NameNode么?这个操作就是为了产生Fsimage与Edits文件
- Fsimage文件是HDFS文件系统元数据中的一个永久性的检查点,里面包含了HDFS文件系统的所有目录和文件inode的序列化信息
- Edits文件用于存放HDFS文件系统的所有更新操作的路径(命令),文件系统客户端执行的所有写的操作会被记录到Edits文件中
- 因为我们在学习IO流的时候知道,Java对象的保存需要进行序列化,而Hadoop是Java写的,所以为什么存储序列化信息大家知道了吧

Fsimage与Edits的文件内容

查看Fsimage与Edits文件,我们进入到如下目录中

cd /opt/module/hadoop-3.1.3/data/dfs/name/current/

在这里插入图片描述
因为我前面有很多操作,所以有很多的Edites文件,前面我们说了,它们是以序列化的形式进行保存的,那么我们怎么查看它的文件内容呢?我们可以使用如下命令

oiv查看Fsimage文件

  • 语法格式
    hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
    
  • 示例
    # 将fsimage_0000000000000000225文件转换为xml文件并设置名称为fsimage.xml
    hdfs oiv -p XML -i fsimage_0000000000000000225 -o /opt/module/hadoop-3.1.3/fsimage.xml
    
  • 通过查看文件,我们会发现文件中的内容没有记录块所对应DataNode,这是因为DataNode节点会间隔一段时间向NameNode汇报一次数据块信息

oev查看Edits文件

  • 语法格式
    hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径```
    
  • 示例
     hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml
    
  • NameNode如何确定下次启动时合并哪些Edits?很简单
    在这里插入图片描述
    seen_txid记录的是edits后面的号码,inprogress_xx是当前执行的edits文件,我们可以根据这两个信息来确定下次启动时合并哪些Edits文件

CheckPoint时间设置

  • 通常情况下,SecondaryNameNode每隔一小时执行一次
  • SecondaryNameNode会一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次
  • 这个设置在hdfs-default.xml中,因此我们可以自己来更改CheckPoint的时间设置,但是不建议,因为没有必要,使用默认就好

DataNode

DataNode工作原理

接下来就是最后一个模块:DataNode,还是老样子,直接上整个流程图
在这里插入图片描述

  1. 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
  2. DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
  3. 心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
  4. 集群运行中可以安全加入和退出一些机器

详细流程如下:

  • NameNode是老大,它管理着所有的DataNode,每一个DataNode中都是以数据块(block)的形式进行数据的存储,数据块中除了数据本身,还有数据的长度、校验和以及时间戳
  • 校验和就是为了防止数据被篡改,后面介绍数据完整性时,会介绍校验和
    在这里插入图片描述
  • 当DataNode启动时,会向老大汇报自身情况即它的块数据,这就是向NameNode注册,我们可以理解为上班签到,老大点头后告诉DataNode成功后,DataNode就会正式开始工作
    在这里插入图片描述
  • 在它工作时,会以每个小时为一个周期再次上报所有的块信息,老大就会根据汇报结果进行元数据的更新等操作
    在这里插入图片描述
  • 在这一小时周期中,DataNode节点可能会因各种情况导致节点崩溃,那么老大NameNode怎么知道该节点是否正常工作呢?
  • 此时就要引入一个知识点–心跳,DataNode每3秒会告诉NameNode老大,自己还活着…如果老大有新的指令,就会带着指令进行操作(所以我们可以进行数据的操作)
  • 如果某个节点超过十分钟都没有向NameNode老大汇报心跳,那么老大就会认为这个DataNode小弟挂掉了,如果此时有备用的节点,就会替换掉挂掉的小弟
    在这里插入图片描述

掉线时限参数设置

  • 前面我们说了,DataNode会周期性的汇报工作和心跳,它同样是以配置文件的形式来设置的,设置的配置文件为:hdfs-site.xml
    在这里插入图片描述

  • 我们要注意一下:heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒

    <property>
    	// 汇报的周期
        <name>dfs.namenode.heartbeat.recheck-interval</name>
        <value>300000</value>
    </property>
    <property>
    	// 心跳的秒数
        <name>dfs.heartbeat.interval</name>
        <value>3</value>
    </property>
    

数据完整性

  • 在我现实生活中,如果某个交通要道的红绿灯信号一直是绿灯,或者一直是红灯,岂不是乱了套了,同样的,如果DataNode节点的数据损坏了,却没有发现,那岂不是很危险,因此我们使用校验和机制来保证数据的完整性
    在这里插入图片描述
  1. 当DataNode读取Block的时候,它会计算CheckSum。
  2. 如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
  3. Client读取其他DataNode上的Block。
  4. DataNode在其文件创建后周期验证CheckSum

总结

本章对HDFS的各个模块的底层原理进行了讲解,这个内容主要是为了辅助我们理解HDFS,下一章我为大家带来工作中会遇到的一些HDFS的扩展知识

以上是关于打怪升级之小白的大数据之旅(四十六)<HDFS各模块的原理>的主要内容,如果未能解决你的问题,请参考以下文章

打怪升级之小白的大数据之旅(四十五)<认识HDFS与常用操作>

打怪升级之小白的大数据之旅(四十八)<初识MapReduce>

打怪升级之小白的大数据之旅(六十六)<Hive旅程第七站:Hive的分区表与分桶表>

打怪升级之小白的大数据之旅(六十六)<Hive旅程第七站:Hive的分区表与分桶表>

打怪升级之小白的大数据之旅(四十)<Shell编程>

打怪升级之小白的大数据之旅(四十一)<大数据与Hadoop概述>