HDFS进阶笔记1
4. 核心概念block
4.1 数据块block
4.1.1 HDFS block块
-
向HDFS上传文件,是按照128M为单位,切分成一个个block,分散的存储在集群的不同数据节点datanode上
-
问:HDFS中一个44M大小的块会不会占据128M的空间?
- 小于一个块大小的文件不会占据整个块的空间
-
问:这样存储有没有问题?
4.2 block副本
-
因为HDFS是用普通的商用服务器搭建起来的;所以有节点出问题的可能性;
-
那么如果每个block只有一份的话,当block所在的节点宕机后,此block将无法访问,进而导致文件无法完整读取
-
为保正数据的可用及容错,HDFS设计成每个block共有三份,即三个副本
-
如何设置副本数?
-
replication = 3
-
hdfs-site.xml
<property> <name>dfs.replication</name> <value>3</value> </property>
-
4.3 机架存储策略
-
实际机房中,会有机架,每个机架上若干服务器
-
第一块:在本机器的HDFS目录下存储Block的第一个副本。
第二块:在不同Rack(机架,暂且称为r1)的某个DataNode(称为dn2)上存储Block的第二个副本。
第三块:在dn2所在机架r1下,找一台其它的datanode节点,存储Block的第三个副本。
更能多副本:随机节点
了解下服务器参数:https://item.jd.com/4564487.html
机架:https://item.jd.com/16829137698.html
4.4 block的一些操作
-
设置文件副本数,有什么用?
-
数据分块存储和副本的存放,是保证可靠性和高性能的关键
-
方式一:使用命令设置文件副本数;动态生效,不需要重启hadoop集群
hadoop fs -setrep -R 4 /path
-
方式二:修改配置文件hdfs-site.xml,需要重启hadoop集群才能生效
<property> <name>dfs.replication</name> <value>4</value> </property>
-
-
HDFS提供了fsck命令,用于检查HDFS上文件和目录的健康状态、获取文件的block信息和位置信息
[hadoop@node01 ~]$ hdfs fsck
- 查看文件中损坏的块
[hadoop@node01 ~]$ hdfs fsck /tmall-201412-1w.csv -list-corruptfileblocks
- 查看文件的块基本信息
hdfs fsck /02-041-0029.mp4 -files -blocks -locations
- 删除损坏的文件
[hadoop@node01 ~]$ hdfs fsck /tmall-201412-1w.csv -delete
4.5 小结
- HDFS上的文件分块存储
- 每个块有3个副本
- 考虑机架存储策略
- 关于block的一些常用命令:hdfs fsck
5. HDFS架构
- 大多数分布式框架都是主从架构
- HDFS也是主从架构Master|Slave或称为管理节点|工作节点
5.1 NameNode
5.1.1 文件系统
- file system文件系统:操作系统中负责管理和存储文件信息的软件;具体地说,它负责为用户创建文件,存入、读取、修改、转储、删除文件等
- 读文件 =>>找到文件 =>> 在哪 + 叫啥?
- 元数据
- 关于文件或目录的描述信息,如文件所在路径、文件名称、文件类型等等,这些信息称为文件的元数据metadata
- 命名空间
- 文件系统中,为了便于管理存储介质上的,给每个目录、目录中的文件、子目录都起了名字,这样形成的层级结构,称之为命名空间
- 同一个目录中,不能有同名的文件或目录
- 这样通过目录+文件名称的方式能够唯一的定位一个文件
5.1.2 HDFS-NameNode
- HDFS本质上也是文件系统filesystem,所以它也有元数据metadata;
- 元数据metadata保存在NameNode内存中
- NameNode作用
- HDFS的主节点,负责管理文件系统的命名空间,将HDFS的元数据存储在NameNode节点的内存中
- 负责响应客户端对文件的读写请求
- HDFS元数据
-
文件目录树、所有的文件(目录)名称、文件属性(生成时间、副本、权限)、每个文件的块列表、每个block块所在的datanode列表
-
每个文件、目录、block占用大概150Byte字节的元数据;所以HDFS适合存储大文件,不适合存储小文件
-
HDFS元数据信息以两种形式保存:①编辑日志edits log②命名空间镜像文件fsimage
- edits log:HDFS编辑日志文件 ,保存客户端对HDFS的所有更改记录,如增、删、重命名文件(目录),这些操作会修改HDFS目录树;NameNode会在编辑日志edit日志中记录下来;
- fsimage:HDFS元数据镜像文件 ,即将namenode内存中的数据落入磁盘生成的文件;保存了文件系统目录树信息以及文件、块、datanode的映射关系,如下图
-
说明:
①为hdfs-site.xml中属性dfs.namenode.edits.dir的值决定;用于namenode保存edits.log文件
②为hdfs-site.xml中属性dfs.namenode.name.dir的值决定;用于namenode保存fsimage文件
5.2 DataNode
- DataNode数据节点的作用
- 存储block以及block元数据到datanode本地磁盘;此处的元数据包括数据块的长度、块数据的校验和、时间戳
5.3 SeconddaryNameNode
-
为什么引入SecondaryNameNode
-
为什么元数据存储在NameNode在内存中?
-
这样做有什么问题?如何解决?
-
HDFS编辑日志文件 editlog:在NameNode节点中的编辑日志editlog中,记录下来客户端对HDFS的所有更改的记录,如增、删、重命名文件(目录);
-
作用:一旦系统出故障,可以从editlog进行恢复;
-
但editlog日志大小会随着时间变在越来越大,导致系统重启根据日志恢复的时候会越来越长;
-
为了避免这种情况,引入检查点机制checkpoint,命名空间镜像fsimage就是HDFS元数据的持久性检查点,即将内存中的元数据落磁盘生成的文件;
-
此时,namenode如果重启,可以将磁盘中的fsimage文件读入内容,将元数据恢复到某一个检查点,然后再执行检查点之后记录的编辑日志,最后完全恢复元数据。
-
但是依然,随着时间的推移,editlog记录的日志会变多,那么当namenode重启,恢复元数据过程中,会花越来越长的时间执行editlog中的每一个日志;而在namenode元数据恢复期间,HDFS不可用。
-
为了解决此问题,引入secondarynamenode辅助namenode,用来合并fsimage及editlog
-
-
SecondaryNameNode定期做checkpoint检查点操作
- 创建检查点checkpoint的两大条件:
- SecondaryNameNode每隔1小时创建一个检查点
- 另外,Secondary NameNode每1分钟检查一次,从上一检查点开始,edits日志文件中是否已包括100万个事务,如果是,也会创建检查点
- Secondary NameNode首先请求原NameNode进行edits的滚动,这样新的编辑操作就能够进入新的文件中
- Secondary NameNode通过HTTP GET方式读取原NameNode中的fsimage及edits
- Secondary NameNode读取fsimage到内存中,然后执行edits中的每个操作,并创建一个新的统一的fsimage文件
- Secondary NameNode通过HTTP PUT方式将新的fsimage发送到原NameNode
- 原NameNode用新的fsimage替换旧的fsimage,同时系统会更新fsimage文件到记录检查点的时间。
- 这个过程结束后,NameNode就有了最新的fsimage文件和更小的edits文件
- 创建检查点checkpoint的两大条件:
-
SecondaryNameNode一般部署在另外一台节点上
- 因为它需要占用大量的CPU时间
- 并需要与namenode一样多的内存,来执行合并操作
-
如何查看edits日志文件
hdfs oev -i edits_0000000000000000256-0000000000000000363 -o /home/hadoop/edit1.xml
-
如何查看fsimage文件
hdfs oiv -p XML -i fsimage_0000000000000092691 -o fsimage.xml
-
checkpoint相关属性
属性 值 解释 dfs.namenode.checkpoint.period 3600秒(即1小时) The number of seconds between two periodic checkpoints.
| dfs.namenode.checkpoint.txns | 1000000 | The Secondary NameNode or CheckpointNode will create a checkpoint of the namespace every ‘dfs.namenode.checkpoint.txns’ transactions, regardless of whether ‘dfs.namenode.checkpoint.period’ has expired. |
| dfs.namenode.checkpoint.check.period | 60(1分钟) | The SecondaryNameNode and CheckpointNode will poll the NameNode every ‘dfs.namenode.checkpoint.check.period’ seconds to query the number of uncheckpointed transactions. |
5.4 心跳机制
工作原理:
- NameNode启动的时候,会开一个ipc server在那里
- DataNode启动后向NameNode注册,每隔3秒钟向NameNode发送一个“心跳heartbeat”
- 心跳返回结果带有NameNode给该DataNode的命令,如复制块数据到另一DataNode,或删除某个数据块
- 如果超过10分钟NameNode没有收到某个DataNode 的心跳,则认为该DataNode节点不可用
- DataNode周期性(6小时)的向NameNode上报当前DataNode上的块状态报告BlockReport;块状态报告包含了一个该 Datanode上所有数据块的列表
心跳的作用:
-
通过周期心跳,NameNode可以向DataNode返回指令
-
可以判断DataNode是否在线
-
通过BlockReport,NameNode能够知道各DataNode的存储情况,如磁盘利用率、块列表;跟负载均衡有关
-
hadoop集群刚开始启动时,99.9%的block没有达到最小副本数(dfs.namenode.replication.min默认值为1),集群处于安全模式,涉及BlockReport;
心跳相关配置
- hdfs-default.xml
- 心跳间隔
属性 | 值 | 解释 |
---|---|---|
dfs.heartbeat.interval | 3 | Determines datanode heartbeat interval in seconds. |
- block report
More Actions属性 | 值 | 解释 |
---|---|---|
dfs.blockreport.intervalMsec | 21600000 (6小时) | Determines block reporting interval in milliseconds. |
- 查看hdfs-default.xml默认配置文件
5.5 负载均衡
-
什么原因会有可能造成不均衡?
- 机器与机器之间磁盘利用率不平衡是HDFS集群非常容易出现的情况
- 尤其是在DataNode节点出现故障或在现有的集群上增添新的DataNode的时候
-
为什么需要均衡?
- 提升集群存储资源利用率
- 从存储与计算两方面提高集群性能
-
如何手动负载均衡?
$HADOOP_HOME/sbin/start-balancer.sh -t 5% # 磁盘利用率最高的节点若比最少的节点,大于5%,触发均衡
5.6 小结
- NameNode负责存储元数据,存在内存中
- DataNode负责存储block块及块的元数据
- SecondaryNameNode主要负责对HDFS元数据做checkpoint操作
- 集群的心跳机制,让集群中各节点形成一个整体;主节点知道从节点的死活
- 节点的上下线,导致存储的不均衡,可以手动触发负载均衡
6. HDFS读写流程
6.1 数据写流程
6.1.1 详细流程
-
创建文件:
- HDFS客户端向HDFS写数据,先调用DistributedFileSystem.create()方法,在HDFS创建新的空文件
- RPC(ClientProtocol.create())远程过程调用NameNode(NameNodeRpcServer)的create(),首先在HDFS目录树指定路径添加新文件
- 然后将创建新文件的操作记录在editslog中
- NameNode.create方法执行完后,DistributedFileSystem.create()返回FSDataOutputStream,它本质是封装了一个DFSOutputStream对象
-
建立数据流管道:
- 客户端调用DFSOutputStream.write()写数据
- DFSOutputStream调用ClientProtocol.addBlock(),首先向NameNode申请一个空的数据块
- addBlock()返回LocatedBlock对象,对象包含当前数据块的所有datanode的位置信息
- 根据位置信息,建立数据流管道
-
向数据流管道pipeline中写当前块的数据:
- 客户端向流管道中写数据,先将数据写入一个检验块chunk中,大小512Byte,写满后,计算chunk的检验和checksum值(4Byte)
- 然后将chunk数据本身加上checksum,形成一个带checksum值的chunk(516Byte)
- 保存到一个更大一些的结构packet数据包中,packet为64kB大小
-
packet写满后,先被写入一个dataQueue队列中
- packet被从队列中取出,向pipeline中写入,先写入datanode1,再从datanoe1传到datanode2,再从datanode2传到datanode3中
-
一个packet数据取完后,后被放入到ackQueue中等待pipeline关于该packet的ack的反馈
- 每个packet都会有ack确认包,逆pipeline(dn3 -> dn2 -> dn1)传回输出流
-
若packet的ack是SUCCESS成功的,则从ackQueue中,将packet删除;否则,将packet从ackQueue中取出,重新放入dataQueue,重新发送
- 如果当前块写完后,文件还有其它块要写,那么再调用addBlock方法(流程同上)
-
文件最后一个block块数据写完后,会再发送一个空的packet,表示当前block写完了,然后关闭pipeline
- 所有块写完,close()关闭流
-
ClientProtocol.complete()通知namenode当前文件所有块写完了
6.1.2 容错
- 在写的过程中,pipeline中的datanode出现故障(如网络不通),输出流如何恢复
- 输出流中ackQueue缓存的所有packet会被重新加入dataQueue
- 输出流调用ClientProtocol.updateBlockForPipeline(),为block申请一个新的时间戳,namenode会记录新时间戳
- 确保故障datanode即使恢复,但由于其上的block时间戳与namenode记录的新的时间戳不一致,故障datanode上的block进而被删除
- 故障的datanode从pipeline中删除
- 输出流调用ClientProtocol.getAdditionalDatanode()通知namenode分配新的datanode到数据流pipeline中,并使用新的时间戳建立pipeline
- 新添加到pipeline中的datanode,目前还没有存储这个新的block,HDFS客户端通过DataTransferProtocol通知pipeline中的一个datanode复制这个block到新的datanode中
- pipeline重建后,输出流调用ClientProtocol.updatePipeline(),更新namenode中的元数据
- 故障恢复完毕,完成后续的写入流程
6.2 数据读流程
6.2.1 基本流程
- 1、client端读取HDFS文件,client调用文件系统对象DistributedFileSystem的open方法
- 2、返回FSDataInputStream对象(对DFSInputStream的包装)
- 3、构造DFSInputStream对象时,调用namenode的getBlockLocations方法,获得file的开始若干block(如blk1, blk2, blk3, blk4)的存储datanode(以下简称dn)列表;针对每个block的dn列表,会根据网络拓扑做排序,离client近的排在前;
- 4、调用DFSInputStream的read方法,先读取blk1的数据,与client最近的datanode建立连接,读取数据
- 5、读取完后,关闭与dn建立的流
- 6、读取下一个block,如blk2的数据(重复步骤4、5、6)
- 7、这一批block读取完后,再读取下一批block的数据(重复3、4、5、6、7)
- 8、完成文件数据读取后,调用FSDataInputStream的close方法
6.2.2 容错
-
情况一:读取block过程中,client与datanode通信中断
- client与存储此block的第二个datandoe建立连接,读取数据
- 记录此有问题的datanode,不会再从它上读取数据
-
情况二:client读取block,发现block数据有问题
- client读取block数据时,同时会读取到block的校验和,若client针对读取过来的block数据,计算检验和,其值与读取过来的校验和不一样,说明block数据损坏
- client从存储此block副本的其它datanode上读取block数据(也会计算校验和)
- 同时,client会告知namenode此情况;
7. Hadoop HA高可用
7.1 HDFS高可用原理
- 对于HDFS ,NN存储元数据在内存中,并负责管理文件系统的命名空间和客户端对HDFS的读写请求。但是,如果只存在一个NN,一旦发生“单点故障”,会使整个系统失效。
- 虽然有个SNN,但是它并不是NN的热备份
- 因为SNN无法提供“热备份”功能,在NN故障时,无法立即切换到SNN对外提供服务,即HDFS处于停服状态。
- HDFS2.x采用了HA(High Availability高可用)架构。
- 在HA集群中,可设置两个NN,一个处于“活跃(Active)”状态,另一个处于“待命(Standby)”状态。
- 由zookeeper确保一主一备(讲zookeeper时具体展开)
- 处于Active状态的NN负责响应所有客户端的请求,处于Standby状态的NN作为热备份节点,保证与active的NN的元数据同步
- Active节点发生故障时,zookeeper集群会发现此情况,通知Standby节点立即切换到活跃状态对外提供服务
- 确保集群一直处于可用状态
- 如何热备份元数据:
- Standby NN是Active NN的“热备份”,因此Active NN的状态信息必须实时同步到StandbyNN。
- 可借助一个共享存储系统来实现状态同步,如NFS(NetworkFile System)、QJM(Quorum Journal Manager)或者Zookeeper。
- Active NN将更新数据写入到共享存储系统,Standby NN一直监听该系统,一旦发现有新的数据写入,就立即从公共存储系统中读取这些数据并加载到Standby NN自己内存中,从而保证元数据与Active NN状态一致。
- 块报告:
- NN保存了数据块到实际存储位置的映射信息,为了实现故障时的快速切换,必须保证StandbyNN中也包含最新的块映射信息
- 因此需要给所有DN配置Active和Standby两个NN的地址,把块的位置和心跳信息同时发送到两个NN上。