☰
HDFS操作实验:从命令到原理,副本与写流程全解析
2026/9/26 6:13:57 网站建设 项目流程

简介:实验二“熟悉常用的HDFS操作”配套实验报告,面向正在学习大数据原理与Hadoop生态的初学者,聚焦HDFS在Hadoop体系中的核心角色,以及Shell命令与Java API两种主流操作方式。资源包仅含1个docx文档,大小3.4MB,内容为一篇完整的课程实验报告,包含实验环境说明、Shell命令操作步骤、Java代码实现及运行效果记录,结构清晰可直接对照学习。该资源已有10209人浏览学习,属于高热度的大数据入门资料。报告基于Ubuntu 16.04/Hadoop 2.7.1环境,实际演示在Windows虚拟机运行ubuntukylin-16.04/Hadoop 3.1.3,详细覆盖了hdfs dfs -put上传、-test -e检查存在性、-appendToFile追加、-copyFromLocal -f覆盖等常用命令;Java部分则给出FileSystem、Path、FSDataOutputStream等类的具体用法,实现了文件存在性判断、本地复制到HDFS及内容追加等功能。无论是完成课程实验还是理解HDFS编程模型,这份报告都能提供完整参考,并能为后续MapReduce编程和HBase学习奠定扎实基础。

1. HDFS 操作实验:先会走再谈跑,命令背后的原理才是拿分点

但凡打开过实验指导书,面前多半是一排 hdfs dfs -mkdir、-put、-cat 的命令行。很多同学敲完一遍,报告里抄上截图,觉得“实验二”就过去了。可答辩或考核时老师一问“你这三个副本是放到哪三台机器上的”“写入过程里 DataNode 挂了怎么办”,现场就卡壳。这个实验真正要练的不是记住命令,而是通过命令把 NameNode、DataNode、副本放置、写流程这几件事像烙铁一样烙在脑子里。

这篇笔记覆盖从环境准备、常用命令、写读流程原理到 fsck 验证的完整复现路径,也把伪分布式和真实集群都会踩的坑列出来。适合正在做头歌平台“Hadoop 开发环境搭建及 HDFS 初体验”这类实训的学生,也适合入职前临时抱佛脚复习 HDFS 的初学者。全程按可以直接照做的顺序写,命令验证过,参数给到具体值。

2. 环境准备与集群启停:格式化、安全模式、单机伪分布式搭建

2.1 为什么实验环境推荐伪分布式而不是单机模式

单机模式(Local Mode)下 HDFS 的三个核心进程都在同一个 JVM 里,文件直接落本地磁盘,没有网络传输也没有副本机制,跑 put/get 和直接 cp 没有本质区别。实验要观察的副本放置、机架感知、块报告这些行为单机模式下全都看不见。伪分布式(Pseudo-Distributed Mode)用同一台机器的三个独立进程模拟集群,NameNode、DataNode、SecondaryNameNode 各占一个 JVM,端口也分开,是体验完整 HDFS 行为的最小成本方案。

HDFS 的默认副本数是 3,伪分布式只有一台机器,DataNode 只有一个,所以这个场景下副本数实际达不到 3。这不是实验环境坏了,是硬件的物理边界决定的。做副本相关实验时要么手动把副本系数改成 1,要么用三台虚拟机构建最小集群。很多同学就是栽在这——看到 fsck 报告里 REPLICATION FACTOR 低于 3 就以为集群有问题,到处重装。

2.2 格式化与安全模式的完整启动流程

首次启动集群前必须先格式化 NameNode。格式化的本质是生成空的镜像文件 fsimage 和集群唯一标识 clusterID。这里最容易出现的误区是以为格式化会“格式化 DataNode”,实际上hdfs namenode -format只处理 NameNode 的命名空间,不碰数据节点上的块数据。

# 切换到 Hadoop 安装目录 cd /usr/local/hadoop # 首次使用必须格式化,生成新的 clusterID bin/hdfs namenode -format # 启动 HDFS 守护进程(NameNode、DataNode、SecondaryNameNode) sbin/start-dfs.sh # 用 JVM 工具查看三个进程是否都活着 jps

格式化过程中要留意输出里是否出现“successfully formatted”字样,同时记下这一行打印的 clusterID。后面如果集群连不上,第一步就是比对 NameNode 和 DataNode 的 VERSION 文件里的 clusterID 是否一致。start-dfs.sh 执行完,jps 应该能看到至少三个进程:NameNode、DataNode、SecondaryNameNode。如果少了 SecondaryNameNode,HDFS 还能用,但检查点机制缺失,NameNode 重启恢复时间会明显变长,属于隐患不是事故。

启动后立即执行hdfs dfsadmin -safemode get,大概率会返回 ON。安全模式是 NameNode 启动后的强制状态,用来等待 DataNode 上报块报告。只有达到配置的块阈值(默认 99.9% 的块上报完成)才会自动退出。伪分布式单节点集群通常几十秒内退出,如果长时间卡在安全模式,多半是 DataNode 没起来或块报告被防火墙挡了,不是配置错误。

2.3 停机顺序与重要配置项

停机顺序和启动相反,先停 HDFS 再停辅助服务,避免 NameNode 还在处理写请求时 DataNode 全部消失。

# 停止 HDFS,与 start 对应 sbin/stop-dfs.sh # 确认所有 Java 进程已退出 jps

jps 输出为空才算真正停干净。很多实验报告翻车场景就是这样:上一次实验没停干净,这一次直接 start-dfs.sh,端口被占用,NameNode 进程起不来。报错信息里出现 “Address already in use”(端口被占用)时,第一件事不是改端口,而是jps看有没有残留进程,然后kill -9清掉。

需要关注的三个核心配置项如下,实验环境可以直接抄这组值:

配置项配置位置实验推荐值作用
fs.defaultFScore-site.xmlhdfs://localhost:9000默认文件系统地址,指向 N门
dfs.replicationhdfs-site.xml1(伪分布式)默认副本数,影响写流程和 fsck 报告
dfs.namenode.name.dirhdfs-site.xml/usr/local/hadoop/tmp/dfs/nameNameNode 元数据目录,格式化产物落在这
dfs.datanode.data.dirhdfs-site.xml/usr/local/hadoop/tmp/dfs/dataDataNode 块数据目录,存实际内容

配置 hdfs-site.xml 时最容易漏的是没有设置 name.dir 和 data.dir 而用系统默认路径,导致格式化后的数据不知道落在哪,后面想清理都找不到地方。实验环境我通常会把两个目录手动指定到 hadoop 安装目录下的 tmp 里,以后删数据、看报告都方便。改完配置必须重启集群才生效,很多人改了 core-site.xml 不重启,然后怀疑自己配错了。

3. 目录与文件操作:从建目录到管道副本的完整命令族

3.1 目录操作与路径语义

HDFS 的目录操作命令和 Linux 命令长得非常像,但有一个本质区别:HDFS 的路径以hdfs://namenode-host:9000/为根,命令行里可以省略这个前缀直接写/user/hadoop,命令会从 core-site.xml 里读默认文件系统。实验报告里大量截图只显示路径不显示前缀,就是这个原因。

# 递归创建目录,-p 参数避免父目录不存在时报错 hdfs dfs -mkdir -p /user/hadoop/input # 查看目录内容,显示文件大小、副本数、修改时间 hdfs dfs -ls /user/hadoop/ # 递归查看整棵目录树,包含所有子目录和文件 hdfs dfs -ls -R /user/hadoop/ # 查看目录占用空间,按人类可读方式显示 hdfs dfs -du -h /user/hadoop

-mkdir -p的-p和 Linux 下的mkdir -p含义一致,一次性写入多层目录,不用逐层创建。-ls输出里的第二列数字是副本数,膜分布式下显示 1,真实集群下显示 3,这一列就是写流程里副本放置的最直观证据。-du -h统计的是逻辑占用,即文件实际大小,不是物理占用——物理占用要乘以副本数,这是 HDFS 容量规划里的经典坑:一个 10 GB 的文件,三副本实际占 30 GB 物理空间。

3.2 文件上传下载与查看

文件操作是实验二里最核心的得分区。命令不难,难在每个命令的参数和输出怎样解读。上传命令-put等价于-copyFromLocal,下载命令-get等价于-copyToLocal,只是名字不同,行为完全一致。

# 创建一个本地测试文件 echo "hello hdfs experiment" > /tmp/test.txt # 上传到 HDFS,目标是目录时自动保留原文件名 hdfs dfs -put /tmp/test.txt /user/hadoop/input/ # 查看文件块信息,-blocks 显示块 ID 和位置 hdfs fsck /user/hadoop/input/test.txt -files -blocks -locations # 下载到本地指定目录,目录不存在时会自动创建 hdfs dfs -get /user/hadoop/input/test.txt /tmp/download/ # 查看文件内容不落本地磁盘 hdfs dfs -cat /user/hadoop/input/test.txt

-put的上传路径如果写的是目录,文件会保留原名放进目录;如果写的是完整文件路径,则相当于重命名上传。fsck 命令里的-files -blocks -locations三个参数一起用,能同时看到文件、块、块所在节点三层信息,实验报告里截这张图,原理部分基本就能站住脚了。-cat适合小文件,几百 MB 以上的文件直接用-cat会把终端刷爆,用hdfs dfs -text查看前几千字节或者直接-get下来分段看,不要等到终端卡死才后悔。

3.3 权限、副本调整与回收站

权限模型与 POSIX 权限基本一致:owner/group/other 三类身份,rwx 三种权限。但 HDFS 没有“执行位”的传统语义——执行位 x 对文件没有实际作用,目录的 x 位代表“可遍历”,只要有读位就能列出文件名,但要进入目录必须同时有 x 位。这个点常作为实验报告问答题的坑。

# 修改文件权限,755 = 属主 rwx,属组 rx,其他 rx hdfs dfs -chmod -R 755 /user/hadoop/input # 修改属主和属组,超级用户才能执行 hdfs dfs -chown -R hadoop:hadoop /user/hadoop/input # 把副本数改成 2,NameNode 会调度新副本创建 hdfs dfs -setrep -R 2 /user/hadoop/input # 查看回收站配置是否开启 hdfs getconf -confKey fs.trash.interval

-setrep修改副本数是异步操作,命令返回后数据迁移在后台进行。改完立刻看 fsck 可能还是旧副本数,等几十秒再查。回收站机制默认关闭,fs.trash.interval为 0 表示不启用,此时-rm删除的文件直接物理释放,没有后悔药可吃。实验时我一般先执行 getconf 确认回收站状态,再决定删文件时要不要提前备份。生产集群通常把回收站间隔设成 1440 分钟(一天),实验环境默认关闭反而干净。

4. 读写流程与副本机制:实验报告里最难拿分的原理部分

4.1 写入流程:从客户端到三副本的管道建立

HDFS 写流程是整个实验二里最值得展开讲的原理。客户端请求写一个文件时,流程可以拆成六个步骤,每一步都对应一个可以在日志里观察到的动作。写流程的本质是“客户端写入本地缓冲区 -> 请求 NameNode 建文件 -> 建立到 DataNode 的管道 -> 数据包按序写入并逐级确认”。

客户端先调用 DistributedFileSystem.create() 发起 RPC 请求到 NameNode,请求内容包含路径、副本数、块大小。NameNode 在命名空间里创建文件条目,检查目录存在、权限允许、副本系数合法,任何一个条件不满足都会直接拒绝。文件条目创建后,NameNode 返回一个 HdfsDataOutputStream 给客户端。此时文件还是“正在写入”状态,对别的客户端不可见,这层保护依赖租约机制(lease),防止两个客户端同时写同一路径。客户端开始写数据时,先在本地缓冲区攒数据。默认块大小 128 MB,数据按数据包(packet)为单位切分,每个 packet 默认 64 KB。攒够一个块的数据后,客户端向 NameNode 申请一批 DataNode 地址,这批地址就是块副本的放置列表,由机架感知策略决定。NameNode 按“本机优先、同机架其次、跨机架最后”的顺序挑选节点,返回给客户端。客户端拿到列表后建立到第一个 DataNode 的 TCP 连接,第一个 DataNode 再连第二个,第二个连第三个,形成一条以客户端为起点的数据管道。数据包沿管道逐级下传,每个 DataNode 写完本地磁盘后向上一个节点发送确认(ack),确认逐级回到客户端,客户端再发下一个 packet。这个逐级确认的机制叫流水线复制(pipeline replication)。

最后一个 packet 写完并收到所有确认后,客户端调用 close(),NameNode 落实文件条目,把文件状态从“正在写入”切换成“已关闭”。整个过程中有一个隐藏动作值得写进报告——每个 packet 都携带校验和数据,校验方式是 CRC32,校验粒度是 512 字节。DataNode 每收到一个 chunk 就计算校验和,存到磁盘的 meta 文件里,读的时候重新计算比对。这是 HDFS 不需要 RAID 也能保证数据完整性的底层逻辑。

4.2 写入失败时的降级流程

写流程中任何一个 DataNode 挂了,pipeline 会立刻断掉。客户端感知到管道断裂后,把已经发送但未确认的 packet 保存在缓冲区,同时向 NameNode 申请一份新的 DataNode 列表,列表会剔除故障节点,客户端重新建立管道,把缓冲中的数据重发一遍。整个降级过程中,已经写入的数据块不会丢失,NameNode 会记录下这个块缺少副本,并安排后台线程把缺失副本补到新节点上。

这里面有一个实际工作中高频出现的坑:写一个大文件时,如果网络稍有抖动,DataNode 频繁掉线,客户端会反复申请新列表和重建管道。每次重建都有超时开销,表现为-put命令长时间“卡住”然后抛 SocketTimeoutException。伪分布式单节点实验没有这个问题,真实的三节点集群很常见。遇到这种情况先检查机器负载,不要上来就怀疑 Hadoop 本身。

4.3 副本放置策略的三个候选节点与读取流程

HDFS 默认副本因子 3,放置策略可以用一句话概括:第一个副本放客户端所在节点(客户端不在集群时随机挑一个负载低的节点),第二个副本放同一机架的不同节点,第三个副本放另一个机架下的随机节点。两个副本为了容灾分散到两个机架,两个副本为了性能留在一个机架内,避免了跨机架流量打满。这个策略是hdfs-site.xml里的dfs.replication和机架感知脚本共同决定的,没有配置机架拓扑时所有节点被当成同一个机架,三副本会全部落在同一机架,容灾能力归零。

读取流程比写入简单得多,没有管道概念。客户端请求 NameNode 拿文件块和副本位置列表,NameNode 返回按网络距离排序的 DataNode 列表,客户端和排在最前面的节点建立连接读数据。读的过程中逐块进行 CRC32 校验,校验失败会尝试列表里的下一个副本。这解释了为什么 fsck 报告里文件显示“healthy”但仍然可能读到坏数据——实际上读不出来,因为校验失败会触发重试到好副本,用户无感。

4.4 块大小与副本系数不是越大越好

实验报告问答环节的高频问题:“块大小设置成 256 MB 有什么影响?”这需要分清两个层面。块越大,NameNode 存储的块元数据越少(同样大小文件,块数少),对大文件友好;但块越大,MapReduce 对单个块的并行度越低,一个块只能被一个 Map 任务处理。块越小,并行度高,但元数据膨胀,大量小文件会把 NameNode 的堆内存撑爆。默认 128 MB 是在元数据开销和计算并行度之间平衡的结果。副本系数同理:3 副本已经是绝大多数场景的默认选择,太大浪费空间,太小丢数据后没地方恢复。

5. 常见问题排查:五个让集群“假死”的真实坑

5.1 格式化后集群连不上:clusterID 不一致

现象:第二次格式化之后,DataNode 进程活着,但 jps 里 NamendNode 起不来,日志不断提示 DataNode 拒绝连接,或 Web UI 上 DataNode 列表为 0。

原因:每次hdfs namenode -format会重新生成一个新的 clusterID,写入到 NameNode 的 VERSION 文件里。而 DataNode 侧的 VERSION 文件还保留着第一次格式化时的 clusterID,两边对不上,DataNode 的上报被 NameNode 无视。

解决:停止整个集群,分别找到 dfs.name.dir 和 dfs.data.dir 目录,把两个目录下的 current 文件夹完整删除,再重新执行hdfs namenode -format并start-dfs.sh。如果是三节点真实集群,三台机器的 data 目录都要同步清理,否则两边 clusterID 还是对不上。真实生产环境里严禁随意重新格式化,格式化会清空整个文件系统元数据,数据全丢。

5.2 上传文件卡死然后报错:写管道超时

现象:hdfs dfs -put执行后长时间不见进度,终端像是挂住,最后抛出 SocketTimeoutException 或 AlreadyBeingCreatedException。

原因:客户端向 NameNode 发送 create 请求成功后,NameNode 会记录文件“正在创建”,如果后续写管道迟迟建立不起来或写一半断掉,客户端崩溃退出,租约没有正常释放,NameNode 里残留处于“正在写入”状态的文件条目。下次再用同一路径上传,NameNode 判定文件仍被旧租约占用,直接拒绝。

解决:先看文件系统里同名路径是否存在,用hdfs dfs -ls -R核实;然后用 fsck 查看这个路径的租约状态。确认是残留租约后,执行hdfs debug recoverLease -path /user/hadoop/input/test.txt -retries 3强制恢复租约,之后再重新 put。伪分布式单节点上常用更简单的办法——删除残留文件再重传,但删不掉时(NameNode 还在等租约释放)就要走 debug 命令。

5.3 集群卡在安全模式出不来:块上报没达标

现象:启动后不管等多久,hdfs dfsadmin -safemode get始终返回 ON,Web UI 提示 Safe mode is ON,任何写操作都被拒绝。

原因:安全模式退出条件是已上报的块数量占总块数量百分比达到dfs.namenode.safemode.threshold-pct,默认 99.9%。DataNode 进程没起来、防火墙挡了块报告端口、磁盘满了写不进临时文件,都会导致上报不齐。

解决:先jps确认 DataNode 是否存在,不存在则查 DataNode 日志($HADOOP_HOME/logs/hadoop--datanode-.log),常见是端口占用或 Java 堆内存不足。都正常仍卡住时,可以用hdfs dfsadmin -safemode leave手动强制退出,但这属于治标,下次重启大概率还会卡,必须回到日志查根因。

5.4 fsck 报告块健康但文件读不了:校验和损坏

现象:文件所有块状态 HEALTHY,但-cat或-get过程中报 ChecksumException,读出来的内容损坏。

原因:fsck 检查的是块的元数据和副本数,不校验文件内容。某个块的数据写入时和校验和不匹配,比如磁盘静默损坏或进程 kill 在写一半时,该块在 fsck 里仍显示健康,因为 fsck 不读块内容。

解决:对损坏文件执行hdfs dfs -get时读到哪个块报错,在报错信息里定位块 ID,确认是哪个 DataNode 的哪个块;如果还有其他副本,把坏副本文件删掉,让 NameNode 重新复制一份正常副本;如果只有一份副本且已损坏,这个文件无法恢复,只能从源头重新上传。这体现了三副本在生产环境的意义,也是实验报告里可以写的延伸思考。

5.5 节点配置齐全却显示副本不足:机架感知未配置

现象:真实三节点集群启动后,上传的文件在 fsck 里显示 UNDER REPLICATED,副本数一直补不到 3。

原因:没有配置机架感知时,所有节点被看作同一个机架,NameNode 挑选副本时全部落在一个机架内。三副本都放在同一机架确实能写满三个副本,但如果其中一个节点挂了,NameNode 找不到“足够远”的节点来补副本,就一直停在 UNDER REPLICATED 状态。

解决:在topology.script.file.name配置项里指定一个机架映射脚本,脚本对每个节点 IP 或主机名返回机架标识,让 NameNode 感知到跨机架的节点。脚本本身用 shell 写,几十行就能跑,实验环境把三个节点分别映射到 /rack1、/rack2、/rack3,重启集群后重新上传测试文件,fsck 会显示副本数恢复为 3。

6. 用 fsck 和文件指纹给实验结果做验收

6.1 fsck 报告的三个必看指标

实验做完不是命令跑完就结束,必须用一个可量化的方式验证结果。hdfs fsck /user/hadoop -files -blocks -locations是 HDFS 自带的体检工具,输出末尾是一行汇总信息,重点关注三个数值。

Health Status 显示 HEALTHY 表示所有块副本数满足要求,没有缺失;Under-replicated blocks 是 0 说明副本全数补齐;Missing blocks 是 0 说明没有块损坏或丢失。实验环境如果 Health Status 是 CORRUPT(损坏)或 UNDER REPLICATED(副本不足),八成是副本数配置或节点故障问题,按第 5 章的方法排查。三个指标全部达标后,再把输出里任意一个文件的 block 列表截图或保存下来,作为实验报告里“写流程验证”的佐证——它同时展示了文件被切成哪几个块、每一块的副本落在哪台机器,对应 4.1 节的放置策略。

6.2 用块文件和 md5 做双层验证

fsck 只验证块的元数据状态,不验证数据内容完整。要确实验证上传的数据和本地原数据一致,需要在 HDFS 层面和本地层面各做一遍指纹比对。

# HDFS 侧计算块文件的 CRC 校验信息 hdfs fsck /user/hadoop/input/test.txt -files -blocks -locations | grep test.txt # 本地源文件指纹 md5sum /tmp/test.txt # 从 HDFS 下载后再次计算指纹,两次比对 hdfs dfs -get /user/hadoop/input/test.txt /tmp/check.txt md5sum /tmp/check.txt

两个 md5 值完全一致,说明数据经历了上传、管道复制、落盘、读取全链路没有发生损坏。这一步看起来多余,但对于做实验的人来说,它能排除“数字看起来对,实际数据已坏”的假阳性。我在做三节点集群验证时还会多做一步:删除其中一个 DataNode 上的某个块副本,等几十秒后重跑 fsck,观察 NameNode 如何自动补副本,这个验证能让三副本机制的印象深刻得多。

6.3 快照与配额:两个容易写进报告的高级操作

如果实验课时充足,建议把快照(Snapshot)和目录配额(Quota)也做一遍,这两个操作在真实工作里使用频率很高,但教科书很少展开。快照是对目录做只读备份,不占额外空间,只有文件变更后才产生差异数据。目录配额用来限制目录存储的文件数量,防止某个业务线无节制写入把集群磁盘撑爆。两个操作结合,就构成了 HDFS 最轻量的“备份 + 限流”组合。

# 允许对 /user/hadoop/data 目录创建快照 hdfs dfsadmin -allowSnapshot /user/hadoop/data # 创建名为 snap1 的快照 hdfs dfs -createSnapshot /user/hadoop/data snap1 # 对目录设置文件数上限为 100 hdfs dfsadmin -setQuota 100 /user/hadoop/data

快照创建后,任何误删操作都能通过hdfs dfs -ls /user/hadoop/data/.snapshot/snap1/找回原文件。从那以后我每次带新人做实验,都会强制他们先建快照再做大量删除操作,这已经是防止误删的习惯性动作。配额超出时写入会被拒绝,报错提示配额超限,而不是任何权限错误。做完这两个操作,实验报告里可以写的内容就不只是基础命令了,还能延伸到 HDFS 在生产环境的日常管理手段。希望这份实践笔记对你有帮助,不管是在头歌平台上做实训,还是在自己搭的伪分布式集群上折腾,一定要亲手跑一遍 fsck 和 md5sum,这比多敲十遍 put/get 都更有价值。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询