NameNode
可以说是HDFS中的一个进程
NameNode的功能
-
负责客户端请求(读写数据 请求 )的响应
-
NameNode存放文件与Block的映射关系
-
DataNode存放Block和DataNode的映射关系
-
-
保存文件的元数据信息
- 文件的归属
- 文件的权限
- 文件的大小和时间
- Block信息(也就是上图中的file的信息,Bolck的大小、多少、位置等等信息,不会持久化)。Block的位置信息不会被存放到硬盘,每次开启集群的时候需要DataNode来上传数据给NameNode,NameNode这方面的数据会存放在内存中,关机丢失。
- 即文件系统的目录树以及追踪集群文件,简单来说就是NameNode不实际存储数据,但是他知道数据的存放位置。这些信息不是长久固定的,每次启动系统后需要重新从数据节点获取这些信息。
-
收集Block的信息
-
收集Block信息,例如Block的大小,数量,创建日期等
-
数据块的大小与与NameNode的大小无关
-
系统启动时
- NameNode关机的时候不会存储任意的Block与DataNode的映射信息
- DataNode启动的时候,会将自己节点上存储的Block信息汇报给NameNode
- Name Node接受请求之后重新生成映射关系
- 如果某个数据块的副本数小于设置数,那么NameNode会将这个副本拷贝到其他节点
-
集群运行中
-
NameNode与DataNode保持心跳机制,每三秒钟发送一次
-
可以通过设置参数来设定心跳间隔 ,
vim /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml ·
<property> <name>heartbeat.recheck.interval</name> <value>5000</value> </property> <property> <name>dfs.heartbeat.interval</name> <value>3</value> </property>
-
-
如果客户端需要读取或者上传数据的时候,NameNode可以知道DataNode的健康情况
-
可以让客户端读取存活的DataNode节点
-
-
如果DataNode超过三秒钟没有心跳,就会认为DataNode出现异常
- 不会让新的数据写到DataNode
- 客户访问的时候不会提供异常节点的地址
- 如果DataNode超过10分钟+30秒没有心跳,那么NameNode会将当前DataNode存储的数据转存到其他节点
- 超时时长的计算公式为:
- timeout = 2×heaertbeat.recheck.interval + 10×dfs.heartbeat.interval
- 默认的heartbeat.recheck.interval大小为5min,dfs.heartbeat.interval默认为3s
-
每个DataNode有着心跳机制,会定时向上级NameNode汇报。如果节点死亡,那么NameNode就会将该数据节点的数据复制到一个新的节点上
-
性能
- NameNode为了效率,将所有的操作都在内存中完成
- NameNode不会和磁盘进行任何的数据交换
- 问题:
- 数据的持久化
- 数据保存在内存中,掉电易失
- 小文件太多,占用内存多大
DataNode
DataNode的功能
- 存放的是文件的数据信息和验证文件完整性的校验信息
- 数据会存放在硬盘上
- 1M=1条元数据,1G=1条元数据
- NameNode排斥存放小文件,一般小文件在存储之前需要进行压缩
- 汇报
- 启动时
- 汇报之前先验证Block文件是否被损坏
- 向NameNode汇报当前DataNode上的Block信息
- 运行中
- 向NameNode保持心跳机制
- 客户可以向DataNode读写数据
- 启动时
- 当客户端读写数据的时候,首先去NameNode查询File与Block与DataNode的映射
- 查询结束之后,客户端直接与DataNode建立连接,然后读写数据
Secondary NameNode数据恢复
Hadoop2引入,已经半废弃。
单点故障传统解决方案
- 日志机制
- 在做任何操作前,先记录日志
- 下一次NN启动时,重做。感觉和数据库学的一样。
- 缺点:
- edits文件大小不可控,随时间发展,集群启动时间越来越长
- 有可能日志中存在大量无效日志
- 优点:
- 不会丢失数据
- 拍摄快照
- 我们可以将内存中的数据写到磁盘上
- 序列化
- 启动时还可以将硬盘上的数据写回到内存中
- 反序列化
- 缺点:
- 关机时间长
- 如果是异常关机,数据还在内存中,没有保存到硬盘
- 如果写出频率过高,会导致使用效率低
- 优点:
- 启动时间较短
- 我们可以将内存中的数据写到磁盘上
SNN解决方案
-
解决思路(日志edits+快照fsimage)
- 让日志大小可控
- 定时快照保存
-
NameNode文件目录
-
查看目录
-
在
/var/bdp/hadoop/full/name/current
中保存镜像和日志文件。
-
-
解决方案[1]:
-
当我们启动一个集群的时候,会产生四个文件:
edits_0000000000000000001
fsimage_0000000000000000000.md5
seen_txid
VERSION(1)Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。
(2)Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字
(4)每次NameNode启动的时候都会将fsimage文件读入内存,加载edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将fsimage和edits文件进行了合并。 -
我们每次操作都会记录日志–>edits_inprogress-000000001
-
随着时间的推移,日志文件会越来越大,当达到阈值的时候(64M或者3600秒,可以在hdfs-site.xml修改),会生成新的日志文件
edits_inprogress-0000000000000000001–>edits_0000001
创建新的日志文件edits_inprogress-0000000000000000016Fsimage:namenode内存中元数据序列化后形成的文件。
Edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。
namenode启动时,先滚动edits并生成一个空的edits.inprogress,然后加载edits和fsimage到内存中,此时namenode内存就持有最新的元数据信息。client开始对namenode发送元数据的增删改查的请求,这些请求的操作首先会被记录的edits.inprogress中(查询元数据的操作不会被记录在edits中,因为查询操作不会更改元数据信息),如果此时namenode挂掉,重启后会从edits中读取元数据的信息。然后,namenode会在内存中执行元数据的增删改查的操作。
由于edits中记录的操作会越来越多,edits文件会越来越大,导致namenode在启动加载edits时会很慢,所以需要对edits和fsimage进行合并(所谓合并,就是将edits和fsimage加载到内存中,照着edits中的操作一步步执行,最终形成新的fsimage)。secondarynamenode的作用就是帮助namenode进行edits和fsimage的合并工作。
secondarynamenode首先会询问namenode是否需要checkpoint(触发checkpoint需要满足两个条件中的任意一个,定时时间到和edits中数据写满了)。直接带回namenode是否检查结果。secondarynamenode执行checkpoint操作,首先会让namenode滚动edits并生成一个空的edits.inprogress,滚动edits的目的是给edits打个标记,以后所有新的操作都写入edits.inprogress,其他未合并的edits和fsimage会拷贝到secondarynamenode的本地,然后将拷贝的edits和fsimage加载到内存中进行合并,生成fsimage.chkpoint,然后将fsimage.chkpoint拷贝给namenode,重命名为fsimage后替换掉原来的fsimage。namenode在启动时就只需要加载之前未合并的edits和fsimage即可,因为合并过的edits中的元数据信息已经被记录在fsimage中。[1]使用SNN进行数据恢复
-
先强行杀死NameNode节点
-
kill -9 25764
-
-
删除namenode,先查看下,
[root@BaseNode ~]# ll /var/bdp/hadoop/full/dfs/name/current/ total 19560 -rw-r--r--. 1 root root 42 Nov 4 15:21 edits_0000000000000000001-0000000000000000002 -rw-r--r--. 1 root root 1048576 Nov 4 15:21 edits_0000000000000000003-0000000000000000003 -rw-r--r--. 1 root root 42 Nov 4 15:23 edits_0000000000000000004-0000000000000000005 -rw-r--r--. 1 root root 1048576 Nov 4 15:23 edits_0000000000000000006-0000000000000000006 -rw-r--r--. 1 root root 1048576 Nov 4 15:26 edits_0000000000000000007-0000000000000000007 -rw-r--r--. 1 root root 42 Nov 4 15:29 edits_0000000000000000008-0000000000000000009 -rw-r--r--. 1 root root 1048576 Nov 4 15:56 edits_0000000000000000010-0000000000000000013 -rw-r--r--. 1 root root 42 Nov 4 16:24 edits_0000000000000000014-0000000000000000015 -rw-r--r--. 1 root root 1048576 Nov 4 16:24 edits_0000000000000000016-0000000000000000016 -rw-r--r--. 1 root root 1048576 Nov 4 16:46 edits_0000000000000000017-0000000000000000017 -rw-r--r--. 1 root root 42 Nov 4 16:59 edits_0000000000000000018-0000000000000000019 -rw-r--r--. 1 root root 1048576 Nov 4 17:11 edits_0000000000000000020-0000000000000000023 -rw-r--r--. 1 root root 1048576 Nov 5 15:04 edits_0000000000000000024-0000000000000000024 -rw-r--r--. 1 root root 1048576 Nov 5 15:06 edits_0000000000000000025-0000000000000000025 -rw-r--r--. 1 root root 1048576 Nov 5 15:08 edits_0000000000000000026-0000000000000000026 -rw-r--r--. 1 root root 42 Nov 5 15:13 edits_0000000000000000027-0000000000000000028 -rw-r--r--. 1 root root 1048576 Nov 5 15:13 edits_0000000000000000029-0000000000000000029 -rw-r--r--. 1 root root 1048576 Nov 5 15:13 edits_0000000000000000030-0000000000000000030 -rw-r--r--. 1 root root 42 Nov 5 15:22 edits_0000000000000000031-0000000000000000032 -rw-r--r--. 1 root root 1048576 Nov 5 15:22 edits_0000000000000000033-0000000000000000033 -rw-r--r--. 1 root root 42 Nov 5 15:23 edits_0000000000000000034-0000000000000000035 -rw-r--r--. 1 root root 1048576 Nov 5 15:23 edits_0000000000000000036-0000000000000000036 -rw-r--r--. 1 root root 42 Nov 5 18:32 edits_0000000000000000037-0000000000000000038 -rw-r--r--. 1 root root 42 Nov 5 19:32 edits_0000000000000000039-0000000000000000040 -rw-r--r--. 1 root root 1048576 Nov 5 19:32 edits_0000000000000000041-0000000000000000041 -rw-r--r--. 1 root root 42 Nov 5 19:57 edits_0000000000000000042-0000000000000000043 -rw-r--r--. 1 root root 1048576 Nov 5 19:57 edits_0000000000000000044-0000000000000000044 -rw-r--r--. 1 root root 42 Nov 5 20:21 edits_0000000000000000045-0000000000000000046 -rw-r--r--. 1 root root 1048576 Nov 5 20:21 edits_0000000000000000047-0000000000000000047 -rw-r--r--. 1 root root 42 Nov 5 20:27 edits_0000000000000000048-0000000000000000049 -rw-r--r--. 1 root root 1048576 Nov 5 20:27 edits_0000000000000000050-0000000000000000050 -rw-r--r--. 1 root root 42 Nov 6 12:12 edits_0000000000000000051-0000000000000000052 -rw-r--r--. 1 root root 42 Nov 6 13:12 edits_0000000000000000053-0000000000000000054 -rw-r--r--. 1 root root 42 Nov 6 14:12 edits_0000000000000000055-0000000000000000056 -rw-r--r--. 1 root root 90 Nov 6 15:12 edits_0000000000000000057-0000000000000000059 -rw-r--r--. 1 root root 623 Nov 6 16:12 edits_0000000000000000060-0000000000000000068 -rw-r--r--. 1 root root 42 Nov 6 17:12 edits_0000000000000000069-0000000000000000070 -rw-r--r--. 1 root root 42 Nov 6 18:12 edits_0000000000000000071-0000000000000000072 -rw-r--r--. 1 root root 1048576 Nov 6 18:12 edits_inprogress_0000000000000000073 -rw-r--r--. 1 root root 722 Nov 6 17:12 fsimage_0000000000000000070 -rw-r--r--. 1 root root 62 Nov 6 17:12 fsimage_0000000000000000070.md5 -rw-r--r--. 1 root root 722 Nov 6 18:12 fsimage_0000000000000000072 -rw-r--r--. 1 root root 62 Nov 6 18:12 fsimage_0000000000000000072.md5 -rw-r--r--. 1 root root 3 Nov 6 18:12 seen_txid -rw-r--r--. 1 root root 215 Nov 6 12:11 VERSION
可以看到我们NN里面有很多的日志文件,全部删除掉。
rm -rf /var/bdp/hadoop/full/dfs/name/current/*
然后打不开10.4.1.100:9870了。。。意料之中!
再查看下node1的SSN
[root@zknode1 ~]# ll /var/bdp/hadoop/full/dfs/namesecondary/current/ total 13404 -rw-r--r--. 1 root root 1048576 Nov 4 15:29 edits_0000000000000000006-0000000000000000006 -rw-r--r--. 1 root root 1048576 Nov 4 15:29 edits_0000000000000000007-0000000000000000007 -rw-r--r--. 1 root root 42 Nov 4 15:29 edits_0000000000000000008-0000000000000000009 -rw-r--r--. 1 root root 1048576 Nov 4 16:59 edits_0000000000000000016-0000000000000000016 -rw-r--r--. 1 root root 1048576 Nov 4 16:59 edits_0000000000000000017-0000000000000000017 -rw-r--r--. 1 root root 42 Nov 4 16:59 edits_0000000000000000018-0000000000000000019 -rw-r--r--. 1 root root 1048576 Nov 5 16:13 edits_0000000000000000024-0000000000000000024 -rw-r--r--. 1 root root 42 Nov 5 15:04 edits_0000000000000000024-0000000000000000025 -rw-r--r--. 1 root root 1048576 Nov 5 16:13 edits_0000000000000000025-0000000000000000025 -rw-r--r--. 1 root root 1048576 Nov 5 16:13 edits_0000000000000000026-0000000000000000026 -rw-r--r--. 1 root root 42 Nov 5 16:13 edits_0000000000000000027-0000000000000000028 -rw-r--r--. 1 root root 1048576 Nov 5 16:22 edits_0000000000000000029-0000000000000000029 -rw-r--r--. 1 root root 1048576 Nov 5 16:22 edits_0000000000000000030-0000000000000000030 -rw-r--r--. 1 root root 42 Nov 5 16:22 edits_0000000000000000031-0000000000000000032 -rw-r--r--. 1 root root 1048576 Nov 5 16:23 edits_0000000000000000033-0000000000000000033 -rw-r--r--. 1 root root 42 Nov 5 16:23 edits_0000000000000000034-0000000000000000035 -rw-r--r--. 1 root root 42 Nov 5 19:32 edits_0000000000000000037-0000000000000000038 -rw-r--r--. 1 root root 42 Nov 5 20:32 edits_0000000000000000039-0000000000000000040 -rw-r--r--. 1 root root 1048576 Nov 5 20:57 edits_0000000000000000041-0000000000000000041 -rw-r--r--. 1 root root 42 Nov 5 20:57 edits_0000000000000000042-0000000000000000043 -rw-r--r--. 1 root root 1048576 Nov 5 21:21 edits_0000000000000000044-0000000000000000044 -rw-r--r--. 1 root root 42 Nov 5 21:21 edits_0000000000000000045-0000000000000000046 -rw-r--r--. 1 root root 1048576 Nov 5 21:27 edits_0000000000000000047-0000000000000000047 -rw-r--r--. 1 root root 42 Nov 5 21:27 edits_0000000000000000048-0000000000000000049 -rw-r--r--. 1 root root 42 Nov 6 13:12 edits_0000000000000000051-0000000000000000052 -rw-r--r--. 1 root root 42 Nov 6 14:12 edits_0000000000000000053-0000000000000000054 -rw-r--r--. 1 root root 42 Nov 6 15:12 edits_0000000000000000055-0000000000000000056 -rw-r--r--. 1 root root 90 Nov 6 16:12 edits_0000000000000000057-0000000000000000059 -rw-r--r--. 1 root root 623 Nov 6 17:12 edits_0000000000000000060-0000000000000000068 -rw-r--r--. 1 root root 42 Nov 6 18:12 edits_0000000000000000069-0000000000000000070 -rw-r--r--. 1 root root 42 Nov 6 19:12 edits_0000000000000000071-0000000000000000072 -rw-r--r--. 1 root root 722 Nov 6 18:12 fsimage_0000000000000000070 -rw-r--r--. 1 root root 62 Nov 6 18:12 fsimage_0000000000000000070.md5 -rw-r--r--. 1 root root 722 Nov 6 19:12 fsimage_0000000000000000072 -rw-r--r--. 1 root root 62 Nov 6 19:12 fsimage_0000000000000000072.md5 -rw-r--r--. 1 root root 215 Nov 6 19:12 VERSION
-
-
- 然后拷贝SNN(zknode1)的备份日志文件到NN的日志目录下
scp zknode1:/var/bdp/hadoop/full/dfs/namesecondary/current/* /var/bdp/hadoop/full/dfs/name/current/
-
拷贝完之后,启动NN
hadoop-daemon.sh start namenode
东西也都在:
思考,NN创建新的edits时,SNN才会合并。创建新的edits没来得及合并,就会数据丢失。(日志文件的缺陷,记得学习数据库时也有这个缺点),部分数据丢失该如何解决???嘿嘿,SNN看来不是最终解决方案!!
安全模式
-
集群启动时的一个状态
- 安全模式是HDFS的一种工作状态,处于安全模式的状态下,只向客户端提供文件的只读视图,不接受对命名空间的修改,同时NameNode也不会进行数据块的复制或者删除
-
NameNode启动时
- 首先将镜像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作
- 一旦内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件和一个空的编辑日志
- NameNode开始监听RPC和HTTP请求
- 此时NameNode处于安全模式,只接受客户端的请求
-
系统中的数据块的位置并不是由Name No de维护的,而是以块列表的形式存储在DataNode中
-
安全模式下
- 安全模式下,各个DataNode会向NameNode发送自身的数据块列表
- 当 NameNode有足够的数据块信息后,便在30s之后退出安全模式
- NameNode发现数据节点过少会启动数据复制过程
-
如果NameNode收集Block信息没有达到最少副本数,就会将缺失的副本从有该副本的DataNode上 拷贝到其他的DataNode上
- dfs.namenode.replication.min=2(在官网查询hdfs-default.xml配置文件)
- 但是默认最低副本数为1
- 拷贝的过程中系统还是处于安全模式
-
安全模式相关命令
hadoop dfsadmin -safemode leave #强制NameNode退出安全模式
hadoop dfsadmin -safemode enter #进入安全模式
hadoop dfsadmin -safemode get #查看安全模式状态
hadoop dfsadmin -safemode wait #等待,直到安全模式结束
HDFS权限
- HDFS对权限的控制
- 只能防止好人做错事
- 无法防止坏人做坏事
- 用户说自己是谁,HDFS就认为用户是谁
- 通过权限控制配置文件hadoop-env.sh设置权限
机架感知策略
- 就是当数据崩溃的时候,如何以最少代价去获取到需要的备份数据
- 假如当第一个节点断电或损坏时,会访问第二个节点,恰好若同时第二个节点也是损坏的则访问第三个节点,并以此类推
- 定义这个访问顺序的策略就是机架感知策略
节点距离
- distance(/D1/R1/H1,/D1/R1/H1)=0:也就是说H1和自身的距离是0
- distance(/D1/R1/H1,/D1/R1/H3)=2:从/D1/R1/H1节点出发,需要经过的路径是H1->R1->H3,也就是经过了两个节点。即:同一个机架下的DataNode距离为2。
- distance(/D1/R1/H1,/D1/R2/H4)=4:从/D1/R1/H1节点出发,需要经过的路径是H1->R1->D1->R2->H4,也就是经过了四个节点。即:同一个服务器下的DataNode距离为4。
- distance(/D1/R1/H1,/D2/R3/H7)=6:从/D1/R1/H1节点出发,需要经过的路径是H1->R1->D1->/->D2->R3->H7,也就是经过了6个节点。即不同集群下的datanode距离为6.
机架感知
- 机架感知(rack awareness)是为了保证副本在集群的安全性
- 我们需要将副本放在不同的DataNode上,节点也需要一定的考量
- 可靠性、可用性、宽带消耗
- 第一个节点
- 集群内布(优先考虑和客户端相同节点作为第一个节点)
- 集群外部(选择资源丰富且不繁忙的节点作为第一个节点)
- 第二个节点
- 选择和第一个节点不同机架的其他节点
- 第三个节点
- 与第二个节点相同机架的其他节点
- 第N个节点
- 与前边节点不重复的其他节点
HDFS写数据流程
写数据就是把客户端的数据上传到HDFS
宏观流程
客户端要向HDFS写数据,首先要跟namenode通信以确认可以写文件并获得接收文件block的datanode,然后,
客户端按顺序将文件逐个block传递给相应datanode,并由接收到block的datanode负责向其他datanode复制block的副本。[2]
具体流程如下:
-
与namenode通信请求上传文件,namenode检查目标文件是否已存在,父目录是否存在,是否有足够的空间权限创建这个文件。
-
namenode返回是否可以上传。能:
- 能:NN会针对这个文件创建一个空的Entry对象,并返回状态给DFS
- 不能:直接抛出异常,给客户端错误提示信息
-
DFS接受到成功状态,会创建一个FSDataOutputStream的对象给client使用
-
client向NN请求第一个 block该传输到哪些datanode服务器上
-
namenode返回3个datanode服务器ABC
-
client和DN直接建立连接。请求3台dn中的一台A上传数据(本质上是一个RPC调用,建立pipeline管道),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成,逐级返回客户端
-
client将文件按照块block切分数据,但是会按照packet发送数据。
- 每个packet64k,每个块128M,为2048个packet。
-
client通过pipeline使用FSDateOutputStream开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,此时A设为ack状态。A收到一个packet就会传给B,此时B设为ack状态,B传给C,A设为ack状态,当C将这个packet接收完成后,会响应这个ack给B设为true,B响应给A,A响应给client。
-
当客户端收到成功的状态,就认为某个packet发送成功了,直到当前block的所有的packet发送完成
-
如果客户端接收到最后一个packet的成功状态,说明当前block传输完成。
-
client会将这个消息发送给NN,NN确定传输完成。
-
当一个block传输完成之后,client再次请求namenode上传第二个block的服务器,以此类推。
-
当最后一个block传输完成后,NN会再Entry中存储所有的file和block与DN的映射关系
-
关闭所有FSDataOutputStream
微观流程
-
首先客户端从自己的硬盘中以流的方式读取数据文件到自己的缓存中
-
然后将缓存中的数据以chunk(512B)和checksum(4B)的方式放入到packet(64k)
-
chunk:checksun=128:1
-
checksum:在数据处理和数据通信领域中,用于校验目的的一组数据项的和
-
packet分为两类,一类是实际数据包,另一类是heater包
-
一个packet数据包的组成结构
一个Packet是由Header和Data两部分组成,其中Header部分包含了一个Packet的概要属性信息,相当于data的元数据:
-
-
当packet满的时候,添加到dataqueue
-
datastreamer开始从dataqueue队列上取出一个packet,通过pipleline,取出的时候,也会将packet加入到ackqueue,典型的生产者消费者模式
-
客户端发送一个packet后开始接收ack,会有一个用来接收ack的ResponseProcessor进程,如果收到成功的ack
- 如果某个packet的ack为ture,则从ackqueue中删除这个packet
- 如果某个packet的ack为false,则将ackqueue中的所有的packet重新挂载到发送队列,重新发送
-
最终DFS保存数据的数据格式为
HDFS读数据流程
- 首先客户端发送读数据请求给DFS,申请读取某一个文件
- DFS会访问NameNode来看这个文件在不在。
- 如果文件不存在,则抛出异常
- 如果文件存在,则返回成功状态
- 当返回成功的时候,DFS会创建FSDataInputStream对象,客户端通过该对象读取数据
- 客户端获取文件第一个block信息,返回DN1,BN2,DN8
- 客户端可以知道在哪些地方可以读到需要的数据(Block) ,出于就近原则,客户端会选择最近的节点来读取数据
- 以此类推并读取其他的数据,直到最后一个Block读取结束,会将所有的Block合并为一个文件
- 关闭DFSDataInputStream
参考
[1] .https://blog.csdn.net/weixin_37838429/article/details/81674765
[2].https://www.cnblogs.com/dummyly/p/10080286.html