摘要:助辅助做元数据的备份。元数据存储在内存和磁盘中,这是因为磁盘的读写效率较低,而保存到内存又有断电消失的隐患。但磁盘中的元数据并不是最新的,内存中的元数据才是实时的。将中的和复制到自身节点上并加载进内存,根据的记录操作更改元数据信息。
HDFS(Hadoop Distributed File System )
前言:最近正式进入了大数据框架的学习阶段,文章来自个人OneNote笔记全部手码,记录学习仅作自勉与交流,如有错误希望交流指正。
HDFS概念:HDFS是一种用于在普通硬件上运行的分布式文件系统,提供高度容错的服务,并被设计为部署在低成本的硬件上
HDFS适合批量处理,而不是用户交互使用。重点是高吞吐量的数据访问,而不是低延迟的数据访问。
运行在HDFS上的应用程序具有较大的数据集。因此,HDFS被调优以支持大文件。
HDFS设计思想:
分而治之 负载均衡
HDFS使用的典型块大小为128 MB(此处指Hadoop2.X,Hadoop3.X默认256M)。尽可能的将每个块驻留在不同的DataNode上。将超级大的文件切分成每一个小文件(数据块)进行存储在不同的节点上。同时切分的数据块太大了,容易造成集群中节点的存储的负载不均衡。太小了会造成一个文件切分过多的块会造成NameNode的压力过大。
除了最后一个块之外,文件中的所有块都是相同大小的,如一个500M的文件被默认被切分成4*128M的文件块,第四块的大小为500-3×128=116M,每个block块都有一个唯一的块ID。如果想更改默认块大小可以更改dfs.blocksize属性。
冗余数据 提高容错
为了解决数据丢失的问题,hadoop使用空间换取数据安全,在hdfs中每一个数据块都会进行备份存储。默认的情况下每一个数据块存储3份。副本之前地位相同没有优先级,提供服务时谁有空谁服务。
应用程序可以指定文件的副本数量。复制因子(副本的数量)可以在文件创建时指定,以后可以更改。由于NameNode不允许DataNodes拥有同一个block的多个副本,也就是说同一个节点的多个数据块中肯定没有相同的。因此创建的副本的最大数量是当时的DataNodes总数。
如果复制因子大于3,则随机确定第4次复制和后续复制的位置,同时将每个rack(机架策略,下面会写到) 的副本数量保持在上限以下(replicas - 1) / racks + 2。如果副本数量不符合设置则会根据条件自动管理,关系如下:
数据副本 < 复制因子:如果某个数据节点宕机导致数据副本小于复制因子则会复制此数据到另一个数据节点
数据副本>复制因子:如果因为上面的情况复制了数据之后,之前宕机的节点突然恢复运行,此时副本数大于复制因子则会删除一个数据节点中的副本。
复制因子>DataNodes:如果复制因子大于数据节点总数NameNodes,而上面也提到了NameNode不允许单节点拥有同一个block的多个副本,则NameNode对这个block进行记录,当集群中添加了新的DataNode时再复制补足副本
下图为副本数的设置,可以在hdfs-site.xml文件中设置,如果不是设置的话默认为3。后续也可以通过在集成开发环境中编写hdfs-site.xml或使用命令的方式设置,命令>IDE配置的文件>集群配置文件
HDFS采用一主多从架构(Hadoop3.X已经支持多个NameNode)
主:NameNode
存储块到DataNodes的映射元数据用于管理文件系统命名空间。
执行文件系统命名空间操作,比如打开、关闭和重命名文件和目录。
处理调节来自Client的读写请求。
负责分配block的存储节点。
负责负载均衡。
助:SecondaryNameNode
辅助NameNode做元数据的备份、CheckPoint 。
辅助并分担NameNode的压力,当NameNode宕机时不能主动顶替NameNode,但是可以辅助NameNode的恢复。
从:DataNode
存储数据,管理自身节点的数据存储。
真实的处理读写请求。
按指定周期向NameNode发送心跳报告。
元数据的概念:NameNode中存储着元数据,元数据包括(以下D表示存储于磁盘disk,M表示内存memory):
抽象目录树(DM)
数据与block的映射关系(DM)
block存储的数据节点位置(M)
元数据就像是所有数据的目录一样,集群启动时会将磁盘中的元数据读取到内存,并根据DataNodes传递的心跳报告记录block存储的位置。元数据存储在内存和磁盘中,这是因为磁盘的读写效率较低,而保存到内存又有断电消失的隐患。但磁盘中的元数据并不是最新的,内存中的元数据才是实时的。
下图为NameNode元数据目录下的截图(路径是手动设置的,不是默认路径)
其中
edits_XXXXXXXXX-XXXXX 历史日志文件,记录了客户端对数据的操作日志
edits_inprogress_XXXXXXXX 正在编辑的日志文件,记录了目前对数据的操作
fsimage_xxxxxxxxx 元数据的一个持久化的CheckPoint,包含 Hadoop 文件系统中的所有目录和文件元数据信息,但不包含文件块位置的信息。该文件是通过真实元数据序列化的结果,集群启动时对这些文件进行反序列化
seen_txid:合并点记录文件,用户对数据进行操作时不直接修改元数据而是记录当前操作到日志文件,等集群空闲时再合并到元数据中,而合并点记录文件中记录的就是即将要合并的操作(还没合并),这个合并的操作由SecondaryNameNode或指定的CheckPointNode来完成。
可以通过hdfs oiv将元数据转换为其他格式文件(如XML)来查看,oev参数转换日志文件,其中参数p表示转换,参数 i 表示输入,参数 o 表示输出
hdfs oiv -p XML -i fsimage_0000000000000000062 -o fs62.xml hdfs oev -p XML -i edits_0000000000000000046-0000000000000000061 -o edit46.xml
将转换好的文件从Linux下取出到Windows并使用VS Code格式化查看:
可以看到每一步操作都有非常详细的记录,将时间戳转换为具体时间即可查看操作时间
上面提到了元数据的合并且由SecondaryNameNode完成(以下简称SNN)
CheckPoint由于磁盘内的元数据相对于内存中的元数据不是实时的,那么如何判断何时该进行元数据合并呢?
CheckPoint默认触发的条件有两条,任意满足一条都会启动CheckPoint
距离上次元数据合并时间超过1小时
当前产生的操作记录超过100W条,此条件每分钟检查一次
默认CheckPointNode为SNN,那么首先请求开始CheckPoint,要求NameNode停止操作edit_inprogress并将后面的操作写入到一个新文件中。
SNN将NameNode中的fsimage和edits复制到自身节点上并加载进内存,根据edits的记录操作更改元数据信息。(在这个过程中需要注意的是如果不是第一次进行CheckPoint,那么SNN拉取的是合并点记录文件编号到最新编辑日志文件中的文件,而不是所有文件)
SNN将合并好的元数据信息命名为fsimage.checkpoint并发送给NameNode,自己也保存一份
NameNode接收文件并将其改名为fsimage替换旧的元数据文件
如果在集群没有达到CheckPoint条件的时候被正常关闭了,那么内存中的完整元数据将会被序列化到磁盘元数据文件中。
HDFS四大机制
心跳机制:
NameNode如何确认DataNode存活?
每个DataNode定期向NameNode发送一条心跳消息,心跳报告间隔默认为3S。网络分区可能导致DataNodes的子集与NameNode失去连接,NameNode通过心跳机制来检测此情况,如果一个NameNode连续10次接收不到dataNode的心跳信息,会主动的对该DataNode发送两次检查,检查的时间默认为五分钟,两次检查失败该DataNode将被标记为 死亡 ,并且不会再向它们发送任何IO请求。此外,DataNode每小时还需要向NameNode重新报告自身所有数据信息保证有效性。
已注册死亡的DataNode的任何数据都不再适用于HDFS。DataNodeDeath可能导致某些块的复制因子低于其指定值。NameNode经常跟踪需要复制的块,并在必要时启动复制。由于许多原因,重新复制的必要性可能会出现:DataNode可能变得不可用,副本可能被破坏,DataNode上的硬盘可能会失败,或者文件的复制因子可能会增加。
标记DataNodes死亡的超时时间是谨慎的(默认情况下超过10分钟),以避免由DataNodes的状态抖动引起的复制风暴。用户可以设置较短的间隔以将DataNodes标记为陈旧的,并通过配置性能敏感的工作负载来避免在读取和/或写入时陈旧的节点。
安全模式
如集群启动时就进入了安全模式,不允许任何写操作,此时发生了什么?
启动NameNode并将磁盘中的元数据文件加载到内存建立元数据,并监听DataNode的请求与心跳
启动DataNode并向NameNode发送心跳报告以注册DataNode的存活状况及block存储信息
启动SecondaryNameNode
准备完毕后只要集群内的副本达到“最小副本条件”——文件系统中的每个副本数 > 最小副本级别(默认为1),NameNode会在30S后退出安全模式
此外,用户也可以手动使用命令进入和离开安全模式
机架策略
HDFS块放置将通过在不同的机架上放置一个块副本来使用机架感知实现容错。这提供了在集群内发生网络交换机故障或分区时的数据可用性。如默认机架数为2,复制因子为3.
第一个副本一般存储在客户端所在的节点上(如果客户端是一个DataNode的话,不是就随机一个节点)
第二个副本存储在和第一个副本不同的机架上的任意节点
第三个副本存储在和第一个副本相同机架不同节点
负载均衡
每个数据节点存储的数据与其硬件实力的比例差距不大,没有绝对的均衡。集群规模较小可以使用默认的负载均衡,规模较大需要手动调整均衡属性。自动调整负载均衡的带宽,这里设置的带宽是指负载均衡传输的速率,且自动负载均衡会在集群空闲的时候才启动:
dfs.datanode.balance.bandwidthPerSec 1048576 //1M
命令方式手动负载均衡:
start-balancer.sh -t 10% //参数代表了各个节点数据占用率差值不超过10%时视为负载均衡
写操作:
Client通过Distributed FileSystem向NameNode发送上传文件的请求和文件信息
NameNode接收请求并分析文件信息决定是否允许上传(文件/目录是否存在,客户端是否有权限)
如果NameNode分析同意上传请求那么根据节点距离情况返回复制因子数目的数据节点列表信息(前提客户端是一个数据节点,如果不是则首个节点随机返回一个)
客户端接收NameNode的允许响应并对文件进行逻辑切分
准备上传并构建PipeLine,根据NameNode返回的返回的信息找到第一个写入的数据节点,客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。dn3、dn2、dn1逐级应答客户端。
以packet为单位上传block(先写入缓存)到通信管道中的每个节点
用传输第一个块的方式完成其他块的传输
所有块传输完成后Client向NameNode发送传输状态信息(成功或失败)同时关闭FsDataOutputStream,NameNode根据状态信息更新元数据。
读操作:
Client通过Distributed FileSystem向NameNode发送下载文件请求
NameNode查询元数据,找到并返回文件块所在的DataNode地址,如果找不到直接抛出异常。
客户端获取到block的数据节点会就近选择节点按顺序开始下载block
每个block下载完成后会进行checksum验证,如果在某个DataNode读取数据时发生错误则会通知NameNode并重新从其他拥有该block副本的DataNode进行下载
所有block下载完成后关闭FsDataOutputStream并由分布式文件系统向NameNode报告下载情况
关于HDFS写操作失败的结果网上说法不一,等学习的深入一些自行验证,这里先记录我看到的两种:
说法一:如果在这个过程中有节点传输失败HDFS默认会进行一次重试,再次失败则放弃失败的节点,从通信管道中删除该节点并报告给NameNode,如果传输的节点全部失败则重新向NameNode发起请求并构建新的PipeLine,也就是说最少需要一个节点传输完成。未达到复制因子数量则在集群空闲时复制副本。
说法二:复制管道中的某一个DataNode无法将数据写入磁盘,管道立即关闭。已发送的但尚未收到确认的数据包会被回退到队列中,以确保管道中错误节点的下游节点可以获得数据包。在剩下的健康数据节点中,正在写入的数据块被分配新的ID。当发生故障的数据节点恢复后,冗余的数据块貌似不属于任何文件而自动丢弃,由剩余节点组成的新复制管道会重新开放,继续写操作直至文件关闭
NameNode故障处理如果运行的过程中NameNode发生意外宕机了,可以使用以下方法进行挽救
将SecondaryNameNode中保存的备份数据复制到NameNode中,需要先将NameNode中的数据删除
使用-importCheckpoint启动NameNode守护进程,由hadoop修复NameNode
那么开始动手摧残集群(这里先对虚拟机拍了快照)
如图,启动集群后杀死NameNode进程并删除元数据文件夹,再次启动NameNode,此时请求获取根目录文件列表失败
[root@master hadoop]# jps //查看当前集群进程 8192 DataNode 8610 Jps 8451 NodeManager 8041 NameNode [root@master hadoop]# kill 8041 //杀死NameNode进程 [root@master hadoop]# rm -rf data/tmp/dfs/name/* //删除元数据文件夹 [root@master hadoop]# sbin/hadoop-daemon.sh start namenode //多带带启动NameNode starting namenode, logging to /usr/local/Software/hadoop/logs/hadoop-root-namenode-master.out [root@master hadoop]# bin/hadoop fs -ls / //请求文件列表失败 19/08/04 15:38:25 WARN ipc.Client: Failed to connect to server: master/192.168.35.101:9000: try once and fail. java.net.ConnectException: 拒绝连接
那么现在尝试恢复NameNode,将SecondaryNameNode的元数据备份复制到NameNode下,再次尝试获取集群中的数据,成功获取,至于第二种复制方法设置有点麻烦,下次有时间再补充记录。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75772.html
阅读 1260·2021-09-22 15:18
阅读 2591·2021-09-22 15:17
阅读 2219·2019-08-30 15:55
阅读 1569·2019-08-30 15:54
阅读 1033·2019-08-30 13:12
阅读 620·2019-08-30 13:12
阅读 1675·2019-08-29 11:33
阅读 1434·2019-08-26 17:04