理解HDFS文件系统架构和原理

1、Hadoop是一种具体的技术吗?

准确的说,Hadoop是一套大数据的解决方案或者技术栈,不仅仅特指某种大数据技术,由Apache基金会上多个与大数据有关的明星组件构成,包括HDFS(分布式文件系统),YARN(分布式资源调度系统),MapReduce(分布式计算系统)、Spark、Hive、Hbase、Mahout、Zookeeper、Flume等,如下图所示。在这里插入图片描述本文将重点讨论HDFS、YARN以及MapReduce,为何?
设想这么一个场景:
1)、如果T企业每天产生10T的数据,一年为3650T,显然单台服务器是无法存储的,必须分别存放在多台服务器上。HDFS就是负责存放这些超大数据文件的核心组件。
2)、对于初始数据价值密度低的数据文件,T企业需要对其进行数据挖掘,提取高价值密度数据,用以协助调整自身的商业策略,那么这环节会涉及到从多台服务器上读数据、并执行相应的计算、统计逻辑任务(业务代码),这里就涉及如何从多台服务器上的数据计算出一份有价值数据出来呢?这是MapReduce要负责的活。
3)、在MapReduce这一场景中,例如T企业同时运行多个主题的计算任务,如果没有对于多台服务器的cpu+内存+网络吞吐资源进行统一分配、有效管理、回收,那么有可能计算非核心任务a占据集群资源的80%,而核心任务确只能分配到20%计算资源,显然无法达到计算资源最优化,这就是YARN要做的事情。
当然三个组件要负责的具体工作远不止以上的描述,博客将分别发布三篇文章讨论对应以上三个组件。
此外,从Hadoop的演进历史来看:
Hadoop1.0版本为两个核心(分布式存储+计算):HDFS+MapReduce
Hadoop2.0版本,引入了Yarn:HDFS+Yarn+Mapreduce
Yarn是资源调度框架。能够细粒度的管理和调度任务。此外,还能够支持其他的计算框架,比如Spark等。

2、HDFS

一个HDFS集群是由一个Namenode和一定数目的Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点一个,负责管理它所在节点上的存储。HDFS暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。
HDFS 采用Master/Slave的架构来存储数据,这里以下图所示作为说明:
在这里插入图片描述

  • 2.1 Hadoop block块概念
    block是物理的文件,真正存储的位置在磁盘中例如目录:{hadoop.tmp.dir}/data,将客户端上传的完整数据文件切分多个block后存储的块文件
    Hadoop1.0是按64MB切,BlockSize=64MB
    Hadoop2.0 BlockSize=128MB
    文件分块存储,DateNode中存储以数字编号的方块用于备份,每个块都会复制到其他节点上(默认3个节点),如果一个块不可用,可从其它节点读取副本,副本默认为3份,如果配置文件中副本设置为 4 ,而仅有2台Datanode,最后block副本还是2

    对存储小文件,1000个1M的小文件会占用1024个块和1024个 inode,每个1M文件只是占用1个物理文件块中的1M,不会占用整个128M的完整block,但因为inode存储在NameNode的内存里,如果NameNode内存不足以存储更多的inode,那么磁盘也无法存储更多数据block文件,白白浪费存储资源,因此HDFS并不适合存储小文件,务必考虑将小文件合并为大文件,再扔到HDFS上。

补充:inode的内容:文件(这里指代Linux一切皆文件的文件)索引数据结构,inode中主要存储以下这些元数据:
- inode编号

  • 文件大小
  • 占用的块数目与块大小
  • 文件类型(普通文件、目录、管道,etc.)
  • 存储该文件的设备号
  • 链接数目
  • 读、写、执行权限
  • 拥有者的用户ID和组ID
  • 文件的最近访问、数据最近修改时间
  • inode最近修改时间
    其中,inode编号相当于这个结构中的“主键”,说明Linux使用inode编号唯一标识一个文件,通过stat命令可以查看元数据信息,如下图所示。
[root@nn ~]# stat /opt/hadoop-3.1.2/ 
  File: ‘/opt/hadoop-3.1.2/’
  Size: 204             Blocks: 0          IO Block: 4096   directory
Device: fd00h/64768d    Inode: 4216030   Links: 13
Access: (0755/drwxr-xr-x)  Uid: ( 1001/ UNKNOWN)   Gid: ( 1002/ UNKNOWN)
Context: unconfined_u:object_r:usr_t:s0
Access: 2019-1**51.243402848 +0800
Modify: 2019-**:40.433267611 +0800
Change: 2019-**:40.433267611 +0800
 Birth: -

显示块信息命令:

# 显示hdfs目录/app下TJKL.txt数据文件,大小为536M,到底被切分为多少文件块,以及这些文件块的详细情况及其所在位置
[root@nn ~]# hdfs fsck /app -files -blocks -locations -racks
/app/TJKL.txt 562227059 bytes, replicated: replication=3, 5 block(s):  OK
0. BP-1004123743-192.188.0.4-15**1724:blk_1073741912_1096 len=134217728 Live_repl=3  [/default-rack/192.188.0.5:9866, /default-rack/192.188.0.6:9866, /default-rack/192.188.0.4:9866]
1. BP-1004123743-192.188.0.4-15**1724:blk_1073741913_1097 len=134217728 Live_repl=3  [/default-rack/192.188.0.5:9866, /default-rack/192.188.0.6:9866, /default-rack/192.188.0.4:9866]
2. BP-1004123743-192.188.0.4-15**1724:blk_1073741914_1098 len=134217728 Live_repl=3  [/default-rack/192.188.0.6:9866, /default-rack/192.188.0.5:9866, /default-rack/192.188.0.4:9866]
3. BP-1004123743-192.188.0.4-15**1724:blk_1073741915_1099 len=134217728 Live_repl=3  [/default-rack/192.188.0.6:9866, /default-rack/192.188.0.5:9866, /default-rack/192.188.0.4:9866]
4. BP-1004123743-192.188.0.4-15**1724:blk_1073741916_1100 len=25356147 Live_repl=3  [/default-rack/192.188.0.6:9866, /default-rack/192.188.0.5:9866, /default-rack/192.188.0.4:9866]

以上信息说明:TJKL.txt被切分为5个文件块(前4个block都是128M,第5个block为24M),每个文件块都有3个副本,每个副本分别放在同一Rack(机架)上三台服务器上

  • 2.2 Client:连接到hadoop集群的客户端, 或者说使用API或指令操作的一端都可以看做是客户端。
    文件上传 HDFS 的时候,Client 将文件切分成 一个一个的Block,然后进行存储
    与 NameNode 交互,获取文件的位置信息
    与 DataNode 交互,读取或者写入数据,例如使用管道把文件块从上游节点写到下游节点
    Client 提供一些命令来管理 HDFS,比如启动或者关闭HDFS
    Client 可以通过一些命令来访问 HDFS

  • 2.3、NameNode:Master角色,名字节点
    管理元数据信息(Metadata),只存储元数据信息,存放在内存中,会通过fsimage和edits文件,将元数据信息持久化到磁盘上
    管理数据块(Block)映射信息
    配置副本策略
    处理客户端读写请求
    注意:Hadoop1.0版本使用SecondaryNamenode做fsimage和edits文件的合并,但是这种机制达不到热备的效果,即存在单点故障问题,Hadoop2.0解决了该缺点。

  • 2.4 fsimage、edits
    fsimage 文件,记录元数据信息的文件edits文件,记录元数据信息改动的文件。只要元数据发生变化,这个edits文件就会有对应记录。
    fsimage和edits文件会定期做合并,这个周期默认是3600s。fsimage根据edits里改动记录进行元数据更新。
    元数据信息如果丢失,HDFS就不能正常工作了,因此在生产环境中,元数据是需要做备份的。
    hadoop集群部署中,命令hadoop namenode -format 执行时,创建了初始的fsimage文件和edits文件,如下所示:

[root@nn current]# pwd
/opt/hadoop-3.1.2/namenode/current
......
edits_0000000000000000556-0000000000000000557  fsimage_0000000000000001186
edits_0000000000000000558-0000000000000000655  fsimage_0000000000000001186.md5
  • 2.5 Secondary Namenode
    辅助 NameNode,分担其工作量。
    定期合并 fsimage和fsedits,并推送给NameNode。
    在紧急情况下,可辅助恢复 NameNode。
    Hadoop集群最开始启动的时候,创建Fsimage和edits文件,这个namenode负责,此外,namenode会做一次文件合并工作,这么做的目的是确保元数据信息是最新的,之后的合并工作,就交给SN去做了。这种SN机制是Hadoop1.0的机制,该机制达不到元数据的实时更新,若NN宕机,元数据信息可能还会丢失。

  • 2.6、DataNode:Slave角色,具体干活者,NameNode下发指令操作,DataNode 执行实际的操作
    存储实际的物理数据块block。
    执行数据块的读/写操作。
    为了防止datanode挂掉造成的数据丢失,对于文件块要有备份,一个文件块有三个副本。这里体现出hdfs是一种高容错的文件系统。
    在服务器上的构成:

[root@dn1 subdir0]# pwd
/opt/hadoop-3.1.2/datanode/current/BP-1004123743-192.188.0.4-***current/finalized/subdir0/subdir0
......
blk_1073741876_1052.meta  blk_1073741901_1078.meta  blk_1073741916_1100.meta
blk_1073741877            blk_1073741902
blk_1073741877_1053.meta  blk_1073741902_1079.meta
  • 2.7 Rack:hadoop集群服务器机架

  • 2.8 HDFS写文件流程图
    在这里插入图片描述

    1)、发起一个写数据请求,并指定上传文件的路径,然后去找NN。NN首先会判断路径合法性以及客户端是否有写权限,若符合,则NN会给客户端返回一个输出流。此外,NN会为文件分配块存储信息(理解为记录block文件位置大小等信息的索引文件)。注意NN也是分配块的存储信息,但不做物理切块工作。

    2)、客户端拿到输出流以及块存储信息之后,就开始向DN节点写数据。因为一个块数据,有三个副本,所以图里有三个NN节点。
    3)、数据块的发送(管道发送或者接力棒传递方式),先发给第一台DN节点,数据再从第一台DN发往第二台DN,……,此方式用到了pipeLine 数据流管道的机制,就像redis发送管道命令,然后批量返回结果,从而减少网络来回RTT时间消耗。
    pipeLine:[bl1,datanode01-datanode02-datanode-03]
    数据流管道充分利用每台机器的带宽,避免网络瓶颈和高延时的连接,最小化推送所有数据的延时,提高传输效率。
    packet 默认为64kb大小的数据包

    4)、通过ack确认机制,向上游节点发送确认,例如DN3向DN2ack说我已写好数据,DN2继续向DN1说我已写好数据,DN1再跟客户端说:数据块已经在DN1、DN2、DN3都存储好,这么做的目的是确保块数据复制的完整性。

    5)、通过最上游节点DN1,向客户端发送ack,如果块数据没有发送完,客户端会就继续发送下一块,直到所有块数据都已发完,关闭文件关流。

    6)、所有块数据都写完后,关闭文件流。

  • 2.8 hadoop读取文件流程图

  • 在这里插入图片描述
    1)、客户端发出读数据请求,Open File指定读取的文件路径,在NN节点获取元数据信息。
    2)、NN将目标文件的元数据信息返回给客户端。
    3)、客户端根据返回的元数据信息,去对应的DN去读块数据。
    假如一个文件特别大,比如1TB,会分成好多块,此时,NN并是不一次性把所有的元数据信息返回给客户端,而是分节点返回。
    4)、客户端读完此部分后,再向NN节点要下一部分的元数据信息,再接着读。
    5)、读完之后,通知namenode关闭流

3、再讨fsimage和editlog

  • NameNode通过组织两个核心数据结构:“FSImage”和“EditLog”文件,实现维护文件系统树内所有文件和目录,记录每个文件在哪个DateNode的位置和副本信息,来通知客户端应该去哪个节点访问文件blocks。

  • fsImage_*:元数据镜像文件,即系统的目录树,包括文件目录和inodes元信息(文件名,文件大小,创建时间,备份级别,访问权限,block size,所有block的构成),每个inode是hdfs的一个代表文件或者目录的元数据。这个镜像文件相当于hdfs的元数据额数据库文件。

  • edits_*:编辑日志文件,也就是事务日志文件,也就是针对文件系统做的修改操作记录,记录元数据的变化,相当于操作日志文件。一个文件的创建,追加,移动等。 NameNode内存中存储的是=fsimage+edits 检查点:NameNode启动时,从磁盘中读取上面两种文件,然后把edits_*里面记录的事务全部刷新到 fsimage_*中,这样就截去了旧的edits_*事务日志,这个过程叫checkpoint。

  • 为何使用一大一小两种数据结构的文件? 因为fsimage本身是大文件,试想你要向大文件每时每刻open file–>append new line–> close file,也太累了吧。因此可把新来的操作记录放到小的EditLog里, 再设定每隔一段时间,把一个FsImage和一个Editlog 进行合并会得到一个新的FsImage。

  • fsimage中存储的信息就相当于整个hdfs在某一时刻的一个快照,既然这个快照可以管理整个hdfs集群的文件信息,那么对其备份则非常重要,于是
    引入一个叫SendaryNamenode的节点用来做备份fsimage,它会定期的和namenode就行通信来完成整个的备份操作,具体工作原理见第4点:

4、SecondaryNameNode合并FSImage
在这里插入图片描述为何NN节点不负责合并工作而是由其他节点服务器来运行此任务?
因为这两个文件合并过程需要消耗内存、磁盘io以及cpu,因此将这些“蓝领”工作交给其他节点做,否则NN主节点消耗大量资源。
具体流程:
1)、SN定时和NN通信chectpoint,在什么时候进行checkpoint?由两个参数dfs.namenode.checkpoint.preiod(默认值是3600,即1小时)和dfs.namenode.checkpoint.txns(默认值是1000000)来决定),通过请求NN其停止使用edits文件,暂时将新的操作写到一个新的edits.new文件
2)、SN通过HTTP GET方式从NN上获取到fsimge和edits文件,并下载到本地的相应目录下;
3)、SN将下载下来的fsimage载入到内存,然后一条一条地执行edits文件中的各项更新操作,使得内存中的fsimge保持最新;这个过程就是edits和fsimage文件合并,同时SN节点也会在磁盘上存放一份fsimage(不就实现了fsimage的备份吗)
4)、SN执行完(3)操作之后,会通过HTTP POST方式将新的fsimage文件发送到NN节点上
5)、 NN将从SN接收到的新的fsimage替换掉旧fsimage文件,同时将edits.new替换edits文件,通过这个过程edit内容就变小而且都是最新的操作日志。

5、文件blocks副本存放策略
NN节点如何选择在哪个datanode 存储block副本?
这里需要对可靠性、写入带宽和读取带宽进行权衡。Hadoop对DN存储副本有自己的副本策略,在其发展过程中一共有两个版本的副本策略,分别如下所示:
在这里插入图片描述

发布了52 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/pysense/article/details/102557720