前言
HDFS是Hadoop体系的基础,不知道各位怎么对待HDFS。反正我更多的关注一些应用层的东西,对于HDFS多有忽视。
但是每次面试的时候都要重新去背面经,我觉得这样的情况不太正常,因此耗时两天半整理了HDFS的知识体系,力求知其然也要知其所以然。
文章中有不少个人思考,希望能让各位更好的理解HDFS.
一、HDFS特性
高容错性:HDFS认为硬件总是不可靠的。
高吞吐量:HDFS为大量数据访问的应用提供了高吞吐量支持。
大文件存储:HDFS支持存储TB甚至PB级别的数据。
高度关注这个容错性,这个风格灌输HDFS设计的始终。至于大文件存储和高吞吐量,那玩意儿现在是个框架都支持。我个人认为高容错性是这个HDFS体系最强烈的风格。
二、HDFS架构
HDFS架构包含三个部分:NameNode,DataNode,Client。他们职责分别如下:
NameNode:主节点,名称节点,NameNode用于存储、生成文件系统的元数据。运行一个实例。
DataNode:从节点,数据节点,DataNode用于存储实际的数据,将自己管理的数据块上报给NameNode ,运行多个实例。
Client:支持业务访问HDFS,从NameNode ,DataNode获取数据返回给业务。多个实例,和业务一起运行。
在我个人的理解中:NameNode相当于我们的桌面快捷方式。DataNode则是电脑里面的存储单元。Client则是操作系统。
三、基本定义
3.1元数据(Metadata):
保存文件属性的数据,如文件名,文件长度,文件所属用户组,文件存储位置等。
元数据类似于文件索引,相当于我们电脑上应用的快捷方式。
元数据长什么样子?
元数据用来维护文件与数据块之间映射关系的数据结构,简单来说它应该是类似以下一个key-value形式的数据。
这个只是我理解的元数据的样子,key为文件名.value为块Blk,一个快有在多个数据节点DN有备份。
3.2数据块(Block):
存储文件的最小单元,一般为64M或者128M。对存储介质划分了固定的区域,使用时按这些区域分配使用。
数据块类似于Bit,或者字节,数据块存储的是实际的文件数据。
好的,问题来了:
3.2.1为什么一定要用数据块为存储单位?
在大数据的处理场景,TB甚至PB级别的大文件是经常能遇到的。假如我们要上传这样一个PB级的文件,没有任何一块磁盘能够存储,这样这个文件就没法上传了。
但如果我们使用块的概念把文件分割成许多块,这样这个文件可以使用计算机集群中的任意计算机节点进行存储。
当有文件上传到HDFS上时,若文件大小大于块的大小,则该文件会被切分存储为多个块,多个块可以存放在不同的DataNode上,整个过程中 HDFS系统会保证一个块存储在一个datanode上 。但值得注意的是 如果某文件大小没有到达块的大小,该文件并不会占据整个块空间。即,多个文件可共用一个块。
3.2.2数据块的其他优势
1. 数据存储要考虑容灾备份,以块为单位比较容易进行备份,HDFS默认每个块备份3份,这样如果这个块上或这个节点坏掉,可以直接找其他节点上的备份块。
非重点,仅了解:
一般来说这三份分别是本身一份,同机架下不同节点放一个副本,不同机架下放一个副本。这样的备份策略主要是为了兼顾网络传输开销和数据安全。
1.如果本机数据损坏或者丢失,那么客户端可以从同机架的相邻节点获取数据,速度肯定要比跨机架获取数据要快。
2.如果本机所在的机架出现问题,那么之前在存储的时候没有把所有副本都放在一个机架内,这就能保证数据的安全性,此种情况出现,就能保证客户端也能取到数据。
2. 数据块备份数目可变,增加备份数量不仅更安全,而且能够明显分散机群的读取负载,因为可以在多个节点中寻找到目标数据,减少单个节点读取。
这里还要注意一点,这个块的大小不是随机定义的:
3.2.3为什么块的大小设置为64MB或者128MB?
磁盘是由数据块组成的,一般默认大小是512字节,构建磁盘之上的文件系统一般是磁盘块的整数倍。
HDFS将数据块设置的这么大最主要的目的是为了最小化寻址时间。
“HDFS的块比磁盘块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间可以明显大于定位这个块开始位置所需的时间。这样,传输一个由多个块组成的文件的时间就取决于磁盘传输速率。”
“我们做一个估计计算,如果寻址时间为10ms左右,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们需要设置块大小为100MB左右。而默认的块大小实际为64MB,但是很多情况下HDFS使用128MB的块设置。以后随着新一代磁盘驱动器传输速率的提升,块的大小将被设置得更大。”
“但是,该参数也不会设置得过大。MapReduce中的map任务通常一次处理一个块中的数据,因此,如果任务数太少(甚至少于集群中的节点数量),作业的map变少,运行速度就会变慢。” —-《Hadoop权威指南》
总结: 块越大,定位文件的寻址时间越短,总体的文件传输速率取决于磁盘传输速率。随着磁盘传输速率不断提升,块也从64MB变为了128MB,甚至也出现了256MB的块的设置。
为什么块不能设置的过小?
1. 这里一方面是为了最小化寻址时间
2. 另一方面NameNode的元数据维护文件存储映射关系,如果块小而多的话,NameNode的内存就扛不住了。这同样也是为什么HDFS不适合大量小文件存储的原因。
为什么块不能设置的过大?
1.MapReduce中的map任务通常一次处理一个块中的数据,因此,如果任务数太少(甚至少于集群中的节点数量),作业的map变少,运行速度就会变慢。
2.数据块过大,文件写入的过程会增加传输管道的运行时间,在此期间如果出现故障中断任务会增加服务开销。(个人思考,非官方回答)
四、名称节点工作原理
参考文章:Hadoop之 HDFS的名称节点与数据节点(FsImage、EditLog)hadoop计算节点和数据节点无糖饮料就一定无糖吗的博客
名称节点负责管理分布式文件系统的命名空间,它保存了两个核心的数据结构——FsImage、EditLog;
命名空间听起来唬人,其实简单理解就是Linux的root。
4.1HDFS命名空间、FsImage、EditLog的基本功能解析
- HDFS命名空间:目录、文件、块。命名空间管理就是指对HDFS中目录、文件、块做类似文件系统的创建、修改、删除等基本操作。
- FsImage:维护文件系统树以及文件树中的文件和文件夹的元数据。
- EditLog:记录针对文件的创建、删除、重命名等这样的更新操作;
这里有个问题,为什么一定要是这样的设计,这样的设计有什么深意?
4.2为什么一定要用FsImage,EditLog的组合?
这个问题没有找到很好的标准答案,文件系统镜像(Fsimage)是Hadoop HDFS的一个核心组件,它记录了文件系统的元数据信息,包括文件和目录的名称、权限、大小、时间戳等。但是,如果在FsImage生成之后,文件系统发生了新的更改,那么这些更改将无法被记录在FsImage中。
因此,为了确保最新的更改被记录,我们需要定期生成新的Fsimage文件,并将其与此前的FsImage文件进行比较,以确定哪些更改是新的,需要被记录。
他这里的解析简直就像放屁。有一个很明显的逻辑缺陷,就是没有解释为什么不直接写入FsImage?
为什么新的更改将无法被记录在FsImage中?
1.FsImage无法记录新变化的一个可能原因是FsImage是一个静态文件,记录了某个时间点的文件系统元数据。(从他的名字也可看出来,镜像文件嘛)
2.FsImage文件一般都很大(GB级别的很常见),如果所有的更新操作都往FsImage文件中添加,这样会导致系统运行的十分缓慢
4.3FsImage、EditLog工作原理:
名称节点运行期间,HDFS内的更新操作被写入到EditLog文件中,随着更新操作的不断发生,EditLog也将不断变大。
名称节点在每次重启时,将FsImage加载到内存中,再逐条执行EditLog中的记录,使FsImage保持最新状态。
但是这样会面临一个问题,EditLog的记录如果很多的话就会导致名称节点加载他的过程中启动过慢,影响正常服务的效率。
仔细思考下,如何解决它?其实这是很简单的一个问题,定期清理EditLog更新FsImage就可以了。
EditLog过大怎么办?
定期清理EditLog更新FsImage。这个定期其实可以设置成固定的周期,如一天清理一次,一周清理一次,可根据具体情况具体调整;也可以设置一个阈值,EditLog高于此阈值就开始进行清理。
我们知道FsImage是一个静态文件,因此不能直接在原文件上操作,只能采用副本的策略。由此,HDFS设计了第二名称节点(SecondaryNameNode)来进行FsImage的更新。
4.4第二名称节点 SecondaryNameNode
微信截图_20230311111145.pngSecondaryNameNode和NameNode内存需求相同,两者是运行在不同的机器上的。 SecondaryNameNode 周期性地与 NameNode 通信,进行检查点操作,合并FsImage和EditLog。 具体操作流程如下:
检查点间隔由两个参数确定:fs.checkpoint.period 和 fs.checkpoint.size。 前者指定两个连续检查点之间的最长时间(以秒为单位),默认值为 3600 秒(一小时)。 后者指定触发检查点的 EditLog 文件的最大大小(以字节为单位),默认值为 64 MB。
其实第二名称节点也相当于名称节点的一个备份,只是实时性没有那么高,但是当名称节点出现故障的时候,第二名称节点也能顶上去,只不过原名称节点的EditLog就会丢失了。
说人话就是,FsImage在SecondaryNameNode处更新。
五、数据节点工作原理
数据节点工作原理相关资料比较少,简单理解下就行了。
数据节点是HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块的列表。
在我的理解中,数据节点主要做的工作是存储,管理文件。
- 存储:在HDFS中,文件被拆分为一个或多个块,数据节点作为存储数据块的媒介。
- 管理:DataNode 可以执行文件系统命名空间的操作,例如打开、关闭和重命名文件或目录。同时DataNode还维护着数据块到数据节点的映射。
在这里我突然产生了一个小小的疑问,他们俩都维护映射关系,这是冗余?
数据节点和名称节点分别维护的映射关系有什么区别?
这里需要注意一点,名称节点(NameNode)内部的元数据维护着文件到数据块的映射,同时包含着数据块所在的数据节点(DataNode)。
数据节点则记录了此节点内部所有的数据块,维护着数据节点到数据块的映射关系。
一开始我是认为这是一种冗余存储,后来我才想明白名称节点是不知道一个数据节点内分别有哪几个数据块的,它仅仅记录这一个文件对应的几个块在哪几个数据节点上。
事实上,通过DataNode查询其数据块的场景非常少,为此消耗宝贵的内存空间存储这种映射关系性价比太低。
六、HDFS体系架构
HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群包括一个名称节点(NameNode)和若干个数据节点(DataNode)。名称节点通过心跳机制实时监控数据节点的状态
6.1 心跳机制
数据节点每隔固定时间向名称节点汇报心跳,心跳内容包括:
报告自己的存活状态,每次汇报之后都会更新维护的计数信息
向nameNode汇报自己的存储的block列表信息
这个简单了解下吧,我估计没人关注这玩意儿。
NameNode通过心跳判断DataNode是否宕机的细节
nameNode判断一个dataNode是否宕机的基准:连续10次接收不到dataNode的心跳信息,和2次的检查时间。
如果namenode连续十次没有收到datanode的汇报,那么namenode就会认为该datanode存在宕机的可能。
这里要注意datanode启动以后会专门启动一个进程负责给namenode发送心跳数据包,所以存在一种可能,datanode没有问题,仅仅只是发送信息数据包的进程挂了,namenode后续还会发送命令向这个datanode进行确认,
namenode会向datanode确认两遍,查看这个发送心跳包的进程是否还能正常运行,每隔一段时间确认一次。如果两次都没有返回结果,那么namenode就会认为datanode已经宕机了。
6.2数据存取策略
6.2.1数据存放
存放我们要兼顾存放速度和数据安全。
名称节点会根据数据节点的心跳判断其是否健康。衡量的点包括:
是否宕机
是否有充足存储空间
IO负载繁忙程度
同时在上文中我们也提到了,为了容错数据节点会有存储至少三份。
6.2.2数据读取
读取我们考虑的主要是读取速度。
我们要读取的某个数据块有三个副本,优先考虑同一机架内的数据块。如果没有的话,应该就是随机了。
6.3容错恢复
6.3.1名称节点出错
第二名称节点
SecondaryNameNode 周期性地与 NameNode 通信,进行检查点操作,合并FsImage和EditLog,获得最新的FsImage。
在名称节点宕机后,第二名称节点作为备份会顶上去,当然原EditLog内的部分元数据会丢失。
高可用HA(High Available)
以上的方案存在一定的问题,单一的NameNode对外提供服务风险太高,很容易出现单点故障。
HDFS-HA功能通过配置Active/Standby两个nameNodes(2.0支持一主一备,3.0最多支持一主五备)实现在集群中对NameNode的热备份来解决上述问题
这个注意对NameNode设置的备份,不能是像SecondaryNameNode间隔同步备份。HA是为NameNode增加实时同步的副本(热备份)。
DataNode向两个NamenNode汇报,两个NameNode内存一致,数据同步,功能相同。
这里要注意:两个NameNode不能同时向外提供服务,要保证主官和副官有一个能指挥的,但是不能两个一起指挥。
6.3.2数据节点出错
根据6.1的心跳机制,数据节点定时向名称节点汇报自己的状态,如果数据节点出错,名称节点将不会给该数据节点派发任何IO请求。
至于恢复,在设计之初我们就认为DataNode不太行,所以将数据块存储在不同的数据节点中,分散风险,所有block所在的数据节点同时宕机的可能性微乎其微。
虽然数据节点同时宕机几乎不可能出现,但是数据节点前后宕机也可能会影响到系统的正常运转。
冗余因子
HDFS为数据节点设计一个参数,冗余因子。
由于一些数据节点的宕机,会导致一些数据块的副本数量小于冗余因子。名称节点会定期检查这种情况(应该是通过元数据和心跳对照检查),一旦发现某个数据块的副本数量小于冗余因子,就会启动数据冗余复制,为它生成新的副本。
HDFS和其它分布式文件系统的最大区别就是可以调整冗余数据的位置
6.3.3数据出错
网络传输和磁盘错误等因素,都会造成数据错误
客户端在读取到数据后,会采用校验和对数据块进行校验(常用的CRC-32),以确定读取到正确的数据。具体方法为:
在文件被创建时,客户端就会对每一个文件块进行信息摘录,并把这些信息写入到同一个路径的隐藏文件里面。
当客户端读取文件的时候,会先读取该信息文件,然后,利用该信息文件对每个读取的数据块进行校验,如果校验出错,客户端就会请求到另外一个数据节点读取该文件块,并且向名称节点报告这个文件块有错误,名称节点会定期检查并且重新复制这个块
七、HDFS文件操作
HDFS提供了一个客户端提供了接口用来操作文件、目录。
7.1写入文件
面经高频考点,但是死记硬背不如切实理解。
Client与NameNode通信校验是否可以上传文件。(包括是否存在文件,是否客户是否有权限上传文件,文件的父目录是否已存在)NameNode确认可上传才会继续下一步,同时会将该操作写进EditLog。
Client对文件进行拆分,向NameNode询问是否第一个数据块传输到哪几个DataNode上。一般情况下,NameNode会返回三台DataNode服务器DataNode 1,DataNode 2,DataNode 3
开始进行文件传输,因为有三台NamaNode服务器,HDFS的传输采用了pipline的方式。NameNode传输给DataNode1,DataNode1 传输给DataNode2,DataNode2传输给DataNode3。
当一个block传输完成之后,Client再次请求NameNode上传第二个block的服务器.
以pipline的写入方式而非并行写入最主要的优势就是节省了DataNode的IO开销,传输一次和传输三次的差别还是挺明显的。
这里的应答序列需要三个都成功,NameNode才会接收到写入成功的信号,否则会重复发送。
7.2读数据
1、客户端与NameNode通信查询元数据,找到文件块所在的DataNode服务器
2、挑选一台DataNode(网络拓扑上的就近原则,如果都一样,则随机挑选一台DataNode)服务器,请求建立socket流
3、DataNode开始发送数据(从磁盘里面读取数据放入流,以packet(一个packet为64kb)为单位来做校验)
4、客户端以packet为单位接收,先在本地缓存,然后写入目标文件
网友评论