1 HDFS 的重要概念
1.1 典型的 Master/Slave 架构
- HDFS集群往往是⼀个NameNode(HA架构会有两个NameNode,联邦机制)+多个DataNode组成;
NameNode是集群的主节点,DataNode是集群的从节点。
1.2 分块存储(Block机制)
HDFS 中的⽂件在物理上是分块存储(block)的,块的⼤⼩可以通过配置参数来规定;
- Hadoop2.x版本中默认的block⼤⼩是128M;
如果有两个文件,分别是 200M 和 20M,那么第一个文件先分成两个切片(128M + 72M),第二个文件分成一个切片(20M),共三个Block块。
1.3 命名空间(NameSpace)
HDFS
- ⽀持传统的层次型⽂件组织结构。⽤户或者应⽤程序可以创建⽬录,然后将⽂件保存在这些⽬录⾥。⽂件系统名字空间的层次结构和⼤多数现有的⽂件系统类似:⽤户可以创建、删除、移动或重命名⽂件。
- NameNode
- 负责维护⽂件系统的名字空间,任何对⽂件系统名字空间或属性的修改都将被NameNode 记录下来。
抽象目录树
NameNode 的元数据记录每一个文件所对应的 block 信息(block的 id 以及所在的 DataNode 节点的信息)
1.5 DataNode 数据存储
文件的各个 block 的具体存储管理由 DataNode 节点承担
一个 block 会有多个 DataNode 来存储,DataNode 会定时向 NameNode 来汇报自己持有的 block 信息(**很重要**)
1.6 副本机制
为了容错,文件的所有 block 都会有副本,默认是 3 个(包括本来的block,一共 3 个)。每个文件的 block大小 和 副本系数 都是可配置的
HDFS 是设计成适应 一次写入,多次读出 的场景,且不支持文件的随机修改(支持追加写入,不支持随机更新)
因此,HDFS 适合用来做 大数据分析的底层存储服务,并不适合用来做网盘等应用(修改不方便,延迟大,网络开销大,成本太高)
2 HDFS 架构
2.1 NameNode
- 客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址
- 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据
- DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet(64KB) 为单位来做校验)
客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件
3.2 写
客户端通过 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(64KB)为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3
- dn1 每传一个 packet 会放入一个 确认队列 等待确认
- 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器(重复执行 3 - 7 步)
4 NN 和 2NN
4.1 HDFS 元数据管理机制
- 问题引出
- NameNode如何管理和存储元数据?
- 计算机中存储数据的两种方式:磁盘、内存
- 元数据存储磁盘:速度慢,安全性高
- 元数据存储内存:高效,但安全性低,断电则内存数丢失
- 解决方案:内存 + 磁盘,结合在一起,NameNode = 内存 + fsimage文件(磁盘)
- 那么新问题来了
- 磁盘和内存中元数据如何划分?两个数据一模一样?还是两个数据合并在一起 才是一份完整的数据?
- ① 如果两份数据一模一样的话,客户端 Client 如果对元数据进行增删改操作,则需要时刻保证两份数据的一致性,导致效率变低
- ② 如果两份数据合并后 ==> 完整数据的情况。NameNode 引入了 edits 文件(日志文件,只能追加写入),记录了client 的增删改操作,而不再让 NameNode 把数据 dump 出来形成 fsimage文件(让 NameNode 专注于处理客户端的请求)
- edits文件 文件生成快,恢复慢
- fsimage文件 文件生成慢,恢复快
- 磁盘和内存中元数据如何划分?两个数据一模一样?还是两个数据合并在一起 才是一份完整的数据?
流程分析
第一阶段:NameNode 启动
- 第一次启动 NameNode,格式化后,创建了 镜像文件fsimage 和 编辑日志edits 空白文件。如果不是第一次启动,则直接加载 日志文件edits 和 镜像文件fsimage 到内存中
- 客户端对元数据进行 增删改 的请求
- NameNode 记录操作日志,更新日志。日志内容到达一定量后,滚动日志
- 所谓滚动日志,即 把前一阶段的日志保存成一个日志文件,再新生成一个文件,新生成文件后缀带有 inprogress 字样
- NameNode 在内存中对数据进行增删改操作
第二阶段:Secondary NameNode 工作
- Secondary NameNode 询问是否 NameNode 需要 CheckPoint,然后得到来自 NameNode 的是否执行检查点操作的 响应
- 若响应是 执行检查点操作(此时 NameNode 中的edits日志也要进行滚动),Secondary NameNode 便开始执行 CheckPoint,然后从 NameNode 中拷贝 滚动前的edits日志(新生成的日志不包括在内)和 镜像文件fsimage,然后再 Secondary NameNode 中合并这两个文件
- 利用合并后的文件生成 新的镜像文件 fsimage.chkpoint
- 拷贝该文件到 NameNode 中
- NameNode 将 得到的文件 fsimage.chkpoint 更名为 fsimage
4.2 FsImage 与 Edits 文件解析
NameNode 在执行格式化之后,会在
/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current
目录产生以下文件- Fsimage
- 是 namenode 中关于元数据的镜像,一般称为检查点,这里包含了 HDFS 文件系统所有目录以及文件相关信息(Block数量,副本数量,权限等信息)
- Edits
- 存储了客户端对 HDFS 文件系统所有的更新操作记录,Client 对 HDFS 文件系统所有的更新操作都会被记录到 Edits 文件中(不包括查询操作)
- seen_txid
- 该文件是保存了一个数字,数字对应着最后一个 Edits 文件名的数字
- VERSION
- 该文件记录 namenode 的一些版本号信息,比如:ClusterId,namespaceID 等
- Fsimage
NameNode 启动时会将 Fsimage 文件加载到内存中,同时也把之前未合并元数据的 Edits 文件加载,集合两个文件中的元数据,这样保证了 NameNode 中的元数据是最新最全的。通俗点说就是 NameNode 启动时把 Fsimage 和Edits 文件进行了合并
Fsimage 文件内容
官方地址 https://hadoop.apache.org/docs/r2.9.2/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html
- 查看
oiv
和oev
命令
.
- 基本语法
hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径
- 实例
hdfs oiv -p XML -i fsimage_0000000000000000265 -o /opt/lagou/servers/fsimage.xml
- 查看文件
```xml
<?xml version=”1.0”?>
-63 1 826afbeae31ca687bc2f8471dc841b66ed2c6704 722925838 1000 1049 0 1073741873 621 16487 36 16385 DIRECTORY 1604115316122 root:supergroup:0777 9223372036854775807 -1 16389 DIRECTORY wcinput 1604023034981 root:supergroup:0777 -1 -1
- **问题:Fsimage 中为什么没有记录块所对应 DataNode ?**
- **答案:在集群启动后,NameNode 要求 DataNode 上报数据块信息,并间隔一段时间后再次上报**
<a name="YW49O"></a>
### Edits 文件内容
1. 基本语法
- `hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径`
2. 案例实操
- `hdfs oev -p XML -i edits_0000000000000000266-0000000000000000267 -o /opt/lagou/servers/hadoop-2.9.2/edits.xml`
- 查看文件内容
```xml
<?xml version="1.0" encoding="utf-8"?>
<EDITS>
<EDITS_VERSION>-63</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>113</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_PERMISSIONS</OPCODE>
<DATA>
<TXID>114</TXID>
<SRC>/wcoutput/_SUCCESS</SRC>
<MODE>493</MODE>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_PERMISSIONS</OPCODE>
<DATA>
<TXID>115</TXID>
<SRC>/wcoutput/part-r-00000</SRC>
<MODE>493</MODE>
</DATA>
</RECORD>
</EDITS>
...
- 备注:Edits 中只记录了更新相关的操作,查询或者下载文件并不会记录在内!!!
- 问题:NameNode 启动时如何确定加载哪些 Edits 文件呢?
答案:需要借助 fsimage 文件最后数字编码,来确定哪些 edits 之前是没有合并到 fsimage 中,启动时只需要加载那些未合并的 edits 文件即可。
checkpoint 周期
通过
hdfs-default.xml
进行配置(在 Java依赖库中查找该文件) ```xmldfs.namenode.checkpoint.period 3600
<a name="lJbKL"></a>
### NN 故障处理
- **NameNode 故障后,HDFS 集群就无法正常工作**,因为 HDFS 文件系统的元数据需要由 NameNode 来管理维护并与 Client 交互;如果元数据出现损坏和丢失,同样会导致 NameNode无法正常工作,进而 HDFS 文件系统无法正常对外提供服务
- 如果 **元数据出现丢失损坏如何恢复 **呢?
- 1. 将 2NN 的元数据拷贝到 NN 的节点下
- 此种方式会存在 元数据的丢失
- 2. **搭建 HDFS 的 HA(高可用)集群,解决 NN 的单点故障问题**
- 借助 Zookeeper 实现 HA,一个 Active 的 NameNode,一个是 Standby 的 NameNode
- [https://www.yuque.com/raylee916/pqs5c3/gx9g61#dpjg2](https://www.yuque.com/raylee916/pqs5c3/gx9g61#dpjg2)
<a name="S8Jvb"></a>
## 4.3 限额、归档、集群安全模式
<a name="qrX9f"></a>
### HDFS 文件限额配置
- HDFS 文件的限额配置允许我们以文件大小或者文件个数来限制我们在某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘等限制每个用户允许上传的最大的文件的量
- **数量限额**
```shell
#创建 hdfs 文件夹
hdfs dfs -mkdir -p /user/root/lagou
#给该文件夹下面设置最多上传两个文件
hdfs dfsadmin -setQuota 2 /user/root/lagou
# 清除文件数量限制
hdfs dfsadmin -clrQuota /user/root/lagou
上传超过 4Kb 的文件,会提示文件超过限额
hdfs dfs -put /export/softwares/xxx.tar.gz /user/root/lagou
清除空间限额
hdfs dfsadmin -clrSpaceQuota /user/root/lagou
查看 hdfs 文件限额数量
hdfs dfs -count -q -h /user/root/lagou
```
Hadoop 归档技术
- 主要解决 HDFS 集群存在大量 小文件 的问题
- 由于大量量小文件会占用 NameNode 的内存,因此对于 HDFS 来说存储大量小文件造成 NameNode 内存资源的浪费
- Hadoop存档文件HAR文件,是一个更高效的文件存档工具,HAR文件是由一组文件通过 archive 工具创建而来,在减少了 NameNode 的内存使用的同时,可以对文件进行透明的访问,通俗来说就是HAR文件对NameNode来说是一个文件减少了内存的浪费,对于实际操作处理文件依然是一个一个独立的文件
案例
- 启动 YARN 集群
start-yarn.sh
- 启动 YARN 集群
- 归档文件
- 把
/user/lagou/input
目录里面的所有文件归档成一个叫input.har
的归档文件,并把归档后文件存储到/user/lagou/output
路径下 bin/hadoop archive -archiveName input.har –p /user/root/input /user/root/output
- 把
- 归档文件
- 查看归档
hadoop fs -lsr /user/root/output/input.har
hadoop fs -lsr har:///user/root/output/input.har
- 查看归档
安全模式是 HDFS 所处的一种特殊状态,在这种状态下,文件系统 只接受读数据请求,⽽不不接受删除、修改等变更请求。在 NameNode 主节点启动时,HDFS 首先进入安全模式,DataNode 在启动的时候会向 NameNode 汇报可用的 block 等状态,当整个系统达到安全标准时,HDFS 自动离开安全模式。如果 HDFS 出于安全模式下,则文件 block 不能进行任何的副本复制操作,因此达到最小的副本数量要求是基于 DataNode 启动时的状态来判定的,启动时不会再做任何复制(从而达到最小副本数量要求),HDFS集群刚启动的时候,默认30秒钟的时间是出于安全期的,只有过了了 30S 之后,集群脱离了了安全期,然后才可以对集群进行操作
- 相关命令
hdfs dfsadmin -safemode