type
status
date
slug
summary
tags
category
icon
password

一、HDFS概述
在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统。
HDFS(Hadoop Distributed File System)是 Hadoop 项目的一个子项目。是 Hadoop 的核心组件之一, Hadoop 非常适于存储大型数据 (比如 TB 和 PB),其就是使用 HDFS 作为存储系统. HDFS 使用多台计算机存储文件,并且提供统一的访问接口,像是访问一个普通文件系统一样使用分布式文件系统。

二、HDFS架构
HDFS是主从(Mater/Slave)体系结构,由三部分组成:NameNode 和 DataNode 以及 SecondaryNamenode:
- NameNode 负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。
- DataNode 负责管理用户的文件数据块,每一个数据块都可以在多个 DataNode 上存储多个副本,默认为3个。
- Secondary NameNode 用来监控 HDFS 状态的辅助后台程序,每隔一段时间获取 HDFS 元数据的快照。最主要作用是辅助 NameNode 管理元数据信息。

NameNode | DataNode |
存储元数据 | 存储文件内容 |
元数据保存在内存中 | 文件内容保存在磁盘 |
保存文件、block、DataNode之间的映射关系 | 维护了blockid到DataNode本地文件的映射关系 |
三、HDFS特性
首先,HDFS是一个文件系统,用于存储文件,通过统一的命名空间目录树来定位文件。
其次,它是分布式的,由多台服务器协同工作实现其功能,集群中的每台服务器都有特定角色。
1.master/slave架构
HDFS采用master/slave架构。一个HDFS集群通常由一个NameNode和多个DataNode组成。NameNode是集群的主节点,DataNode是从节点,两种角色各司其职,共同协调完成分布式文件存储服务。
2.分块存储
HDFS中的文件在物理上是分块存储(block)的,块的大小可通过配置参数设定,在Hadoop 2.x版本中默认为128M。
3.名字空间
HDFS支持传统的层次型文件组织结构。用户或应用程序可以创建目录并在这些目录中保存文件。文件系统的名字空间结构与大多数现有文件系统类似:用户可以创建、删除、移动或重命名文件。
NameNode负责维护文件系统的名字空间,任何对文件系统名字空间或属性的修改都会被NameNode记录。
HDFS为客户端提供统一的抽象目录树,客户端通过路径访问文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data。
4.NameNode元数据管理
目录结构和文件分块位置信息被称为元数据。NameNode负责维护整个HDFS文件系统的目录树结构,以及每个文件对应的block块信息(block的id及所在的DataNode服务器)。
5.DataNode数据存储
HDFS 将所有的文件全部抽象成为 block 块来进行存储,不管文件大小,全部一视同仁都是以 block 块的统一大小和形式进行存储,方便我们的分布式文件系统对文件的管理。所有的文件都是以 block 块的方式存放在 hdfs 文件系统当中,在 Hadoop 1 版本当中,文件的 block 块默认大小是 64M,Hadoop 2 版本当中,文件的 block 块大小默认是128M,block块的大小可以通过 hdfs-site.xml 当中的配置文件进行指定。文件各个block的具体存储由DataNode节点管理。每个block可存在于多个DataNode上。DataNode需定期向NameNode报告自己持有的block信息。系统会存储多个副本(副本数量可通过参数dfs.replication设置,默认为3)。
文件组织方式抽象为块的优势:
- 一个文件有可能大于集群中任意一个磁盘 10T*3/128 = xxx块 2T,2T,2T 文件方式存—–>多个block块,这些block块属于一个文件
- 使用块抽象而不是文件可以简化存储子系统
- 块非常适合用于数据备份进而提供数据容错能力和可用性
6.副本机制
为了容错,HDFS中文件的所有block都有副本。每个文件的block大小和副本数量都是可配置的。应用程序可以指定文件的副本数,副本系数既可在文件创建时指定,也可以后续更改。Hadoop设计时考虑了数据的安全性和效率,数据文件默认在HDFS上存放三份,存储策略为:本地一份,同机架内其它节点一份,不同机架的节点一份。
7.集中式缓存管理
集中式缓存管理也叫堆外块缓存,DataNode 从磁盘读取数据块(block)供客户端或计算任务使用。对于访问频繁的文件,可以把这些文件对应的 block 缓存在 DataNode 的内存中,而且是堆外内存(off-heap),避免 JVM GC 的影响。好处是HDFS 客户端或者 MapReduce/Spark 等任务,如果调度到这些缓存了 block 的 DataNode 上,可以直接从内存中读取,速度比从磁盘快很多。
缓存的分配原则:每个 block 默认只会被缓存到 一个 DataNode 的内存中(节省内存资源,避免冗余占用),如果你需要更高的并发读取能力,可以针对文件设置多个缓存副本(比如 2 个 DataNode 都缓存这个块)。缓存是通过 NameNode 管理的,DataNode 会根据 NameNode 下发的缓存指令来加载对应的 block 到内存中。
8.一次写入,多次读出
HDFS设计为适应一次写入、多次读出的场景,且不支持文件修改。因此,HDFS适合作为大数据分析的底层存储服务,但不适合用作网盘等应用,因为修改不便、延迟大、网络开销大、成本高。
9.HDFS文件权限机制
hdfs的文件权限机制与linux系统的文件权限机制类似
r:read w:write x:execute
权限x对于文件表示忽略,对于文件夹表示是否有权限访问其内容
10.安全模式
安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在,当整个系统达到安全标准时,HDFS自动离开安全模式。HDFS安全模式最小持续时间为30秒
假设我们设置的副本数(即参数dfs.replication)是3,那么在DataNode上应该存在3个副本。如果只有2个副本,则副本率为2/3≈0.666。HDFS默认要求的副本率为0.999。由于我们的副本率0.666明显低于0.999,系统会自动将副本复制到其他DataNode,确保副本率不低于0.999。相反,如果系统中有5个副本,超过了我们设定的3个副本,系统会删除多余的2个副本。
四、HDFS命令行
常见的HDFS命令按照命令格式可以分为Linux风格命令以及独有风格命令,具体如下
1.Linux 风格(同名或语义近似)
命令 | 作用 | 示例 |
help | 查看命令帮助 | hdfs dfs -help ls |
ls | 列目录 | hdfs dfs -ls /user/hadoop/ |
lsr | 递归列目录 | hdfs dfs -lsr /user/hadoop/ |
mkdir | 创建目录,不加-p父目录必须存在, 加上-p之后可以递归创建目录 | hdfs dfs -mkdir /user/hadoop/data
hdfs dfs -mkdir -p /user/hadoop/data/raw |
mv | 移动/改名(HDFS 内部) | hdfs dfs -mv /user/hadoop/file1 /user/hadoop/old/ |
rm | 删除文件/目录 -r参数代表递归删除,-skipTrash为物理删除 | hdfs dfs -rm /user/hadoop/file1
hdfs dfs -rm -r -skipTrash /user/hadoop/tmp/ |
cp | HDFS 内部复制 | hdfs dfs -cp /user/hadoop/file1 /user/hadoop/backup/ |
cat | 查看文件内容 | hdfs dfs -cat /user/hadoop/file1 |
tail | 查看文件尾部 | hdfs dfs -tail /user/hadoop/log.txt |
text | 将压缩文件解码为文本 | hdfs dfs -text /user/hadoop/data.gz |
chmod | 修改权限 | hdfs dfs -chmod 755 /user/hadoop/script.sh |
chown | 修改属主 | hdfs dfs -chown hadoop:dev /user/hadoop/data |
df | 查看 HDFS 剩余空间 | hdfs dfs -df -h / |
du | 查看目录/文件占用 | hdfs dfs -du -h /user/hadoop/data |
2.Hadoop/HDFS 特有命令
命令 | 作用 | 示例 |
put | 本地 → HDFS(上传) | hdfs dfs -put local.txt /user/hadoop/ |
copyFromLocal | 本地 → HDFS(等价 put) | hdfs dfs -copyFromLocal local.txt /user/hadoop/ |
moveFromLocal | 本地 → HDFS 并删除本地文件 | hdfs dfs -moveFromLocal local.txt /user/hadoop/ |
get | HDFS → 本地(下载) | hdfs dfs -get /user/hadoop/remote.txt ./local.txt |
copyToLocal | HDFS → 本地(等价 get) | hdfs dfs -copyToLocal /user/hadoop/remote.txt ./ |
moveToLocal | HDFS → 本地并删除 HDFS 文件 | hdfs dfs -moveToLocal /user/hadoop/remote.txt ./ |
getmerge | 合并下载多个小文件到本地 | hdfs dfs -getmerge /user/hadoop/output/ merged.txt |
appendToFile | 追加本地文件到 HDFS | hdfs dfs -appendToFile more.log /user/hadoop/app.log |
count | 统计目录、文件数、总字节数 | hdfs dfs -count /user/hadoop/datahdfs dfs -count -q /user/hadoop/data |
setrep | 设置副本因子数量 | hdfs dfs -setrep -w 3 /user/hadoop/data/file1 |
expunge | 清空 HDFS 回收站 | hdfs dfs -expunge |
如果没有配置Hadoop的系统环境变量,则需要进入hadoop安装目录的bin文件夹下执行以下命令,如果配置了Hadoop环境变量,则可以在系统任意目录下执行
五、HDFS文件写入过程⭐⭐⭐

(1)Client 发起文件上传请求,通过 RPC 与 NameNode 建立通讯, NameNode 检查目标文件是否已存在,父目录是否存在,返回是否可以上传;
(2)Client 请求第一个 block 该传输到哪些 DataNode 服务器上;
(3)NameNode 根据配置文件中指定的备份数量及机架感知原理进行文件分配, 返回可用的 DataNode 的地址如:A, B, C;
(4)Client 请求 3 台 DataNode 中的一台 A 上传数据(本质上是一个 RPC 调用,建立 pipeline ),A 收到请求会继续调用 B,然后 B 调用 C,将整个 pipeline 建立完成, 后逐级返回 client;
(5)Client 开始往 A 上传第一个 block(先从磁盘读取数据放到一个本地内存缓存),以 packet 为单位(默认64K),A 收到一个 packet 就会传给 B,B 传给 C。A 每传一个 packet 会放入一个应答队列等待应答;
(6)数据被分割成一个个packet数据包在pipeline上依次传输,然后在pipeline反方向上逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipeline ack发送给Client;
(7)当一个 block 传输完成之后,Client 再次请求 NameNode 上传第二个 block,重复步骤 2;
六、HDFS网络拓扑与机架感知
1.网络拓扑
在本地网络中,何谓两个节点"彼此近邻"?在海量数据处理环境下,节点之间数据传输速率(带宽)成为主要限制因素,而带宽资源十分稀缺。因此,这里的核心思想是以两个节点间的带宽作为衡量它们距离的标准。
节点距离:两个节点到达最近的共同祖先的距离总和。
例如,假设有数据中心d1机架r1中的节点n1。该节点可以表示为/d1/r1/n1。利用这种标记,这里给出四种距离描述。
Distance(/d1/r1/n1, /d1/r1/n1)=0(同一节点上的进程)
Distance(/d1/r1/n1, /d1/r1/n3)=2(同一机架上的不同节点)
Distance(/d1/r1/n1, /d1/r3/n3)=4(同一数据中心不同机架上的节点)
Distance(/d1/r1/n1, /d2/r4/n3)=6(不同数据中心的节点)

2.低版本Hadoop副本节点选择
第一个副本在client所处的节点上。如果客户端在集群外,随机选一个。
第二个副本和第一个副本位于不相同机架的随机节点上。
第三个副本和第二个副本位于相同机架,节点随机。

3.高版本Hadoop副本节点选择
第一个副本在client所处的节点上。如果客户端在集群外,随机选一个。
第二个副本和第一个副本位于相同机架,随机节点。
第三个副本位于不同机架,随机节点。

七、HDFS文件读取过程⭐⭐⭐

(1)Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
(2)NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode 都会返回含有该 block 副本的 DataNode 地址; 这些返回的 DN 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离 Client 近的排靠前;心跳机制中超时汇报的 DN 状态为 STALE,这样的排靠后;
(3)Client 选取排序靠前的 DataNode 来读取 block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);
(4)底层上本质是建立 Socket Stream(FSDataInputStream),重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕;
(5)当读完列表的 block 后,若文件读取还没有结束,客户端会继续向NameNode 获取下一批的 block 列表;
(6)读取完一个 block 都会进行 checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的DataNode 继续读。
(7)read 方法是并行的读取 block 信息,不是一块一块的读取;NameNode 只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
(8)最终读取来所有的 block 会合并成一个完整的最终文件。
通过分析 HDFS 文件读写过程可以发现明显区别:HDFS 文件写入采用串行方式,数据包按 A→B→C 的顺序在节点间传递;而文件读取则采用并行方式,客户端 Client 可以直接并行读取存储各个 block 的节点。
八、NameNode 工作机制以及元数据管理⭐⭐

1.NN工作机制
- 第一次启动namenode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
- 客户端对元数据进行增删改的请求。
- namenode记录操作日志,更新滚动日志。
- namenode在内存中对数据进行增删改查。
2.2NN工作机制
- secondary namenode询问 namenode 是否需要 checkpoint。直接带回 namenode 是否检查结果。
- secondary namenode 请求执行 checkpoint。
- namenode 滚动正在写的edits日志。
- 将滚动前的编辑日志和镜像文件拷贝到 secondary namenode。
- secondary namenode 加载编辑日志和镜像文件到内存,并合并。
- 生成新的镜像文件 fsimage.chkpoint。
- 拷贝 fsimage.chkpoint 到 namenode。
- namenode将 fsimage.chkpoint 重新命名成fsimage。
3.FSImage与edits详解
所有的元数据信息都保存在了FsImage与Eidts文件当中,这两个文件就记录了所有的数据的元数据信息,元数据信息的保存目录配置在了 hdfs-site.xml 中。
在 HDFS 中,客户端写入文件时,相关的元数据操作会首先记录到 edits 文件中。
当 edits 被修改时,NameNode 的元数据也会相应更新。只有在这些更新完成后,客户端才能看到最新的信息。
fsimage 是 NameNode 中保存的元数据镜像文件,一般称为检查点(checkpoint)。它包含了 NameNode 管理下所有 DataNode 上的文件信息、文件对应的 block 信息,以及这些 block 所在的 DataNode 信息。
在系统运行初期,NameNode 对元数据的操作并不会直接写入 fsimage,而是先写入 edits。这是因为 fsimage 是一个完整的元数据快照,内容庞大,每次更新都需要将其全部加载到内存并构建树状拓扑结构,这一过程会消耗大量 CPU 与内存。如果每一次小的元数据变更都直接更新 fsimage,将严重影响 NameNode 的性能。
因此,HDFS 采用了 增量记录 + 定期合并 的机制:
- 日常操作记录在 edits 中(轻量、快速追加);
- 当 edits 文件增大到一定规模时,会与 fsimage 进行合并,生成新的 fsimage,从而减少 edits 的大小并提升恢复效率。
这种设计在保证性能的同时,也确保了元数据的一致性与可恢复性。
4.hdfs oiv命令
5.hdfs oev命令
6.2NN辅助管理FSImage与Edits
- secnonaryNN通知NameNode切换editlog。
- secondaryNN从NameNode中获得FSImage和editlog(通过http方式)。
- secondaryNN将FSImage载入内存,然后开始合并editlog,合并之后成为新的fsimage。
- secondaryNN将新的fsimage发回给NameNode。
- NameNode用新的fsimage替换旧的fsimage

完成合并的是 secondarynamenode,会请求namenode停止使用edits,暂时将新写操作放入一个新的文件中(edits.new)。
secondarynamenode从namenode中通过http get获得edits,因为要和fsimage合并,所以也是通过http get 的方式把fsimage加载到内存,然后逐一执行具体对文件系统的操作,与fsimage合并,生成新的fsimage,然后把fsimage发送给namenode,通过http post的方式。
namenode从secondarynamenode获得了fsimage后会把原有的fsimage替换为新的fsimage,把edits.new变成edits。同时会更新fsimage。
hadoop进入安全模式时需要管理员使用dfsadmin的save namespace来创建新的检查点。
secondarynamenode在合并edits和fsimage时需要消耗的内存和namenode差不多,所以一般把namenode和secondarynamenode放在不同的机器上。
fsimage与edits的合并时机取决于两个参数,第一个参数是默认1小时fsimage与edits合并一次。
7.namenode元数据多目录配置
为了保证元数据的安全性,我们一般都是先确定好我们的磁盘挂载目录,将元数据的磁盘做RAID1
namenode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性。
相关配置文件:hdfs-site.xml
8.namenode故障恢复
在SecondaryNameNode对NameNode中的fsimage和edits进行合并时,它会先将NameNode的fsimage与edits文件拷贝一份过来。因此,SecondaryNameNode中也会保存这些文件的副本。如果NameNode的fsimage与edits文件损坏,我们可以将SecondaryNameNode中的这些文件拷贝给NameNode继续使用,虽然这可能会导致部分数据丢失。这一过程涉及几个配置选项
9.模拟namenode的故障恢复功能
- 杀死namenode进程: 使用jps查看namenode的进程号 , kill -9 直接杀死。
- 删除namenode的fsimage文件和edits文件。根据上述配置, 找到namenode放置fsimage和edits路径. 直接全部rm -rf 删除。
- 拷贝secondaryNamenode的fsimage与edits文件到namenode的fsimage与edits文件夹下面去。根据上述配置, 找到secondaryNamenode的fsimage和edits路径, 将内容 使用cp -r 全部复制到namenode对应的目录下即可。
- 重新启动namenode, 观察数据是否存在。
九、DataNode工作机制以及数据存储
1.datanode工作机制
- 一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
- DataNode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有的块信息。(dfs.blockreport.intervalMsec)。
- 心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器。
2.DN的数据完整性
- 当DataNode读取block的时候,它会计算checksum。
- 如果计算后的checksum,与block创建时值不一样,说明block已经损坏。
- client读取其他DataNode上的block。
- datanode在其文件创建后周期验证checksum。
3.掉线时限参数设置
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的单位为秒。
与NameNode不同,DataNode的目录结构在初始阶段会自动创建,无需额外格式化。可以在/opt/hadoop-2.6.0-cdh5.14.0/hadoopDatas/datanodeDatas/current目录下查看版本号。
4.datanode多目录配置
datanode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本。如果多个目录配置需求只需要在value中使用逗号分隔出多个存储目录即可。
5.block块手动拼接成为完整数据
所有的数据都是以一个个的block块存储的,只要我们能够将文件的所有block块全部找出来,拼接到一起,又会成为一个完整的文件,可以通过命令将文件进行拼接:
- 上传一个大于128M的文件到hdfs上面去
我们选择一个大于128M的文件上传到hdfs上面去,只有一个大于128M的文件才会有多个block块。
这里我们选择将我们的jdk安装包上传到hdfs上面去。
node01执行以下命令上传jdk安装包
- web浏览器界面查看jdk的两个block块id
这里可以看到两个block块id分别为
1073742699和1073742700
那么我们就可以通过blockid将我们两个block块进行手动拼接了。
- 根据我们的配置文件找到block块所在的路径
4执行block块的拼接
十、HDFS其他重要功能
1.多个集群之间的数据拷贝
在我们实际工作当中,极有可能会遇到将测试集群的数据拷贝到生产环境集群,或者将生产环境集群的数据拷贝到测试集群,那么就需要我们在多个集群之间进行数据的远程拷贝,hadoop自带也有命令distcp可以帮我们实现这个功能
2.hadoop归档archive
每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如,一个1MB的文件以大小为128MB的块存储,使用的是1MB的磁盘空间,而不是128MB。
Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明的访问。具体说来,Hadoop存档文件可以用作MapReduce的输入。
创建归档文件
- 创建归档文件注意:归档文件一定要保证yarn集群启动
- 查看归档文件内容
- 解压归档文件
3.HDFS快照管理
快照是对HDFS文件系统的一种备份机制。我们可以为指定文件夹创建快照,但值得注意的是,创建快照后系统不会立即复制所有文件,而是仅创建指向原始文件的引用。只有当文件发生写入操作时,系统才会生成新的文件副本。
4.HDFS回收站
文件系统通常都有回收站机制,即删除的文件不会立即彻底清除。我们一般将删除的文件放入回收站,系统会在一段时间后自动清空回收站中的文件。这种机制对文件的安全删除提供了保障,避免因误操作而导致文件或数据的意外丢失。
- 回收站配置参数
默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间。
默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间。
要求fs.trash.checkpoint.interval<=fs.trash.interval。
- 启用回收站
修改所有服务器的core-site.xml配置文件
- 查看回收站
回收站内容在集群的 /user/root/.Trash/ 路径下
- ⚠️注意,通过javaAPI删除的数据,不会进入回收站,需要调用moveToTrash()才会进入回收站
- 恢复回收站及清空回收站数据
- 作者:tacjin
- 链接:http://jin.wiki/article/23be55fd-4dcc-80a8-bcd9-e93938c70dd2
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。