目录
3.4 SecondayNamenode的工作机制(检查点机制)
hdfs中 文件以块形式存储,块以文件得形式存储到linux文件系统中。
HDFS与其他普通文件系统一样,同样引入了块(Block)的概念,并且块的大小是固定的。但是不像普通文件系统那样小,而是根据实际需求可以自定义的。块是HDFS系统当中的最小存储单位,在hadoop2.0和3.0中默认大小为128MB(hadoop1.x中的块大小为64M)。在HDFS上的文件会被拆分成多个块,每个块作为独立的单元进行存储。多个块存放在不同的DataNode上,整个过程中 HDFS系统会保证一个块存储在一个数据节点上 。但值得注意的是,如果某文件大小或者文件的最后一个块没有到达128M,则不会占据整个块空间 。
HDFS的设计思想:以下图为例,来进行解释。

HDFS上的块大小是远远大于传统文件的,原因如下:
1. 一是为了最小化寻址开销时间。
2.二是 为了节省内存的使用率
一个块的元数据大约150个字节。1亿个块,不论大小,都会占用20G左右的内存。因此块越大,集群相对存储的数据就越多。所以暴漏了HDFS的一个缺点,不适合存储小文件。
不适合存储小文件解释:
1. 从存储能力出发(固定内存)
因为HDFS的文件是以块为单位存储的,且如果文件大小不到128M的时候,是不会占用整个块的空间的。但是,这个块依然会在内存中占用150个字节的元数据。因此,同样的内存占用的情况下,大量的小文件会导致集群的存储能力不足。
例如: 同样是128G的内存,最多可存储9.2亿个块。如果都是小文件,例如1M,则集群存储的数据大小为9.2亿*1M = 877TB的数据。但是如果存储的都是128M的文件,则集群存储的数据大小为109.6PB的数据。存储能力大不相同。
2. 从内存占用出发(固定存储能力)
同样假设存储1M和128M的文件对比,同样存储1PB的数据,如果是1M的小文件存储,占用的内存空间为1PB/1Mb*150Byte = 150G的内存。如果存储的是128M的文件存储,占用的内存空间为1PB/128M*150Byte = 1.17G的内存占用。可以看到,同样存储1PB的数据,小文件的存储比起大文件占用更多的内存。
当然块大小在默认配置文件hdfs-default.xml中有相关配置,我们可以在hdfs-site.xml中进行重置
<property>
<name>dfs.blocksize</name>
<value>134217728</value>
<description>默认块大小,以字节为单位。可以使用以下后缀(不区分大小写):k,m,g,t,p,e以重新指定大小(例如128k, 512m, 1g等)</description>
</property><property>
<name>dfs.namenode.fs-limits.min-block-size</name>
<value>1048576</value>
<description>以字节为单位的最小块大小,由Namenode在创建时强制执行时间。这可以防止意外创建带有小块的文件降低性能。</description>
</property><property>
<name>dfs.namenode.fs-limits.max-blocks-per-file</name>
<value>1048576</value>
<description>每个文件的最大块数,由写入时的Namenode执行。这可以防止创建降低性能的超大文件</description>
</property>
在hdfs-site.xml中我们配置过下面这个属性,这个属性的值就是块在linux系统上的存储位置
<!-- 确定DFS数据节点应该将其块存储在本地文件系统的何处-->
<property>
<name>dfs.datanode.data.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/data</value>
</property>

有datanode的结点就有data目录存在块文件,有namenode的地方就有name目录,存放的是元数据,查看data文件中存放的块数据。
从一个服务器上删除文件的块的话另外两台机器还有备份,仍可以从hdfs分布式文件系统中读文件,而且,等一段时间后,他会检测丢失的块并将丢失的块从别的节点上复制过来,容错率很高

元数据是描述数据的数据(HDFS元数据有文件类型、文件大小、创建人、创建时间、块位置等信息)。
命名空间指的就是文件系统树及整棵树内的所有文件和目录的元数据,每个Namenode只能管理唯一的一命名空间。HDFS暂不支持软链接和硬连接。Namenode会在内存里维护文件系统的元数据,同时还使用fsimage和edit日志两个文件来辅助管理元数据,并持久化到本地磁盘上。
- fsimage
命名空间镜像文件,它是文件系统元数据的一个完整的永久检查点,内部维护的是最近一次检查点的文件系统树和整棵树内部的所有文件和目录的元数据,如修改时间,访问时间,访问权限,副本数据,块大小,文件的块列表信息等等。
fsimage默认存储两份,是最近的两次检查点
- 使用XML格式查看fsimage文件:
[root@user1 current]# hdfs oiv -i 【fsimage_xxxxxxx】 -o -p XML【目标文件路径】
案例如下:
hdfs oiv -i /usr/local/hadoop-3.3.1/tmp/dfs/name/current/fsimage_0000000000000000157 -p XML -o /home/qd/fs1.xml
集群正常运行时,客户端的所有更新操作(如打开、关闭、创建、删除、重命名等)除了在内存中维护外,还会被写到edit日志文件中,而不是直接写入fsimage映像文件。
因为对于分布式文件系统而言,fsimage映像文件通常都很庞大,如果客户端所有的更新操作都直接往fsimage文件中添加,那么系统的性能一定越来越差。相对而言,edit日志文件通常都要远远小于fsimage,一个edit日志文件最大64M,更新操作写入到EditLog是非常高效的。
那么edit日志文件里存储的到底是什么信息呢,我们可以将edit日志文件转成xml文件格式,进行查看
查看editlog文件的方式:
[root@user1 current]# hdfs oev -i 【edits_inprogress_xxx】-p XML -o 【目标文件路径】
案例:
hdfs oev -i -p XML -o
参考xml文件后,我们可以知道日志文件里记录的内容有:
1. 行为代码:比如 打开、创建、删除、重命名、关闭
2. 事务id
3. inodeid
1. 副本个数
5. 修改时间
6. 访问时间
7. 块大小
7. 客户端信息
9. 权限等
10. 块id等
三、HDFS的工作机制启动namenode之前,内存里是没有任何有关于元数据的信息的。那么启动集群的过程是怎样的呢?
第一步:
Namenode在启动时,会先加载name目录下最近的fsimage文件.
将fsimage里保存的元数据加载到内存当中,这样内存里就有了之前检查点里存储的所有元数据。但是还少了从最近一次检查时间点到关闭系统时的部分数据,也就是edit日志文件里存储的数据。第二步:
加载剩下的edit日志文件
将从最近一次检查点到目前为止的所有的日志文件加载到内存里,重演一次客户端的操作,这样,内存里就是最新的文件系统的所有元数据了。第三步:
进行检查点设置(满足条件会进行)
namenode会终止之前正在使用的edit文件,创建一个空的edit日志文件。然后将所有的未合并过的edit日志文件和fsimage文件进行合并,产生一个新的fsimage.第四步:
处于安全模式下,等待datanode节点的心跳反馈,当收到99.9%的块的至少一个副本后,退出安全模式,开始转为正常状态。***注意:
http访问9870端口,overview下Summary中safemode is off说明退出安全模式,安全模式下只能读不能写。
不是第一次启动,直接加载编辑日志和edits文件的情况展示:

执行流程

第一次启动namenode格式化后的情况展示:

注意:格式化集群后,第一次启动集群的特点,参考下图
3.1.3 小知识(1) 滚动编辑日志(前提必须启动集群)
1.可以强制滚动
[bigdata@qianfeng02 current]$ hdfs dfsadmin -rollEdits
2.可以等到edits.inprogress满64m生成edits文件
3.可以等操作数量达到100万次
4.时间到了,默认1小时
注意:在2,3,4时发生滚动,会进行checkpoint
(2) 镜像文件什么时候产生
可以在namenode启动时加载镜像文件和编辑日志
也可以在secondarynamenode生成的fsimage.chkpoint文件重新替换namenode原来的fsimage文件时
(3) namenode目录说明

Namenode启动时,首先要加载fsimage文件到内存,并逐条执行editlog文件里的事务操作,在这个期间一但在内存中成功建立文件系统元数据的映像,就会新创建一个fsimage文件(该操作不需要SecondaryNamenode)和一个空的editlog文件。在这个过程中,namenode是运行在安全模式下的,Namenode的文件系统对于客户端来说是只读的,文件修改操作如写,删除,重命名等均会失败。
系统中的数据块的位置并不是由namenode维护的,而是以块列表的形式存储在datanode中。在系统的正常操作期间,namenode会在内存中保留所有块位置的映射信息。在安全模式下,各个datanode会向namenode发送最新的块列表信息,如果满足“最小副本条件”,namenode会在30秒钟之后就退出安全模式,开始高效运行文件系统.所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。
PS:启动一个刚刚格式化完的集群时,HDFS还没有任何操作呢,因此Namenode不会进入安全模式。
3.2.1 系统离开安全模式,需要满足的条件
当namenode收到来自datanode的状态报告后,namenode根据配置确定
1. 可用的block占总数的比例
2. 可用的数据节点数量符合要求之后,离开安全模式。1、2两个条件满足后维持的时间达到配置的要求。
注意: 如果有必要,也可以通过命令强制离开安全模式。
3.2.2 与安全模式相关的主要配置在hdfs-site.xml文件中,主要有下面几个属性
1. dfs.namenode.replication.min:
最小的文件block副本数量,默认为12. dfs.namenode.safemode.threshold-pct:
副本数达到最小要求的block占系统总block数的百分比,当实际比例超过该配置后,才能离开安全模式(但是还需要其他条件也满足)。默认为0.999f,也就是说符合最小副本数要求的block占比超过99.9%时,并且其他条件也满足才能离开安全模式。如果为小于等于0,则不会等待任何副本达到要求即可离开。如果大于1,则永远处于安全模式。
3. dfs.namenode.safemode.min.datanodes:
离开安全模式的最小可用(alive)datanode数量要求,默认为0.也就是即使所有datanode都不可用,仍然可以离开安全模式。4. dfs.namenode.safemode.extension:
当集群可用block比例,可用datanode都达到要求之后,如果在extension配置的时间段之后依然能满足要求,此时集群才离开安全模式。单位为毫秒,默认为1。也就是当满足条件并且能够维持1毫秒之后,离开安全模式。这个配置主要是对集群的稳定程度做进一步的确认。避免达到要求后马上又不符合安全标准。
3.2.3 相关命令
[root@user1 current]# hdfs dfsadmin -safemode get
Safe mode is ON
管理员可以随时让Namenode进入或离开安全模式,这项功能在维护和升级集群时非常关键
[root@user1 current]# hdfs dfsadmin -safemode enter
Safe mode is ON
[root@user1 current]# hdfs dfsadmin -safemode leave
Safe mode is OFF
将下面的属性的值设置为大于1,将永远不会离开安全模式
<property>
<name>dfs.namenode.safemode.threshold-pct</name>
<value>0.999f</value>
</property>
[root@user1 current]# hdfs dfsadmin -safemode wait
# command to read or write a file
1. hdfs是user1/slave结构,user1包括namenode和resourcemanager,slave包括datanode和nodemanager
2. user1启动时会开启一个IPC服务,等待slave连接
3. slave启动后,会主动连接IPC服务,并且每隔3秒链接一次,这个时间是可以调整的,设置heartbeat,这个每隔一段时间连接一次的机制,称为心跳机制。Slave通过心跳给user1汇报自己信息,user1通过心跳下达命令。
4. Namenode通过心跳得知datanode状态。Resourcemanager通过心跳得知nodemanager状态
5. 当user1长时间没有收到slave信息时,就认为slave挂掉了。
SecondaryNamenode,是HDFS集群中的重要组成部分,它可以辅助Namenode进行fsimage和editlog的合并工作,减小editlog文件大小,以便缩短下次Namenode的重启时间,能尽快退出安全模式。
两个文件的合并周期,称之为检查点机制(checkpoint),是可以通过hdfs-default.xml配置文件进行修改的:
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
<description>两次检查点间隔的秒数,默认是1个小时</description>
</property>
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>txid执行的次数达到100w次,也执行checkpoint</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description>60秒一检查txid的执行次数</description>
</property>

通过上图,可以总结如下:
1. SecondaryNamenode请求Namenode停止使用正在编辑的editlog文件,Namenode会创建新的editlog文件,同时更新seed_txid文件。
2. SecondaryNamenode通过HTTP协议获取Namenode上的fsimage和editlog文件。
3. SecondaryNamenode将fsimage读进内存当中,并逐步分析editlog文件里的数据,进行合并操作,然后写入新文件fsimage_x.ckpt文件中。
4. SecondaryNamenode将新文件fsimage_x.ckpt通过HTTP协议发送回Namenode。
5. Namenode再进行更名操作。