大数据学习2——HDFS原理学习

在上一篇博客中,我们已经搭建了一个Hadoop集群,这里开始学习HDFS的基本原理。

HDFS的原理

hadoop的三大组件

hadoop有三大组件:

  1. HDFS文件系统;
  2. MapReduce编程框架;
  3. Yarn资源管理系统(2.x版本后);

这篇文章将针对HDFS进行学习。

什么是HDFS

HDFS即Hadoop分布式文件系统(Hadoop Distributed Filesystem),是为了处理大文件而设计的一种文件系统。传统的文件系统是单机的,能够存储的文件是有限的,而HDFS是分布式的系统,是可以扩展的,可以横跨很多机器的,所以能够处理大数据。HDFS的设计思想来自于Google在2013年10月发表的GFS论文。

HFDS采用的是主从架构,一个HDFS集群主要包括两种节点,一种叫做NameNode,一种叫做DataNode。其实还有一个SecondaryNameNode,是用来辅助NameNode的。

NameNode:管理文件系统元数据的节点,相应客户端需求(写文件,读文件、创建、重命名等)的节点。所谓的元数据,就是这个文件存储在哪些机器上,文件大小,创建时间,叫什么名字,对应的权限。NameNode不存储文件实际数据,所以读写文件的时候,只是告诉客户端具体的文件位置,客户端获取这个位置信息后,就直接和DataNode交互了。

DataNode:存储实际的数据。一个集群通常有很多个DataNode。

SecondaryNameNode:辅助NameNode来进行元数据的管理,后续会具体介绍。

HDFS基本架构

图中绘制了两个机架(Rack),HDFS在存储文件时,可以选择机架感知策略。

上图的架构里面出现了NameNode,DateNode和Client。Client需要读写文件会与NameNode进行交互,获取文件信息。然后去DataNode里面读写相应文件。

HDFS存储机制

每一个文件存储在HDFS里,会被分成文件块。写入HDFS的文件会被分割成64M或者128M的文件块(Block),每个文件块存储在几个节点上,称之为副本。一般来说,HDFS默认是存储3个副本。在上图里面,Client上传的文件T,按照128M一个块,被分成了4个块,最后一个块是小于128M的,但是也作为一个块存储。每个文件快,可以看到都有3个副本。

像文件块1,在DataNode_rack0_0,DataNode_rack0_1,DataNode_rack1_0这3个节点里面都有副本。而关于这个文件的元数据信息,则存储在NameNode节点里面。

机架感知

一般一个集群里,一个文件块会设置3个副本。

  1. 第一个副本块存本机

  2. 第二个副本块存不同机架的一个服务器节点上

  3. 第三个副本块存跟本机同机架内的其他服务器节点

机架感知策略的好处在于:

  1. 如果本机数据损坏或者丢失,那么客户端可以从同机架的相邻节点获取数据,速度肯定要比跨机架获取数据要快。

  2. 如果本机所在的机架出现问题,那么之前在存储的时候没有把所有副本都放在一个机架内,这就能保证数据的安全性,此种情况出现,就能保证客户端也能取到数据

在机架感知下,文件的读取也有一定的规则:

  1. 如果在本机有数据,那么直接读取

  2. 如果在跟本机同机架的服务器节点中有该数据块,则直接读取

  3. 如果该HDFS集群跨多个数据中心,那么客户端也一定会优先读取本数据中心的数据

HDFS读文件流程

在这里插入图片描述

  1. Clinet向NameNode发起请求,Namenode会视情况返回文件的部分或者全部block列表, 对于每个block, Namenode都会返回有该block拷贝的DataNode地址;
  2. 根据NameNode返回的信息,Clinet选取离客户端最近的DataNode来读取block。
  3. 读取完当前block的数据后, 关闭当前的DataNode链接, 并为读取下一个block寻找最佳的DataNode;
  4. 当读完列表block后, 且文件读取还没有结束, 客户端会继续向Namenode获取下一批的block列表;
  5. 读取完一个block都会进行checksum验证, 如果读取datanode时出现错误, 客户端会通知Namenode, 然后再从下一个拥有该block拷贝的datanode继续读。

HDFS写文件流程

  1. Clinet首先将要存储的数据切分成若干块,Clinet向NameNode发起请求;Namenode会检查要创建的文件是否已经存在, 创建者是否有权限进行操作, 成功则会为文件创建一个记录, 否则会让客户端抛出异常;NameNode返回给客户端第一个block可以存储的DataNode列表。

  2. 根据NameNode返回的DataNode列表,选择最近的DataNode,创建socket连接,发送第一个block

  3. 第一个DataNode接收到数据,发送到第二个DataNode,第二个DataNode将接收到的数据发送到第三个DataNode,把它们排成一个pipeline管道。只要写入了dfs.replication.min的复本数(默认为1),写操作就会成功,

  4. 第三个副本完成后,向第二个DataNode返回成功的信息(ack),收到第三个副本所在的DataNode返回的信息,第二个DataNode向第一个DataNode返回成功信息

  5. 第一个副本所在的DataNode向客户端返回成功的信息。开始下一个数据的传输。

如果传输过程中, 有某个Datanode出现了故障, 那么当前的pipeline会被关闭, 出现故障的Datanode会从当前的pipeline中移除, 剩余的block会继续剩下的Datanode中继续以pipeline的形式传输, 同时Namenode会分配一个新的Datanode, 保持副本设定的数量。

NameNode工作机制详解

在NameNode节点里,元数据首先是存在内存里面的。此外,NameNode还会有一个fsimage文件,是最新的元数据检查点文件。为了避免数据丢失,也会把内存里新增的数据保存到硬盘里,如果写入fsimage里,因为会有修改之前的记录,所以性能较差。所以写入到edits文件里,因为是顺序增加,所以性能很快。当系统运行到一段时间之后,edits文件会比较大,需要合并edits到fsimage里去。这时候就是SecondaryNameNode在发挥作用。如果在NameNode上面合并,会影响NameNode的运行。具体的操作流程,如下图。

HDFS的一些策略

心跳机制

主节点和从节点之间的通信是通过心跳机制实现的,如NameNode与DataNode之间,JobTracker和TaskTracker之间。所谓“心跳”是一种形象化描述,指的是持续的按照一定频率在运行,类似于心脏在永无休止的跳动。

在Hadoop中,NameNode如何知道可以使用哪一个DataNode来存储?哪一个datanode的有多少可用空间?这里就用到了心跳机制,DataNode会定时的向NameNode发送报告 目的告诉NameNode自己的存活状况以及可用空间。这个时间默认是3s。

当一个DataNode长时间没有发送心跳报告,NameNode就会判断这个节点是宕机了,这时,NameNode就会设置这个节点为“dead node”,并且寻找这个节点上数据的副本,复制到其他可用的节点上。当然了,如果一次心跳报告没有收到,就判断为宕机,肯定是不合理的。而且,仅仅是没收到就判断宕机,也是有些不合理,还需要NameNode主动去确认一下。DataNode每隔3秒向NameNode发送一次心跳报告,只有NameNode收到了一次,就会重新计数。当NameNode连续10次没有收到DataNode的心跳报告,会觉得DataNode可能宕机了,此时NameNode向DataNode主动发送一次检查,发送一次检查的时间默认5分钟。如果一次检查没有返回信息,这时候NameNode会再进行一次检查,如果还是没有读取不到DataNode的信息,此时判定死亡。也就是说NameNode最终判断DataNode死亡需要$103s+25min=630s$,也就是说NameNode在连续630s中没有得到DataNode的信息才认为当前的DataNode宕机。

所以心跳机制主要要两个用处:

  1. 向NameNode汇报空间信息。
  2. NameNode判断DataNode是否宕机。

安全模式

NameNode启动后会进入一个称为安全模式的特殊状态。处于安全模式的NameNode是不会进行数据块的复制的。NameNode从所有的 DataNode接收心跳信号和块状态报告。块状态报告包括了某个DataNode所有的数据块列表。每个数据块都有一个指定的最小副本数。当NameNode检测确认某个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全(safely replicated)的;在一定百分比(这个参数可配置)的数据块被NameNode检测确认是安全之后(加上一个额外的30秒等待时间),Namenode将退出安全模式状态。接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他DataNode上。

前面已经了解了NameNode的工作机制和SecondaryNameNode的工作机制。在集群启动的时候,NameNode需要加载的元数据包括:1、抽象目录树 2、数据和块的映射关系 3、数据块存储的位置信息。

我们知道元数据即在磁盘存储又在内存存储,但是磁盘里面并没有存储数据库存储的位置信息。这是因为当集群第一次启动的时候,将磁盘元数据加载到内存中,如果磁盘元数据过大,会造成加载到内存的时间过长,所以磁盘只存储抽象目录树和数据和块的映射关系两部分。至于数据块存储的位置信息是通过DataNode的心跳报告获取的,集群在启动的时候NameNode,会接收DataNode的心跳报告,心跳报告中还包含数据块的存储位置信息。这时候NameNode就可以获取DataNode的数据块的存储状况。

1
2
内存存储:1、抽象目录树 2、数据和块的映射关系 3、数据块存储的位置信息
磁盘存储:1、抽象目录树 2、数据和块的映射关系

安全模式下可以查看元数据,例如ls,get,cat命令,但是不能修改元数据(上传文件,创建目录,追加文件,修改文件名)。

在集群维护的时候,也可以手动进入安全模式:

1
2
3
hdfs dfsadmin -safemode enter进入安全模式
hdfs dfsadmin -safemode leave离开安全模式
hdfs dfsadmin -safemode get安全模式是否开启 on:开启 off关闭

负载均衡

HDFS很容易出现负载不均衡的现象,也就是DataNode的磁盘利用率不均衡。例如集群新增节点,集群删除节点。当负载不均衡时,Map任务可能会分配到没有存储数据的机器,这将导致网络带宽的消耗,也无法很好的进行本地计算。当HDFS的负载不均衡时,就需要对HDFS的负载进行调整,让数据均匀的分布在各个DataNode上。其步骤如下:4

  1. 数据均衡服务(Rebalancing Server)首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况;
  2. Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图。数据块迁移路线图,确保网络内最短路径;
  3. 开始数据块迁移任务,源 DataNode复制一块需要移动数据块;
  4. 将复制的数据块复制到目标DataNode上;
  5. 删除原始数据块;
  6. 目标DataNode向源 DataNode确认该数据块迁移完成;
  7. 源Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准。

在第2步中,HDFS会把当前的DataNode节点,根据阈值的设定情况划分到Over、Above、Below、Under四个组中。在移动数据块的时候,Over组、Above组中的块向Below组、Under组移动。四个组定义如下:

Over:在设定的上限阈值之上

Above:在设定的阈值和集群平均值之间

Below:在集群平均值和设置的下限阈值之间

Under:低于下限阈值