简介:面向大数据初学者与高校实验课程使用者,这份实验指导文档系统梳理了“熟悉常用的Linux操作和Hadoop操作”的完整流程。内容先交代实验目的与平台选型,再分模块讲解虚拟机安装、常用命令操作、伪分布式部署和基础文件管理。命令部分涉及目录切换、文件查看、权限修改、压缩打包、字符串查找等常见场景,并配有清晰的执行示例与结果说明;Hadoop部分重点演示了单机伪分布式环境的搭建方法,以及运行自带实例验证是否成功。文档按实验步骤逐条展开,每个操作都给出输入命令与预期输出,便于自主练习和排查问题;末尾还补充了环境变量配置与HDFS常用操作,能有效降低入门门槛。资源包仅含一个Word文档,压缩后大小约289KB,内容结构紧凑,可直接打印作为实验手册。目前已有九百七十七人学习下载,适合作为大数据课程第一次实验的课前预习、课上对照和课后复习材料,也可供教师布置与检查作业时参考。
1. Hadoop 大数据实验的开端:先把 Linux 虚拟机这关过了
第一次做大数据的同学,多半是卡在“装环境”这一步:Windows 上装 Hadoop,要么 shell 脚本跑不起来,要么路径分隔符和权限问题满天飞,最后发现 Hadoop 在 Linux 上运行才能发挥最佳性能。于是实验一的核心就落到了三件事上:装一个 Linux 虚拟机、熟悉常用 Linux 命令、在单机上把 Hadoop 伪分布式环境搭起来跑通。这篇文章按我实际搭环境的顺序写,从 VirtualBox 6.1.4 装 Ubuntu 18.04,到 Hadoop 3.1.3 的四份配置文件,再到最经典的 DataNode 起不来问题,每一步都给出可复现的命令和参数说明,照着走能省掉大半天的折腾时间。
2. 版本选型:VirtualBox 6.1.4、Ubuntu 18.04、Hadoop 3.1.3 怎么组合最稳
2.1 为什么推荐 Ubuntu 18.04 而不是更新版本
Hadoop 伪分布式环境对操作系统没有硬性限制,但在实验场景里,Ubuntu 18.04 搭配 Hadoop 3.1.3 是踩坑最少的组合。18.04 的 glibc 版本和 JDK 8 配合得很好,apt 源里直接能装 openjdk-8-jdk,不用折腾 PPA。相对地,20.04 和 22.04 默认的 OpenSSH 配置和 Python 版本会让 start-dfs.sh 的免密登录环节多出一些意外,比如 ssh-keygen 生成的密钥格式不被旧版本接受,或者 sshd 默认禁止了空密码密钥登录。
Ubuntu 16.04 也能做实验,但系统已经进入 EOL 状态,apt 源默认指向的 archive 地址失效,安装前需要手动把源改成 old-releases,对新手来说又多了一道工序。因此建议直接下载 18.04 的桌面版镜像,安装时选择“清除整个磁盘并安装 Ubuntu”,虚拟机里不需要双系统,后面所有操作都在虚拟机内完成。
若你已经装好了 VMware 加 CentOS 7 的环境,也可以继续用,只是配置文件路径和 JDK 安装方式和本文有差异。Hadoop 3.1.3 在 CentOS 7 上同样能跑,第 5 章的 DataNode 排查部分我会把这个差异单独讲。
2.2 VirtualBox 安装与虚拟机创建参数
VirtualBox 6.1.4 的 Windows 安装包从官方仓库下载,约 100MB,安装过程一路默认即可,不需要额外勾选扩展包。创建虚拟机时有几个参数会影响后面的实验,列一张表说明:
| 参数项 | 推荐值 | 说明 |
|---|---|---|
| 内存 | 4096 MB | Hadoop 伪分布式启动多个 Java 进程,2048 MB 会比较紧张 |
| 磁盘 | 20 GB 动态分配 | Hadoop 安装包加日志数据约 5 GB,20 GB 留出编译和快照空间 |
| 显存 | 16 MB | Ubuntu 桌面版显示足够 |
| 网络 | NAT + Host-Only | NAT 用于虚拟机上网,Host-Only 用于宿主机 SSH 连接 |
| CPU 核数 | 2 | 启动编译或跑 MapReduce 时更快 |
磁盘格式选 VDI,动态分配,实际占用会随着数据增长变大,不用一开始就分满。网络部分如果只做实验,NAT 模式默认就能访问外网,虚拟机内部使用 22 端口 SSH 不受影响;但如果计划从 Windows 宿主机直接访问 Hadoop 的 9870 管理页面,就需要配置端口转发规则,这一条在第 5 章踩坑部分会展开。
2.3 装完 Ubuntu 后先补三件套:SSH、JDK、apt 源
Ubuntu 18.04 安装完成后,我习惯先把系统源和基础软件搞定。VM 里打开终端,执行以下命令:
sudo apt update && sudo apt upgrade -y sudo apt install -y openssh-server openjdk-8-jdk net-tools这一步同时完成三件事:更新软件源、安装 SSH 服务端、安装 OpenJDK 8。Hadoop 伪分布式启动脚本会通过 SSH 连接 localhost 拉起进程,SSH 是必须的。OpenJDK 8 是 Hadoop 3.1.3 最兼容的 Java 版本,JDK 11 也能运行,但某些老教程里的配置会不匹配。
装完 JDK 后确认一下路径,后面配置 JAVA_HOME 要用:
readlink -f $(which java)常见输出为 /usr/lib/jvm/java-8-openjdk-amd64/bin/java,去掉末尾的 bin/java 就是 JDK 的主目录。这个路径在配置 ~/.bashrc 和 hadoop-env.sh 时都会用到,记不住也没关系,用命令查出来的最准。
3. Linux 命令实操:18 个高频命令和它们的易错参数
3.1 目录切换与查看:cd、ls、mkdir、rmdir
实验从 cd /usr/local 开始。切换目录这个操作看着基础,但要注意 cd 和 pwd 的区别,cd 是改变当前目录,pwd 才是查看当前位置。cd .. 回到上一级,cd ~ 回到当前用户的主文件夹,也就是 /home/用户名 这个位置。这三个操作在后续所有实验里都会反复用到,尤其是 cd ~,因为 .bashrc 文件就在主文件夹下。
ls /usr 查看 /usr 目录下的所有文件和目录,不带 -a 参数时不会显示隐藏文件。ls -l 可以看权限和所有者,后面 chown 命令的验证环节会用到。
mkdir 命令有一个很关键的参数 -p,创建多级目录时不加它就会报错:
cd /tmp mkdir a mkdir -p a1/a2/a3/a4第一条 mkdir a 在 /tmp 下创建单层目录,没有问题。第二条 mkdir a1/a2/a3/a4 要求父目录 a1、a2、a3 都不存在,没有 -p 时系统直接提示 No such file or directory。加了 -p 后,命令会递归创建整条路径。这个参数在写部署脚本时几乎是标配,比如创建日志目录 mkdir -p /var/log/app/today。
rmdir 删除空目录的限制是很多人的第一个绊脚石。rmdir /tmp/a 可以删除空目录 a;但要删除 a1/a2/a3/a4 这条链,直接执行 rmdir a1/a2/a3/a4 只会把最内层的 a4 删掉,因为删除 a4 后 a3 变成空目录但 a1、a2 仍非空。我一般会直接 rmdir -p a1/a2/a3/a4,它会递归删除路径上所有变为空的父目录,一步到位。
3.2 文件复制、移动与删除:cp、mv、rm 的细节差别
cp 命令最容易翻车的是漏掉 -r 参数。复制单文件到新位置并改名:
cp ~/.bashrc /usr/bashrc1这条命令成功的前提是目标位置 /usr 存在且当前用户有写权限,实际操作中可能遇到 Permission denied,因为 /usr 属于 root,普通用户没有写入权限,需要 sudo 执行。实验环境里如果用 hadoop 用户操作,建议先 sudo chown -R hadoop:hadoop /usr 或改用 sudo cp。
复制目录时必须加 -r:
mkdir /tmp/test cp -r /tmp/test /usr/testcp -r 表示递归复制整个目录树,不加 -r 时系统会提示 omitting directory,这是 Linux 命令里出现频率最高的报错信息之一。
mv 命令同时承担移动和更名两个职责:
mv /usr/bashrc1 /usr/test/bashrc1 mv /usr/test /usr/test2mv 把 bashrc1 从 /usr 移动到 /usr/test 目录下,文件内容不变;把 /usr/test 重命名为 /usr/test2,原地改名。理解 mv 的规则就是目标路径是目录就移动进去,目标路径不存在或目标路径带新名字就是更名。
rm 命令的坑主要在目录删除上:
rm /usr/test2/bashrc1 rm -r /usr/test2rm 删文件不需要参数,rm 删目录必须加 -r。很多新手在这一步只输入 rm /usr/test2,系统报错 Is a directory 后不知所措,解决办法就是加 -r。至于 rm -rf 这个组合,实验里可以用,但要养成好习惯:敲之前确认路径变量非空,否则一条 rm -rf /usr/local/${DIR}/ 在变量为空时会变成删根目录,这是运维工程师的血泪教训。
3.3 文件内容查看:cat、tac、more、head、tail 全家桶
cat ~/.bashrc tac ~/.bashrc more ~/.bashrc head -n 20 ~/.bashrc tail -n 20 ~/.bashrc head -n -50 ~/.bashrc tail -n +50 ~/.bashrccat 正序输出全文,tac 倒序输出全文,两个命令的拼写恰好相反。more 适合长文件分页查看,按空格翻页、按 q 退出,它在 bash 脚本里的用处更大。head -n 20 取前 20 行,tail -n 20 取最后 20 行,这两个参数最直观。
head -n -50 表示从文件开头显示到倒数第 50 行之前,也就是不显示最后 50 行;tail -n +50 表示从第 50 行开始显示到文件末尾。这两个带正负号的参数容易记反,我的记忆方式是:head 管开头,负数代表去掉尾部;tail 管末尾,正数代表从第几行开始。实验里要求“后面 50 行不显示”用 head -n -50,“只列出 50 行以后的数据”用 tail -n +50,两个场景刚好互补。
3.4 属性修改、文件查找与压缩:touch、chown、find、tar、grep
touch /tmp/hello touch -d "5 days ago" /tmp/hello chown root:root /tmp/hello find ~ -name .bashrc tar -czvf test.tar.gz /test tar -xzvf test.tar.gz -C /tmp grep examples ~/.bashrctouch 第一次执行创建空文件 hello,第二次执行修改文件时间戳。-d "5 days ago" 把修改时间调整为 5 天前。chown root:root 把文件所有者和所属组都改成 root,改完用 ls -l 验证,能看到文件所有者列变成 root。find ~ -name .bashrc 在主目录下按名称精确查找文件,注意 find 的查找路径要写成绝对路径或相对路径,这里 ~ 会被展开成 /home/用户名。
tar 命令的参数组合需要逐个拆开理解:-c 创建归档,-z 用 gzip 压缩,-v 显示处理过程,-f 指定归档文件名,顺序固定写作 -czvf。解压时用 -xzvf,其中 -x 表示解包。最后 -C /tmp 指定解压目标目录,这个参数在安装软件时很常用,把压缩包解压到指定位置。
grep examples ~/.bashrc 从 ~/.bashrc 里查找包含字符串 examples 的行,输出的每一行都会高亮匹配部分。这个命令在后面看日志、搜配置时是最常用的排查工具,第 5 章排查 DataNode 问题时也要靠它定位配置路径。
3.5 环境变量配置:vim 编辑 ~/.bashrc 设置 JAVA_HOME
vim ~/.bashrc在文件末尾追加两行:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$PATH:$JAVA_HOME/bin保存退出后执行 source ~/.bashrc 使配置立即生效,最后用 echo $JAVA_HOME 验证:
source ~/.bashrc echo $JAVA_HOME这一步实验要求里明确写了“查看 JAVA_HOME 变量的值”,很多同学配置完忘了 source,导致 echo 出来是空值,以为配置失败。实际上 vim 编辑后,当前 shell 会话不会自动加载新的环境变量,必须 source 或重新登录。PATH 那行使用 $PATH 追加而非覆盖,这是环境变量配置的黄金规则:永远不要写成 export PATH=$JAVA_HOME/bin,否则系统原来的命令路径全丢了,连 ls 都会找不到。
4. Hadoop 3.1.3 伪分布式安装:解压、改配置、格式化一次走完
4.1 解压安装与目录规划
从 Hadoop 官网下载 hadoop-3.1.3.tar.gz 后,我一般习惯把它解压到 /usr/local 并改名为 hadoop:
cd /usr/local sudo tar -xzf hadoop-3.1.3.tar.gz sudo mv hadoop-3.1.3 hadoop sudo chown -R hadoop:hadoop /usr/local/hadoop这里把目录所有者改成当前实验用户,避免后续每次操作都要 sudo,因为 Hadoop 集群启动后会往 logs 和 tmp 目录写数据,如果目录属于 root,普通用户的启动脚本会报权限错误。chown -R 递归修改整个目录树的所有者,包括 hadoop-env.sh 等配置文件。
解压后的目录结构里最需要关注的是 etc/hadoop(配置文件)、sbin(启动脚本)、bin(客户端命令)和 share(MapReduce 示例 jar 包)。WordCount 示例位于 share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar,第 6 章验证时会用到。
4.2 core-site.xml:指定 NameNode 地址与临时数据目录
vim /usr/local/hadoop/etc/hadoop/core-site.xml在 configuration 节点内写入:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/usr/local/hadoop/tmp</value> </property> </configuration>fs.defaultFS 定义 HDFS 的访问入口,伪分布式模式下使用 hdfs://localhost:9000,端口 9000 是 NameNode 内部通信端口。hadoop.tmp.dir 是集群所有临时数据的根目录,NameNode 的元数据目录和 DataNode 的数据块目录都会自动创建在这个路径下,默认是 /tmp/hadoop-hadoop,但 /tmp 目录在系统重启时可能被清理,所以我总是不厌其烦地建议改成安装目录下的固定位置。这个参数直接影响第 5 章 DataNode 起不来的故障排查,必须记住你配置的路径。
4.3 hdfs-site.xml:副本数、NameNode 与 DataNode 存储目录
vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:/usr/local/hadoop/tmp/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/usr/local/hadoop/tmp/dfs/data</value> </property> </configuration>dfs.replication 设置副本数为 1,是因为伪分布式只有一台物理机,数据本来只存一份,副本数大于 1 也无意义。dfs.namenode.name.dir 和 dfs.datanode.data.dir 显式指定元数据与数据块的存放位置,虽然不写也会继承 hadoop.tmp.dir,但写出来有两个好处:一是排查问题时能直接找到关键目录,二是避免某些老版本脚本解析路径时出错。
注意属性值里的 file: 前缀,HDFS 的 URI 格式要求存储路径以 file: 开头,少了这个前缀会解析成 HDFS 自身路径,导致启动时目录创建失败。这是一个很容易忽略的格式细节,我在好几个环境里都见过因此启动失败的案例。
4.4 hadoop-env.sh 与格式化启动
vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh找到 JAVA_HOME 那一行,取消注释并改成实际 JDK 路径:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64hadoop-env.sh 里的 JAVA_HOME 是 Hadoop 各启动脚本直接读取的变量。如果你只在 ~/.bashrc 里配了 JAVA_HOME,start-dfs.sh 依然会报错 JAVA_HOME is not set,因为脚本在通过 SSH 执行远程命令时不会加载交互式 shell 的环境变量。这个坑的经典程度大概仅次于 DataNode 起不来。
启动前先配置 SSH 免密:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ssh localhostssh-keygen 的 -P '' 表示生成空密码密钥,-f 指定输出文件路径。公钥追加到 authorized_keys 后,chmod 600 设置文件权限,SSH 对密钥文件的权限要求很严格,权限过宽会直接拒绝加载。最后 ssh localhost 能直接进入 shell 就代表免密生效。
格式化与启动:
hdfs namenode -format start-dfs.sh jpshdfs namenode -format 指令执行时,系统会在 NameNode 元数据目录里生成 VERSION 文件,里面包含 clusterId。这个 clusterId 是整个集群的身份标识。start-dfs.sh 启动所有 HDFS 进程,jps 查看进程列表。正常状态应该看到 NameNode、DataNode、SecondaryNameNode 三个进程。只有看到这三个进程,HDFS 才算真正起来了。
5. 避坑排查:DataNode 起不来与 Cluster-Id 不一致的完整记录
5.1 现象:jps 少了 DataNode,9870 页面 LiveNode 为 0
我用某模拟项目 X 的实验环境部署 Hadoop 3.1.3 时,第一次启动集群一切正常,但执行了几次格式化操作后重启集群,发现 jps 输出里只剩 NameNode 和 SecondaryNameNode,DataNode 进程完全消失。浏览器访问 :9870 端口能看到 NameNode 的 Web 管理页面,但 Live Nodes 数量是 0。当时第一反应是 start-dfs.sh 有问题,反复 stop-all.sh 再 start-all.sh,DataNode 还是起不来,这个问题卡了将近一个小时。
5.2 原因:多次 namenode -format 导致 clusterId 不一致
排查方向转向日志。Hadoop 的日志都写在 $HADOOP_HOME/logs 目录下,DataNode 的日志文件名是 hadoop-hadoop-datanode-主机名.log,用 tail 看末尾几十行:
tail -50 /usr/local/hadoop/logs/hadoop-hadoop-datanode-*.log日志里有一句关键信息:namenode clusterID 与 datanode clusterID 不匹配,DataNode 拒绝注册。原因链条很清楚:第一次执行 hdfs namenode -format 时,NameNode 生成一个 clusterId,写入 dfs/name 目录的 VERSION 文件;DataNode 启动时在 dfs/data 目录也会生成一份带 clusterId 的 VERSION。如果之后再次执行 namenode -format,NameNode 会生成一个全新的 clusterId,但 DataNode 数据目录里还是旧 clusterId。两边对不上,DataNode 就只能不断重试、最终放弃启动。
这个问题的诱因很常见:实验中途遇到进程异常,想当然地重新格式化,以为 format 是万能后悔药,结果反而制造了新故障。格式化操作在集群已经初始化过后不应该重复执行,除非确认要清空所有数据。
5.3 解决:删除指定数据目录并重新格式化
解决办法是清除所有旧的元数据和数据目录,让两个节点的 clusterId 重新一致:
stop-all.sh rm -rf /usr/local/hadoop/tmp/dfs hdfs namenode -format start-all.sh jps执行前先确认数据目录到底在哪,因为正常配置过的 core-site.xml 通常会指定 hadoop.tmp.dir,数据路径往往是 $HADOOP_HOME/tmp 或你自定义的目录。用 grep 在配置里查一下最稳:
grep -A 1 "hadoop.tmp.dir" /usr/local/hadoop/etc/hadoop/core-site.xml我当时的 core-site.xml 里配的是 /usr/local/hadoop/tmp,所以执行 rm -rf /usr/local/hadoop/tmp/dfs 删除整个 dfs 子目录,包括 name 和 data。重新 format 后,NameNode 生成新的 clusterId,DataNode 启动时发现本地 data 目录不存在,会创建新目录并接受 NameNode 的 clusterId,两边一致,进程就恢复正常了。
如果你用 VMware 里的 CentOS 7 做实验,且配置的路径是 /opt/module/hadoop-3.1.3/data,那就要删 /opt/module/hadoop-3.1.3/data 整个目录,原理完全一样。当时实验报告里记录的问题解决方法就是删除 core-site.xml 中指定的缓存数据路径,然后重新格式化,用 stop-all.sh 和 start-all.sh 重启集群解决。
5.4 另外三个高频坑:卡密码、端口不通、JAVA_HOME 没写进文件
现象一:start-dfs.sh 执行到 localhost 时卡住,提示输入密码。原因:SSH 免密没有配置成功,多半是 authorized_keys 文件权限不对,或者公钥没有正确追加。解决方式:确认 ~/.ssh 目录权限是 700,authorized_keys 权限是 600,然后手动执行 ssh localhost 看是否能直接登录,如果还需要密码就重新执行 ssh-keygen 和追加公钥的流程。
现象二:宿主机浏览器访问虚拟机 9870 页面打不开。原因:VirtualBox NAT 模式下,宿主机无法直接访问虚拟机内的端口,KVM 或 VMware 的 NAT 也一样需要转发规则。解决方式:在 VirtualBox 设置中配置端口转发规则,把宿主机的 9870 端口映射到虚拟机 IP 的 9870 端口;或者在虚拟机内用 curl http://localhost:9870 先验证服务本身正常,排除服务端问题后再处理网络映射。
现象三:执行 start-dfs.sh 报错 JAVA_HOME is not set and could not be found。原因:只在 ~/.bashrc 配了环境变量,hadoop-env.sh 文件里的 JAVA_HOME 还是空值。解决方式:编辑 etc/hadoop/hadoop-env.sh,把 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 写到文件里,注意不要加空格和引号,重启集群后生效。
6. 验证跑通:WordCount 实例与 HDFS 文件操作检查
6.1 用自带 WordCount 验证 MapReduce 链路
集群启动后,最可靠的验证方式不是只看 jps,而是真正跑一个 MapReduce 作业。Hadoop 3.1.3 自带 wordcount 示例,位于 share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar。先创建 HDFS 测试目录并上传文件:
hdfs dfs -mkdir -p /user/hadoop/test hdfs dfs -put ~/.bashrc /user/hadoop/test/ hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /user/hadoop/test /user/hadoop/output hdfs dfs -cat /user/hadoop/output/part-r-00000hdfs dfs -mkdir -p 在 HDFS 上递归创建目录,-put 将本地文件上传到 HDFS。hadoop jar 命令提交 WordCount 作业,参数依次是 jar 包路径、示例类名、输入目录和输出目录。作业执行完毕后,输出目录下会生成 part-r-00000 文件,用 hdfs dfs -cat 查看内容,能看到 .bashrc 里每个单词及其出现次数,说明整个 HDFS 加 MapReduce 的链路是通的。
6.2 HDFS 文件操作验证清单
实验要求里有一组 HDFS 操作,按顺序跑一遍即可确认环境没有问题:
hdfs dfs -ls /user/hadoop/test hdfs dfs -cp /user/hadoop/test/.bashrc /user/hadoop/test/bashrc_copy hdfs dfs -get /user/hadoop/test/bashrc_copy /usr/local/hadoop/- -ls 查看目录列表,对比本地文件系统,HDFS 的路径以 /user/hadoop 开头。
- -cp 在 HDFS 内部复制文件,验证副本写入能力。
- -get 将 HDFS 文件下载到本地 /usr/local/hadoop 目录,对应实验要求里“将 HDFS 文件夹 test 复制到 Linux 系统本地”的步骤。
最后再用 jps 和 9870 页面确认一遍进程状态,WordCount 的输出文件和下载到本地的 bashrc_copy 都验证了 HDFS 的读写能力。从那以后我每次搭建 Hadoop 环境都会强制走完这一整套流程:jps 查进程、9870 看 LiveNode、WordCount 跑一个真实作业,再执行一轮 HDFS 文件上传下载。这套验证流程把环境问题挡在实验开始之前,希望帮到你。
本文还有配套的精品资源,点击获取