声明: 1. 本文为我的个人复习总结, 并非那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
2. 由于是个人总结, 所以用最精简的话语来写文章
3. 若有错误不当之处, 请指出
HDFS存储优缺点:
-
优点
- 高容错, 因为它有多个副本
- 可处理大数据, 文件数量可达百万
-
缺点
-
HDFS可以追加,但不能修改某一条数据,若实在想修改,只能下载下来原文件进行修改后重新上传覆盖
-
不适合低延迟数据访问,如毫秒级
-
无法高效存储大量小文件
- 小文件导致数量太多, 浪费了NameNode存储文件目录和块信息(150K)等元数据
- 小文件导致数量太多, 导致寻址时间很长, 甚至大于读取(传输)时间
- 从MR计算的角度, 即便再小的一个切片, 也要启动一个MapTask
解决办法:
- 从数据源头解决, 产生文件时,积压到一定量再进行输出, 或到了最后末尾不满足阈值了,也输出
- har归档
- combineInputformat 减少切片个数,进而减少的是maptask
- 开启JVM重用
-
HDFS组成架构:
-
NameNode(NN) 管理者,记录元数据信息(内存)
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块(Block)映射信息
-
DataNode 执行者,记录实际数据,也记录自身的元数据(磁盘)
-
Secondary NameNode 不常用,是NN的助手,当NN挂掉的时候它不能立即上任
- 分担NN的工作, 比如定期合并Fsimage和Edits,并推送给NN
- 对NN进行备份
Client:
1. 把文件切分成块 2. 与NN交互获取文件的位置信息 3. 与DataNode交互, 读写文件 4. 管理HDFS, 比如对NN初次格式化
文件块:
磁盘传输速率普遍为100MB/s, 寻址时间为读取(传输)时间的1%最好
-
设置大了,在开的Map太少,并行度较低
-
设置小了,小文件过多导致寻址时间较长
HDFS的Shell操作:
上传到HDFS:
从本地剪切到HDFS: hadoop fs -moveFromLocal ./kongming.txt /sanguo/shuguo (/sanguo/shuguo文件夹需要提前建立)
从本地拷贝到HDFS: hadoop fs -copyFromLocal README.txt /data
在一个文件末尾追加另一个文件的数据: hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt
从HDFS下载:
从HDFS拷贝到本地: hadoop fs **-copyToLocal **/sanguo/shuguo/kongming.txt ./
合并下载多个文件: hadoop fs -getmerge /user/atguigu/test/* ./temp.txt
常用命令:
hadoop fs -ls /
hadoop fs -mkdir -p /sanguo/shuguo
hadoop fs -cat /sanguo/shuguo/kongming.txt
hadoop fs -chmod 666 /sanguo/shuguo/kongming.txt
hadoop fs -chown atguigu:atguigu /sanguo/shuguo/kongming.txt
hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt
hadoop fs -mv /zhuge.txt /sanguo/shuguo/
hadoop fs -tail /sanguo/shuguo/kongming.txt
hadoop fs -rm /user/atguigu/test/jinlian2.txt
hadoop fs -rmdir /test
hadoop fs -du -s -h /user/atguigu/test
hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt (设置副本数量, 只有3台机器3个DataNode,那么副本实际还是3,但在加机器后它会自动扩充直到10为止)
HDFS写数据流程
如果Client一个人对应多个DN进行写,
好处是可以并行写;
坏处是若有一个DN阻塞卡住, 那么Client就会阻塞
做法: Client将一个400M的文件分块写到3个DN里, Client只连接DN1, DN1在一边写到自己磁盘,一边把不属于它的数据传下去传给DN2
Packet 64k(chunk 512Byte + chunksum校验 4Byte)
(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
(2)NameNode返回是否可以上传。
(3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
(4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道pipeline建立完成
(6)dn1、dn2、dn3逐级应答客户端。
(7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
(8)当一个Block传输完成之后,客户端再次请求NameNode第二个Block上传到哪个DN。(重复执行3-7步)
注意:
packet1发完了,才能发packet2
要是中途有的DataNode不可用了, 那么这个DataNode会被从pipeline里移除; 传完后NameNode知道这个数据备份数不够,再找个DataNode去同步这个数据,凑够备份数
HDFS读数据流程
(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址
(2)挑选一台多个副本间离的较近的DataNode服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件
单位:
- Block 128M, 物理上的文件数据块
- Packet 64k, Client发给DataNode, 以及pipeline的那一堆DataNode间传输用的数据包, 包含实际数据+Chunk+ChunkSum
- Chunk(512Byte) ChunkSum(4Byte), 用来验证数据是否损坏的
- 切片 InputFormat读入时, 逻辑上的文件数据块, 按Block大小来切块; 但还要看剩余部分是否在1.1倍Block范围内,不超过则剩余部分就按一块来切; 所以切片最大为1.1倍Block
网络拓扑-节点距离计算
规则: NameNode会选择距离待上传数据最近距离的DataNode接收数据, 节点距离为两个节点到达最近的共同祖先的距离总和
机架感知(副本存储节点选择)
存储副本时,如果 所有副本都在同一个机器,那么这台机器崩了所有副本就都没了,不安全;又考虑太远会通信延迟,所以采取以下这种做法
NameNode和SecondaryNameNode
FsImage, Edits, SecondaryNameNode
NN的元数据在内存里, FsImage是对元数据的备份写到磁盘, 引发了问题:
- 内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低
- 如果不更新,就会发生一致性问题
- 如果FsImage没来的及写完到磁盘, 一旦NameNode节点断电,就会产生数据丢失
解决方案:
引入Edits文件(只记录日志不执行接过,只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中
一旦NameNode节点断电,可以通过FsImage和Edits的合并,FsImage+Edits=内存元数据, 来合成元数据,
引发新的问题:
-
如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低
-
一旦断电,恢复元数据需要的时间过长
解决方案:
定期进行FsImage和Edits的合并, 引发新的问题
- 如果这个操作由NameNode节点完成,又会效率过低
解决方案: 引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并, 以及备份NameNode的FsImage数据
工作机制:
1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。
如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行CheckPoint。
(3)NameNode滚动正在写的Edits日志。
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名成fsimage。
SecondaryNamaNode得不到最新的edits_inprogress的文件
FsImage只会合并序号比它大的Edits文件,小于等于的不会合并
Fsimage和Edits解析
VERSION里存储的namespace,clusterID等信息
FsImage和Edits的合并:
- 开关机时
- 1小时到了
- Edits记录的操作日志超过一百万
FsImage:
查看命令:
hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml
得到结果: 里面有父子node关系的记录
Fsimage中没有记录块所对应DataNode,为什么?
因为在集群启动后,要求DataNode上报数据块信息,并间隔1小时后再次上报
Edits:
查看命令:
hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml
CheckPoint时间设置
1)通常情况下,SecondaryNameNode每隔一小时执行一次。
hdfs-default.xml
<property> <name>dfs.namenode.checkpoint.period</name> <value>3600</value> </property>
2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作动作次数</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >
NameNode故障处理
可以采用如下两种方法恢复数据
1)将SecondaryNameNode中数据拷贝到NameNode存储数据的目录
kill -9 NameNode进程
删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/tmp/dfs/name)
- 拷贝SecondaryNameNode中数据到原NameNode存储数据目录
scp -r atguigu@hadoop104:/opt/module/hadoop-3.1.3/data/tmp/dfs/namesecondary/* $HADOOP_HOME/data/tmp/dfs/name/
重新启动NameNode
hdfs --daemon start namenode
2)使用-importCheckpoint选项启动NameNode守护进程,从而将SecondaryNameNode中数据拷贝到NameNode目录中
修改hdfs-site.xml中的
<property> <name>dfs.namenode.name.dir</name> <value>/opt/module/hadoop-3.1.3/data/tmp/dfs/name</value> </property>
kill -9 NameNode进程
删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/tmp/dfs/name)
如果SecondaryNameNode不和NameNode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件
scp -r atguigu@hadoop104:/opt/module/hadoop-3.1.3/data/tmp/dfs/namesecondary $HADOOP_HOME/data/tmp/dfs rm -rf $HADOOP_HOME/data/tmp/dfsnamesecondary/in_use.lock
导入检查点数据(等待一会ctrl+c结束掉)
bin/hdfs namenode -importCheckpoint
6. 启动NameNode
hdfs --daemon start namenode
安全模式
安全模式期间可读不可写
(1)bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)
(2)bin/hdfs dfsadmin -safemode enter (功能描述:进入安全模式状态)
(3)bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
(4)bin/hdfs dfsadmin -safemode wait (功能描述: 等待安全模式状态)
DataNode
工作机制:
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据: 包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息
(3)心跳是每3秒一次,心跳返回结果带有 “NameNode给该DataNode的命令”, 如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟30秒没有收到某个DataNode的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。
副本默认有3个, 原件也是副本
数据完整性
DataNode节点上的数据损坏了,避免读取损坏信息
解决办法:
-
当DataNode读取Block的时候,它会计算CheckSum; 如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏, Client读取其他DataNode上的Block。然后此节点再将此Block数据 向别的节点副本进行同步修复
-
DataNode在其文件创建后周期验证CheckSum
-
校验: 奇偶校验&crc校验
掉线时
hdfs-default.xml参数
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value> <!--毫秒-->
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value> <!--秒-->
</property>