1. Hadoop概述
1.1 Hadoop是什么
- 高可靠
Hadoop底层维护多个数据副本,即使某个计算元素或存储出现故障,也不会导致数据的丢失。
- 高扩展性
在集群间分配任务数据,可方便的扩展数以千计的节点。
- 高效性
在MR的思想下,Hadoop是并行工作的,以加快任务处理速度。
- 高容错性
1.3 Hadoop组成
1.3.1 HDFS
分布式文件系统。
- NameNode
存储文件的元数据,如文件名、文件结构、文件目录属性,以及每个文件所在的块列表和块所在的DataNode等。
- DataNode
在本地文件系统中存储文件块数据,以及块数据的校验和。
- Secondary NameNode
1.3.2 YARN
1.3.3 MapReduce
分布式计算。
1)Map阶段:并行处理输入数据;
2)Reduce阶段:对Map结果进行汇总。
1.4 常用端口号
- hadoop 3.x
HDFS NameNode内部通信端口:8020/9000/9820
HDFS NameNode对用户的查询端口:9870
Yarn查看任务运行情况的:8088
历史服务器:19888
- hadoop 2.x
HDFS NameNode内部通信端口:8020/9000
HDFS NameNode对用户的查询端口:50070
Yarn查看任务运行情况的:8088
历史服务器:19888
2. HDFS
2.1 HDFS概述
2.1.1 定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭之后就不需要改变。
2.1.2 优缺点
- 优点
- 高容错性:数据自动保存多个副本。通过增加副本的形式,提高容错性。
- 适合处理大规模数据。
- 可构建在廉价机器上。
缺点
NameNode
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块映射信息
- 处理客户端读写请求
- DataNode
- 存储实际的数据块
- 执行数据块的读写操作
- Client
- 文件切分。文件上传HDFS的时候,Client将文件切分成一个个Block,然后进行上传
- 与NameNode交互,获取文件的位置信息
- 与DataNode交互,读取或写入数据
- Client提供一些命令来管理HDFS,如NameNode格式化
- Client可以通过一些命令管理HDFS,比如对HDFS增删改查操作
- Secondary NameNode
- 并非NameNode的热备,当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务
- 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode
-
2.1.4 HDFS文件块大小
HDFS的文件在物理上是分块存储,块的大小可以通过配置参数(dfs.blocksize)来规定。hadoop2.x/3.x默认128MB,1.x默认64MB。
为什么块的大小不能设置太小,也不能设置太大? 太小,会增加寻址时间,程序一直在找块的开始位置;
- 太大,从磁盘传输数据的时间会明显大于定位这个快开始位置所需的时间。导致程序在处理这块数据时会非常慢;
- HDFS块的大小设置取决于磁盘传输速率。
2.2 HDFS读写流程
2.2.1 写流程

- 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
- NameNode返回是否可以上传。
- 客户端请求第一个Block上传到哪几个DataNode服务器上。
- NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
- 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
- dn1、dn2、dn3逐级应答客户端。
- 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
- 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
2.2.2 读数据

- Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
- NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode 都会返回含有该 block 副本的 DataNode 地址; 这些返回的 DN 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离 Client 近的排靠前;心跳机制中超时汇报的 DN 状态为 STALE,这样的排靠后;
- Client 选取排序靠前的 DataNode 来读取 block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);
- 底层上本质是建立 Socket Stream(FSDataInputStream),重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕;
- 当读完列表的 block 后,若文件读取还没有结束,客户端会继续向NameNode 获取下一批的 block 列表;
- 读取完一个 block 都会进行 checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的DataNode 继续读。
- read 方法是并行的读取 block 信息,不是一块一块的读取;NameNode 只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
- 最终读取来所有的 block 会合并成一个完整的最终文件。
从 HDFS 文件读写过程中,可以看出,HDFS 文件写入时是串行写入的,数据包先发送给节点A,然后节点A发送给B,B在给C;而HDFS文件读取是并行的, 客户端 Client 直接并行读取block所在的节点。
3. NameNode和Secondary NameNode
3.1 NN和2NN工作机制
NameNode中的元数据是存储在哪里的?
首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。
3.1.1 NameNode工作机制

- 第一阶段:NameNode启动
- 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
- 客户端对元数据进行增删改的请求。
- NameNode记录操作日志,更新滚动日志。
- NameNode在内存中对元数据进行增删改。
- 第二阶段:Secondary NameNode工作
- Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
- Secondary NameNode请求执行CheckPoint。
- NameNode滚动正在写的Edits日志。
- 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
- Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
- 生成新的镜像文件fsimage.chkpoint。
- 拷贝fsimage.chkpoint到NameNode。
- NameNode将fsimage.chkpoint重新命名成fsimage。
3.2 Fsimage和Edits
NameNode被格式化之后,会产生如下文件:
- Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
- Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
- seen_txid文件:保存的是一个数字,就是最后一个Edits的数字。
- 每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。
3.1.3 Fsimage文件查看
oiv 和 oev 命令。 ```shell hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
**1、Fsimage中没有记录块所对应DataNode,为什么?**<br />在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。<br />**2、NameNode如何确定下次开机启动的时候合并哪些Edits?**<br />NameNode启动的时候合并的是上次停机前正在写入的Edits,即edits_inprogress_xxx,根据seen_txid里面记录最新的Fsimage(镜像文件)的值去合并Edits(编辑日志)。<a name="j0n2o"></a>### 3.3 Checkpoint时间设置- 通常情况下,SecondaryNameNode每隔一小时执行一次。```xml[hdfs-default.xml]<property><name>dfs.namenode.checkpoint.period</name><value>3600s</value></property>
- 一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。
```xml
[hdfs-default.xml]
dfs.namenode.checkpoint.txns 1000000 操作动作次数
<a name="virkz"></a>
## 4. DataNode
<a name="J81Ea"></a>
### 4.1 DataNode工作机制

1. 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
1. DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息。xml
DN向NN汇报当前解读信息的时间间隔,默认6小时;
DN扫描自己节点块信息列表的时间,默认6小时
3. 心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟+30秒没有收到某个DataNode的心跳,则认为该节点不可用。
3. 集群运行中可以安全加入和退出一些机器。
<a name="y1A4K"></a>
### 4.2 数据完整性
**思考:**如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?<br />如下是DataNode节点保证数据完整性的方法。
1. 当DataNode读取Block的时候,它会计算CheckSum。
1. 如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
1. Client读取其他DataNode上的Block。
1. 常见的校验算法crc(32),md5(128),sha1(160)
1. DataNode在其文件创建后周期验证CheckSum。

<a name="DspuZ"></a>
### 4.3 DataNode掉线时限参数设置
datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。**HDFS默认的超时时长为10分钟+30秒**。如果定义超时时间为timeout,则超时时长的计算公式为:
> timeout = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
> 默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。xml
<a name="pKmmQ"></a>### 4.4 DataNode目录结构和namenode不同的是,datanode的存储目录是初始阶段自动创建的,不需要额外格式化。```shell> cd /nkong/hdfs/datanode/current> cat VERSION#Wed Apr 27 09:42:08 CST 2022storageID=DS-f8149c70-2c16-469f-8ac0-d245e2dcec90clusterID=CID-43572805-1382-439c-827d-5d420fe60d29cTime=0datanodeUuid=2f332a3e-bfb4-4538-907b-6c2f5632c450storageType=DATA_NODElayoutVersion=-57
- storageID:存储id号。
- clusterID集群id,全局唯一。
- cTime属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0;但是在文件系统升级之后,该值会更新到新的时间戳。
- datanodeUuid:datanode的唯一识别码。
- storageType:存储类型。
- layoutVersion是一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。
5. HDFS其他重要功能
5.1 多个集群之间的数据拷贝
在我们实际工作当中,极有可能会遇到将测试集群的数据拷贝到生产环境集群,或者将生产环境集群的数据拷贝到测试集群,那么就需要我们在多个集群之间进行数据的远程拷贝,hadoop自带也有命令可以帮我们实现这个功能 ```shell
本地文件拷贝 scp命令
scp -r jdk-8u141-linux-x64.tar.gz root@node02:/export/
集群之间的数据拷贝
bin/hadoop distcp hdfs://node01:8020/jdk-8u141-linux-x64.tar.gz hdfs://node02:8020/ ```
5.2 hadoop归档文件archive
每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如,一个1MB的文件以大小为128MB的块存储,使用的是1MB的磁盘空间,而不是128MB。
Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明的访问。具体说来,Hadoop存档文件可以用作MapReduce的输入。
创建归档文件
- 第一步:创建归档文件
注意:归档文件一定要保证yarn集群启动
bin/hadoop archive -archiveName myhar.har -p /user/root /user
- 第二步:查看归档文件内容 ```shell hdfs dfs -lsr /user/myhar.har
hdfs dfs -lsr har:///user/myhar.har
- 第三步:解压归档文件
```shell
hdfs dfs -mkdir -p /user/har
hdfs dfs -cp har:///user/myhar.har/* /user/har/
5.3 hdfs快照snapShot管理
快照顾名思义,就是相当于对我们的hdfs文件系统做一个备份,我们可以通过快照对我们指定的文件夹设置备份,但是添加快照之后,并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件
快照使用基本语法
1、 开启指定目录的快照功能 hdfs dfsadmin -allowSnapshot 路径 2、禁用指定目录的快照功能(默认就是禁用状态) hdfs dfsadmin -disallowSnapshot 路径 3、给某个路径创建快照snapshot hdfs dfs -createSnapshot 路径 4、指定快照名称进行创建快照snapshot hdfs dfs -createSanpshot 路径 名称 5、给快照重新命名 hdfs dfs -renameSnapshot 路径 旧名称 新名称 6、列出当前用户所有可快照目录 hdfs lsSnapshottableDir 7、比较两个快照的目录不同之处 hdfs snapshotDiff 路径1 路径2 8、删除快照snapshot hdfs dfs -deleteSnapshot <path> <snapshotName>5.4 hdfs回收站
任何一个文件系统,基本上都会有垃圾桶机制,也就是删除的文件,不会直接彻底清掉,我们一把都是将文件放置到垃圾桶当中去,过一段时间之后,自动清空垃圾桶当中的文件,这样对于文件的安全删除比较有保证,避免我们一些误操作,导致误删除文件或者数据
回收站配置两个参数
默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间。
默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间。
要求fs.trash.checkpoint.interval<=fs.trash.interval。
- 启用回收站
修改所有服务器的core-site.xml配置文件
<!-- 开启hdfs的垃圾桶机制,删除掉的数据可以从垃圾桶中回收,单位分钟 -->
<property>
<name>fs.trash.interval</name>
<value>10080</value>
</property>
- 查看回收站
回收站在集群的 /user/root/.Trash/ 这个路径下
注意:通过javaAPI删除的数据,不会进入回收站,需要调用moveToTrash()才会进入回收站
//使用回收站的方式: 删除数据
@Test
public void deleteFile() throws Exception{
//1. 获取FileSystem对象
Configuration configuration = new Configuration();
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), configuration, "root");
//2. 执行删除操作
// fileSystem.delete(); 这种操作会直接将数据删除, 不会进入垃圾桶
Trash trash = new Trash(fileSystem,configuration);
boolean flag = trash.isEnabled(); // 是否已经开启了垃圾桶机制
System.out.println(flag);
trash.moveToTrash(new Path("/quota"));
//3. 释放资源
fileSystem.close();
}
恢复回收站数据
> hdfs dfs -mv trashFileDir hdfsdir # trashFileDir:回收站的文件路径 # hdfsdir:将文件移动到hdfs的哪个路径下清空回收站
> hdfs dfs -expunge

