分布式文件系统:HDFS 核心原理

目录node

基础架构算法

HDFS Client缓存

NameNode和DataNode安全

fsimage和editsbash

SecondaryNameNode服务器

高可用架构网络

JournalNode架构

联邦机制分布式

副本机制工具

机架感知

安全模式

平衡策略

读写原理

读原理

写原理

删除恢复机制


HDFS相关内容:

  1. HDFS超有用的知识点
  2. Hadoop3新特性之HDFS纠删码
  3. HDFS经常使用管理命令
  4. HDFS的副本数量配置
  5. HDFS查看namenode状态
  6. 统计HDFS目录下文件行数及文件大小

基础架构

HDFS(Hadoop Distributed File System)是 Apache Hadoop 项目的一个子项目,Hadoop 很是适于存储大型数据, 其就是使用 HDFS 做为存储系统,而HDFS 使用多台计算机存储文件,而且提供统一的访问接口,像是访问一个普通文件系统同样使用分布式文件系统。做为大数据生态最重要的组件之一,HDFS充当着大数据时代的数据管理者的角色,为各类分布式计算组件提供用于处理的数据存储的能力。

HDFS 基础架构由四个角色组成:HDFS Client、NameNode、DataNode 和 SecondaryNameNode

HDFS Client

HDFS客户端提交读写命令到HDFS,它负责:

  • 文件切分文件上传 HDFS的时候,Client 将文件切分红一个个Block(数据块),而后进行存储。
  • 与 NameNode 交互获取文件真实的位置信息。
  • 与 DataNode 交互读取或写入数据。
  • Client 提供一些命令来管理 和访问HDFS,好比启动或者关闭HDFS。

NameNode和DataNode

NameNode 是HDFS的Master节点,它负责:

  • 管理 HDFS 的名称空间;
  • 管理数据块(Block)映射信息;
  • 配置副本策略;
  • 处理客户端读写请求;
  • 周期性的接收心跳和块的状态信息报告;

 DataNode 是HDFS的Slave节点,它负责:

  • 存储实际的数据块;
  • 执行数据块的读/写操做; 
  • 周期性向NameNode汇报心跳信息;
  • 周期性向NameNode汇报数据块信息;
  • 周期性向NameNode汇报缓存数据块信息;

fsimage和edits

在Hadoop集群当中,NameNode的全部元数据信息都保存在fsimage 与 edits 文件中, 这两个文件记录了全部的数据的元数据信息,当集群重启时NameNode首先会从fsimage和edits文件中将元数据信息加载到内存中,所以NameNode机器对内存的要求相对会比DataNode高不少,元数据信息的保存目录配置在了 hdfs-site.xml 中的这两个参数:dfs.namenode.name.dir,dfs.namenode.edits.dir。

edits

  • 存放了客户端最近一段时间的操做日志;
  • 客户端对 HDFS 进行写文件时的操做会先被记录在 edits 文件中;
  • edits 修改时元数据也会更新;

fsimage

  • NameNode 中关于元数据的镜像,通常称为检查点,fsimage 存放了一份比较完整的元数据信息;
  • 由于 fsimage 是 NameNode 的完整的镜像, 若是每次都加载到内存生成树状拓扑结构,这是很是耗内存和CPU, 因此通常开始时对NameNode 的操做都放在 edits 中;
  • fsimage 内包含了 NameNode 管理下的全部 DataNode 文件和文件 block 以及 block所在的 DataNode 的元数据信息;
  • 随着 edits 内容增大,就须要在必定策略下和 fsimage 合并;

因为集群重启时NameNode会从新加载fsimage和edits文件,fsimage文件加载起来很快,但edits文件内记录的都是操做日志,所以edits文件不能无限增加,不然重放日志很慢,会影响到集群启动的速度,所以edits文件和fsimage会按期进行合并。

SecondaryNameNode

SecondaryNameNode不是NameNode 的热备。当NameNode 挂掉的时候,它并不能立刻替换 NameNode 并提供服务,而是做为一个辅助者分担NameNode的工做量。在后面的内容中介绍的HDFS的高可用中会介绍真正的NameNode热备机制。

  • 按期合并 fsimage和edits,并推送给NameNode,把 edits 控制在一个范围内。
  • 在紧急状况下,可辅助恢复 NameNode。

上面提到edits文件会根据必定策略和fsimage合并,主要由core-site.xml文件中的两个参数来管理:

<!-- 多久记录一次 HDFS 镜像, 默认 1小时 -->
<property>
  <name>fs.checkpoint.period</name>
  <value>3600</value>
</property>
<!-- 一次记录多大, 默认 64M -->
<property>
  <name>fs.checkpoint.size</name>
  <value>67108864</value>
</property>

当edits和fsimage文件合并策略触发时,合并流程以下:

  1. SNN(SecondaryNameNode)通知NN(NameNode)暂时切换将日志写到edits.new内;
  2. SNN经过GET请求将NN中的edits和fsimage文件加载到内存中;
  3. SNN将内存中的edits和fsimage合并生成新的fsimage.ckpt文件;
  4. SNN经过POST请求将生成的fsimage.ckpt文件传给NN;
  5. NN将收到的fsimage.ckpt替换旧的fsimage文件;
  6. NN将edits.new替换旧的edits文件;

高可用架构

JournalNode

上面咱们介绍的都是HDFS的基础架构,从上面的内容中咱们也能够看出,NameNode对于HDFS很重要,整个HDFS文件系统的元数据信息都由NameNode来管理,NameNode的可用性直接决定了Hadoop 的可用性,一旦NameNode进程不能工做了,就会影响整个集群的正常使用。所以在Hadoop2.x版本中加入了HDFS HA的特性,在典型的HA集群中,两台独立的机器被配置为NameNode。在工做集群中,NameNode机器中的一个处于Active状态,另外一个处于Standby状态。Active NameNode负责群集中的全部客户端 操做,而Standby充当从服务器,Standby机器保持足够的状态以提供快速故障切换。

两个NameNode为了数据同步,会经过一组称做JournalNodes的独立进程进行相互通讯。当Active 状态的NameNode的命名空间有任何修改时,会告知大部分的JournalNodes进程。Standby 状态的NameNode有能力读取JNs中的变动信息,而且一直监控edit log的变化,把变化应用于本身的命名空间。Standby 能够确保在集群出错时,命名空间状态已经彻底同步了 ,以此达到快速故障切换。

HA架构下,SecondaryNameNode被JournalNode替代,实现两个NameNode之间的信息同步,由Zookeeper实现两个NameNode之间的高可用,相关的组件以下:

  • ZKFailoverController是基于Zookeeper的故障转移控制器,它负责控制NameNode的主备切换,ZKFailoverController会监测NameNode的健康状态,当发现Active NameNode出现异常时会经过Zookeeper进行一次新的选举,完成Active和Standby状态的切换;
  • HealthMonitor周期性调用NameNode的HAServiceProtocol RPC接口(monitorHealth 和 getServiceStatus),监控NameNode的健康状态并向ZKFailoverController反馈;
  • ActiveStandbyElector接收ZKFC的选举请求,经过Zookeeper自动完成主备选举,选举完成后回调ZKFailoverController的主备切换方法对NameNode进行Active和Standby状态的切换;
  • DataNodeNameNode包含了HDFS的元数据信息和数据块信息(blockmap),为了确保快速切换,Standby 状态的NameNode有必要知道集群中全部数据块的位置。为了作到这点,全部的DataNode必须配置两个NameNode的地址,同时发送数据块位置信息和心跳给他们两个。 
  • 共享存储系统(JournalNode)共享存储系统负责存储HDFS的元数据(EditsLog),Active NameNode(写入)和 Standby NameNode(读取)经过共享存储系统实现元数据同步,在主备切换过程当中,新的Active NameNode必须确保元数据同步完成才能对外提供服务;对于HA集群而言,确保同一时刻只有一个NameNode处于active状态是相当重要的。不然,两个NameNode的数据状态就会产生分歧,可能丢失数据,或者产生错误的结果。为了保证这点,JNs必须确保同一时刻只有一个NameNode能够向本身写数据。

Hadoop3.x版本中的新特性容许2个以上的NameNode节点,该功能可以经过运行更多Standby NameNode来提供更高的容错性,知足一些部署的需求。好比,经过配置3个NameNode和5个JournalNode,集群可以知足容许两个节点故障的容错。

联邦机制

虽然HA模式保证了NameNode的高可用,但HDFS中其实最严重的问题就是小文件过多致使的NameNode维护的元数据信息过多,由此引发的性能降低的问题,所以不管在MapReduce仍是Spark程序中都应当尽可能避免产生过多小文件。同时HDFS也推出了NameNode的水平扩展方案:联邦机制(Federation)

HDFS联邦机制表示有多个NameNode,但和HA模式下的多个NameNode的意思不一样,在HA模式下的NameNode是主备的概念,而联邦机制中的多NameNode相似分管,表示某个NameNode管理某块命名空间(namespace)内的元数据信息,将原本大量的元数据信息分散在多个NameNode上进行管理,它们之间相互独立不须要互相协助,各自分工,管理本身的区域。

 

同一个namespace下的block集合被称为Block Pool(存储池),所以在联邦机制下,每一个NameNode对应一个Block Pool,对应到DataNode中就是一个个的Block Pool,分别有对应的ID,这时候在DataNode上就不只仅存储一个Block Pool下的数据了,而是多个,且存储在DataNode的datadir路径里的名为BP-xx.xx的目录。

联邦机制的好处是,多个NameNode共有一个集群里的存储资源,且每一个NameNode均可以单独对外提供服务,解决了单个Active NameNode的内存瓶颈问题。但联邦仍是没有解决单点故障的问题,假如维护namespace为BP-003的NameNode宕机,则客户端也没法读取DataNode中的/BP-003的数据,所以当集群规模较大的时候,应采用HA+Federation的部署方案,即上图中每一个Active NameNode都对应了一个Standby NameNode提高可用性。

副本机制

HDFS中的文件以Block块的形式存储在HDFS文件系统中,目的为:

  • 一个文件有可能大于集群中任意一个磁盘,引入块机制,能够很好的解决这个问题;
  • 使用块做为文件存储的逻辑单位能够简化存储子系统;
  • 块很是适合用于数据备份,提供数据容错能力;

在 Hadoop1.x 当中, 文件的 block 块默认大小是 64M,在Hadoop2.x中, 文件的 block 块大小默认是128M, block 块的大小和副本数量能够经过 hdfs-site.xml 当中的配置文件进行指定:

<!-- 块大小,单位为字节 -->
<property>
    <name>dfs.block.size</name>
    <value>134217728</value>
</property>

<!-- 副本数量,默认3个副本 -->
<property>
    <name>dfs.replication</name>
    <value>3</value>
</property>

注意

  • 当文件大于配置的块大小时会被拆分,如130M的文件会被拆分为两个块,一个128M另外一个2M。
  • 当文件小于配置的块大小时不会拆分,如100M的文件不会拆分,只有一个100M的块。 

机架感知

分布式的集群一般包含很是多的机器,因为受到机架槽位和交换机网口的限制,一般大型的分布式集群都会跨好几个机架,由多个机架上的机器共同组成一个分布式集群。机架内的机器之间的网络速度一般都会高于跨机架机器之间的网络速度,而且机架之间机器的网络通讯一般受到上层交换机间网络带宽的限制。

Hadoop在设计时考虑到数据的安全与高效,数据文件默认在HDFS上存放三份,存储策略为:

  1. 第一个block副本放在客户端所在的数据节点里(若是客户端不在集群范围内,则从整个集群中随机选择一个合适的数据节点来存放);
  2. 第二个副本放置在与第一个副本所在节点不一样的机架内的数据节点上(随机选择);
  3. 第三个副本放置在不一样机架的节点上;
  4. 若是还有其余副本,则随机放在其余节点上;

这样设计的好处是:

  • 当本地数据损坏时,节点能够从同一机架内的相邻节点拿到数据,速度确定比从跨机架节点上拿数据要快;
  • 当整个机架的网络出现异常,也能保证在其它机架的节点上找到数据;

为了下降总体的带宽消耗和读取延时,HDFS会尽可能让程序读取离它最近的节点上的副本,以节约带宽和提高性能。HDFS经过机架感知这一特性实现此功能。

在默认状况下,机架感知没有被启用,全部的机器hadoop都默认在同一个默认的机架下,名为 “/default-rack”,这种状况下,任何一台datanode机器,无论物理上是否属于同一个机架,都会被认为是在同一个机架下,此时,就很容易出现增添机架间网络负载的状况。由于此时hadoop集群的HDFS在选机器的时候,是随机选择的,也就是说,颇有可能因为副本的随机分配致使大量的网络传输从而影响性能和集群的服务。

经过修改配置文件core-site.xml 中的参数 topology.script.file.name 开启机架感知,value指定为一个可执行程序,一般为一个脚本(根据入参IP返回该IP地址对应的datanode所在的rack)。

:网络拓扑以下图:

开启机架感知后,NameNode就能够画出上图所示的datanode网络拓扑图。D1,R1都是交换机,最底层是datanode。则H1的rackid=/D1/R1/H1,H1的parent是R1,R1的parent是D1。有了这些rackid信息就能够计算出任意两台datanode之间的距离。

distance(/D1/R1/H1,/D1/R1/H1)=0  相同的datanode
distance(/D1/R1/H1,/D1/R1/H2)=2  同一rack下的不一样datanode
distance(/D1/R1/H1,/D1/R1/H4)=4  同一IDC下的不一样datanode
distance(/D1/R1/H1,/D2/R3/H7)=6  不一样IDC下的datanode

安全模式

安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式,当系统处于安全模式时会检查数据块的完整性。

假设咱们设置的副本数(即参数dfs.replication)是5,那么在datanode上就应该有5个副本存在,假设只存在3个副本,那么比例就是3/5=0.6。在配置文件hdfs-default.xml中定义了一个最小的副本的副本率0.999,咱们的副本率0.6明显小于0.99,所以系统会自动的复制副本到其余的dataNode,使得副本率不小于0.999.若是系统中有8个副本,超过咱们设定的5个副本,那么系统也会删除多余的3个副本。

在安全模式下,系统会处于只读状态,NameNode不会处理任何数据块的复制和删除命令。DataNode会向NameNode上传他们数据块的列表,让NameNode获得数据块的位置信息,并对每一个文件对应的数据块副本进行统计:

  • 当最小副本条件知足时,即:必定比例的数据块都到达最小副本数,系统会在30s后退出安全模式。
  • 当最小的副本条件未达到要求时,就会对副本数不足的数据块安排DataNode进行复制,直到达到最小的副本数。

注意:在启动一个刚刚格式化的HDFS时因为没有数据块,因此系统不会进入安全模式。

HDFS安全模式操做命令:

hdfs dfsadmin  -safemode  get #查看安全模式状态
hdfs dfsadmin  -safemode enter #进入安全模式
hdfs dfsadmin  -safemode leave #离开安全模式

安全模式相关参数在hdfs-site.xml 文件中配置:

<!-- 指定退出条件,须要达到最小副本数的数据块比例,默认是 0.999 -->
<property>
    <name>dfs.namenode.safemode.threshold-pct</name>
    <value>0.999f</value>
</property>

<!-- 指定系统退出安全模式时须要的延迟时间,单位为毫秒,默认为 30s -->
<property>
    <name>dfs.namenode.safemode.extension</name>
    <value>30000</value>
</property>

若是 NameNode 长时间处于安全模式,多是由于 hdfs 的数据损坏过多。使用命令hadoop fsck / 检查 hdfs 文件分布的状况。

平衡策略

在HDFS的DN节点间的数据不平衡状况下,尤为在新增和下架节点、或者人为干预副本数量的时候,会大大的影响数据读取的性能,下降任务的执行速度甚至崩溃,所以HDFS有一个组件叫作Balancer,使用该组件能够保证每一个节点的数据均衡分布

#开始数据平衡:
#用默认的10%的阈值启动balancer
start-balancer.sh    
#或指定3%的阈值启动balancer
hdfs dfs balancer -threshold 3
start-balancer.sh -threshold 3    

#中止数据平衡:
stop-balancer.sh

hdfs balancer
      [-threshold <threshold>]
      [-policy <policy>]
      [-exclude [-f <hosts-file> | <comma-separated list of hosts>]]
      [-include [-f <hosts-file> | <comma-separated list of hosts>]]
      [-idleiterations <idleiterations>]

-threshold  10      #集群平衡的条件,datanode间磁盘使用率相差阈值,区间选择:0~100。Threshold参数为集群是否处于均衡状态设置了一个目标
-policy datanode    #默认为datanode,datanode级别的平衡策略
-exclude  -f  /tmp/ip1.txt  #默认为空,指定该部分ip不参与balance, -f:指定输入为文件
-include  -f  /tmp/ip2.txt  #默认为空,只容许该部分ip参与balance,-f:指定输入为文件
-idleiterations  5          #最大迭代次数,默认为 5

可选的配置参数以下:

#并行移动的block数量,默认5
dfs.datanode.balance.max.concurrent.moves

#Balance工具所占用的带宽,默认1048576(1MB)
dfs.datanode.balance.bandwidthPerSec

#用于执行block移动的线程池大小,默认1000
dfs.balancer.moverThreads

#每次balance进行迭代的过程最大移动数据量,默认10737418240(10GB)
dfs.balancer.max-size-to-move

#获取block的数量,默认2147483648(2GB)
dfs.balancer.getBlocks.size

#用来平衡的最小block大小,默认10485760(10MB)
dfs.balancer.getBlocks.minblock-size

平衡算法根据各Datanode的使用状况,将集群中的节点分为四类:过分闲置、平均值如下、平均值以上、过分使用

而后根据划分的角色进行配对:

  • 过分使用--> 过分闲置
  • 过分使用-->平均值下
  • 平均值上-->过分闲置

为了保证HDFS数据安全性,数据块移动策略以下:

  1. 源DataNode的存储类型和目的DataNode的存储类型一致;
  2. 该block的副本未被安排;
  3. 目的DataNode不包含一样的副本;
  4. 移动以后该机架上的block不会减小;

根据角色配对以及移动策略,Balancer数据均衡流程为:

  1. 与NameNode交互,获取DataNode磁盘使用状况;
  2. 根据数据分布状况对DataNode进行角色划分并配对;
  3. 根据移动策略从源DataNode移动block到目标DataNode,并删除源DataNode上的block;
  4. 获取移动结果,并继续移动其余数据块,直到没有数据能够移动或者HDFS集群以及达到了平衡的标准为止,而后向NameNode提交更新后的DataNode信息;

当触发下面的条件时,Balancer会自动退出:

  1. 集群已达到均衡状态;
  2. 没有block能被移动;
  3. 连续5次(参数:idleiterations) 迭代移动没有任何一个block被移动;
  4. 当与NameNode交互时出现了IOException;
  5. 另外一个Balancer进程在运行中。

读写原理

读原理

客户端向HDFS发送读取文件的请求完整流程以下:

  1. 客户端向NN提交读请求;
  2. NN进行权限检查、获取文件块列表:{blk_a_1: dn1,dn2,dn4 ;blk_a_2: dn2,dn3,dn4}
  3. NN根据机架感知将距离客户端最近的文件块所在的DN列表返回给客户端:{blk_a_1:dn1, blk_a_2:dn2}
  4. 客户端和每一个block所在的DN创建管道;
  5. 客户端读取数据,以数据包packet(64k)进行传输;
  6. 客户端将接收到的block合并为一个完整的文件;

NameNode会视状况返回文件的部分或者所有block列表,对于每一个block,NameNode 都会返回含有该 block 副本的 DataNode 地址; 这些返回的 DN 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,而后进行排序,排序两个规则:网络拓扑结构内距离Client 近的排靠前;心跳机制中超时汇报的 DN 状态为 STALE,这样的排靠后;以此来提高网络传输的效率。

客户端选取排序靠前的 DataNode 来读取 block,若是客户端自己就是DataNode,那么将从本地直接获取数据(短路读取)。

每读取完一个 block 都会进行 checksum 验证,若是读取 DataNode 时出现错误,客户端会通知 NameNode,而后再从下一个拥有该block 副本的DataNode 继续读。

写原理

客户端向HDFS发送上传文件的请求完整流程以下:

  1. 客户端向NameNode提交写请求;
  2. NN进行权限检查、判断是否知足写条件;
  3. NN返回信息:能够上传;
  4. 客户端根据HDFS的块策略将文件切分为n个block文件块;
  5. 请求上传第一个文件块blk_a_1;
  6. 根据DN上的block信息和机架感知,选出能够上传的DN列表:(dn1,dn2,dn4);
  7. NN返回可上传的DN列表(dn1,dn2,dn4);
  8. 客户端和DN创建数据传输管道,上传的DN之间也创建管道;
  9. 客户端向DN以数据包packet(64k)传递数据,dn1收到一个packet会传给dn2,dn2收到会传给dn4,每传一个packet会放入一个应答队列等待应答;
  10. DN将收到的packet数据包进行缓存;
  11. 在管道的反方向上, DN逐个发送 ack(命令正确应答), 最终由管道中第一个DN节点dn1将ack发送给客户端;
  12. 当文件块block的packet传输完成则将缓存的临时文件放置在指定的HDFS上传路径;
  13. 继续上传其他的block文件块;

删除恢复机制

当从HDFS中删除某个文件时,这个文件并不会马上从HDFS中删除,而是将这个文件重命名并转移到回收站 /trash目录,只要这个文件还在/trash目录下,该文件就能够迅速被恢复。回收站的位置在HDFS上的/user/$USER/.Trash/Current/ 

文件在/trash目录中存放的时间默认为6个小时,当超过这个时间时,NN就会将文件从名称空间中删除;

删除文件会使得该文件相关的数据块被释放;注意:从用户删除文件到HDFS空闲空间的增长之间会有必定时间的延迟;

经过修改hdfs-site.xml文件中下面的配置能够修改回收站过时的时间:

#时间单位是秒
<property>
    <name>fs.trash.interval</name>
    <value>1440</value>
</property>

但愿本文对你有帮助,请点个赞鼓励一下做者吧~ 谢谢!

相关文章
相关标签/搜索