资讯详情

Ubuntu虚拟机搭建Hadoop分布式集群:避坑全攻略

📅 2026/10/12 23:45:17 | 华诺云谱 👁 阅读
Ubuntu虚拟机搭建Hadoop分布式集群:避坑全攻略
简介面向大数据初学者与开发者的Hadoop分布式环境搭建指南聚焦Ubuntu操作系统下的实战流程。教程从虚拟机创建与系统安装讲起依次覆盖SSH免密登录、共享文件夹挂载、JDK环境配置、Hadoop核心参数调整以及系统环境变量设置每一步都配有步骤说明与界面截图适合零基础用户按图索骥也能帮助有经验者快速定位环境问题。资源包共93个文件总体积222.16MB主要文件类型包括Word实验文档、Java/Class程序文件、XML配置文件、PNG操作截图、JAR依赖包及说明文本目录结构清晰可按章节或模块单独查阅。压缩包内另附一套云计算课程设计项目及多个经典Hadoop实验源码与数据例如倒排索引、矩阵乘法、最短路径和二次排序可直接导入开发环境运行验证有助于理解分布式计算原理。目前已有112人学习使用既能支撑课程实验与期末设计也可作为搭建生产集群前的操作参考。1. 在 Ubuntu 虚拟机上搭 Hadoop 分布式环境先把这条链路上的坑都标出来很多人第一次搭 Hadoop习惯直奔安装包结果卡在虚拟机网络、SSH 密钥、JDK 版本这些看似外围的环节上。真正让“基于 Ubuntu 系统的 Hadoop 分布式环境搭建”耗掉一整天的不是 Hadoop 本身而是虚拟机网络模式选错、SSH 免密登录不通、共享文件夹挂载不上、环境变量设置不生效这四件事。这篇笔记按我实际搭建的顺序写从虚拟机安装 Ubuntu 开始到 SSH 免密登录、共享文件夹挂载、JDK 环境配置再到 Hadoop 安装与配置和环境变量设置最后落到大数据处理平台的启动验证。适合两类人想低成本在笔记本上复现分布式集群的初学者以及要在多台虚拟机上快速搭可复现实验环境的一线工程师。每个参数我都会给出具体值踩过的坑也会单独列一章。2. 虚拟机安装 Ubuntu 与共享文件夹挂载先打通宿主机到集群的数据通道2.1 为什么选 VMware Ubuntu 搭 Hadoop网络与资源的取舍要先想清楚搭建 Hadoop 分布式环境最常见的载体就是 VMware 虚拟机里的 Ubuntu。原因很直接Hadoop 的官方支持列表、社区教程、排错经验大部分都围绕 Linux 展开Ubuntu 又恰好是包管理最省心的发行版。用虚拟机而不是物理机是因为分布式集群最少要两个节点普通笔记本没那么多闲置机器VMware 克隆虚拟机、改主机名、配置静态 IP 都很快。另一个好处是快照在格式化 NameNode 之前打一个快照配置写崩了直接回滚不用重装系统。选 VMware 还是 VirtualBox我的判断标准是“共享文件夹和拖拽复制哪边更省事”。VMware Workstation 的共享文件夹走 vmhgfs-fuse配合 open-vm-tools宿主机和虚拟机之间的数据交换非常直接VirtualBox 的增强功能也能用但在 Ubuntu 内核升级后偶尔要重编模块。所以下面都以 VMware Workstation Ubuntu Desktop 为例服务器版没有图形界面共享文件夹和桌面工具链反而绕路。资源分配上我一般给每台虚拟机 4GB 内存、2 核 CPU、40GB 磁盘。这个配置跑 Hadoop 3.x 加 YARN 的 MapReduce 任务不会太局促。内存别小于 2GB否则 JVM 一启动机器就开始疯狂换页DataNode 放到一半就断连。磁盘大小也别抠HDFS 的副本机制会把数据复制三份磁盘不够时看起来是“服务都在Datanode 日志里全是写入失败”。2.2 VMware 安装 Ubuntu 的系统参数与网络模式NAT 还是桥接直接决定免密登录顺不顺虚拟机创建阶段有三个关键参数网络模式、虚拟机内存、磁盘类型。网络模式里我强烈建议用 NAT。桥接模式会让虚拟机直接暴露在局域网里IP 是路由器分配的如果你办公室的 Wi-Fi 做了 AP 隔离多台虚拟机之间互相 ping 不通SSH 免密登录自然就失败。NAT 模式下 VMware 会在宿主机上模拟一个虚拟交换机多台虚拟机之间不管宿主机有没有网都能互通这对本机搭 Hadoop 集群是最稳的选择。创建虚拟机时按下面这张表填参数即可不需要额外装 VMware ToolsUbuntu 桌面版装完后执行 apt install open-vm-tools open-vm-tools-desktop 就能实现窗口自适应和共享文件夹功能。配置项推荐值说明网络模式NAT保证虚拟机间互通不受外部网络影响内存4096 MBHadoop 各进程 JVM 默认堆内存加起来接近 3GB处理器2 核不需要更多学习环境 CPU 不是瓶颈磁盘40 GB单文件快照和克隆更稳定Ubuntu 版本22.04 LTS 或 20.04 LTS内核新一点open-vm-tools 兼容性更好安装 Ubuntu 的流程里唯一要注意的是磁盘分区选“Erase disk and install Ubuntu”即可让安装器自动用 LVM。Hadoop 的数据目录放在哪个分区下面不重要重要的是不要把 /tmp 单独分太小的区因为我的教程里会把 Hadoop 存储目录放到 /usr/local/hadoop而 /usr/local 在默认分区大小下装完 JDK 和 Hadoop 可能只剩几个 GB保险起见把逻辑卷容量稍微加大。装完第一台虚拟机后先别急着装 Hadoop立刻做两件事设置静态 IP 和修改主机名。Ubuntu 18.04 之后网络配置走 netplan我一般直接改 /etc/netplan/01-network-manager-all.yaml把 DHCP 改成手动。各台虚拟机的 IP 我习惯按节点角色分配master 用 192.168.30.100slave1 用 192.168.30.101slave2 用 192.168.30.102。修改好之后执行 sudo netplan apply再用 ping 192.168.30.100 验证。主机名改到 /etc/hostname 和 /etc/hosts后面 SSH 和 Hadoop 配置都会直接依赖主机名这一步不做后面全是坑。2.3 共享文件夹挂载vmhgfs-fuse 挂载宿主机目录到 /mnt/hgfs共享文件夹是这套环境里最实用的功能。我会在宿主机上建一个 ~/data 目录把要导入 HDFS 的数据放进去虚拟机里直接读取不用每次都通过 scp 拷贝。VMware 里先在“虚拟机设置 – 选项 – 共享文件夹”里启用共享添加宿主机目录然后安装 open-vm-tools用下面这组命令测试挂载# 查看 VMware 共享文件夹列表确认宿主机目录已经传给虚拟机 vmware-hgfsclient # 创建挂载点 sudo mkdir -p /mnt/hgfs # 挂载共享目录.host:/ 表示宿主机所有共享根目录 sudo vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other -o uid1000,gid1000 # 检查是否挂载成功 ls /mnt/hgfsvmware-hgfsclient 这条命令是给 open-vm-tools 用的如果输出为空说明共享文件夹没有开启或者虚拟机还没加载到配置。挂载命令里 .host:/ 是固定写法表示取宿主机共享根目录也可以写成 .host:/data 直接挂载某个具体目录。allow_other 参数非常关键不加它只有 root 用户能访问挂载点Hadoop 的普通用户读写共享目录时会出现 Permission denied。uid 和 gid 我直接写成当前用户的 id避免用 root 挂载后普通用户往共享文件夹写入时报权限错误。ls /mnt/hgfs能列出宿主机目录说明挂载成功。但这个挂载是临时的虚拟机重启后还会丢。要让共享文件夹开机自动挂载我一般把挂载命令写进 /etc/fstab。fstab 里这一行容易写错我先把完整格式放出来# 在 /etc/fstab 末尾追加这一行 .host:/ /mnt/hgfs fuse.vmhgfs-fuse allow_other,uid1000,gid1000,defaults 0 0fstab 挂载 vmhgfs 有一个需要注意的点系统启动时网络和 vmhgfs 模块的加载顺序不一定稳定偶尔会挂载失败。更稳妥的做法是写一个 systemd 服务在 multi-user.target 启动后执行挂载命令。我把这个方案放在后面的避坑章节里讲。共享文件夹本身只是数据通道不要在挂载目录里直接跑 Hadoop 的临时文件HDFS 目录和日志一定要独占磁盘否则 vmhgfs 的 FUSE 延迟会让 NameNode 的读写超时。3. SSH 免密登录与 JDK 环境配置把节点间的信任关系和 Java 底座一次搞定3.1 分布式集群为什么必须依赖 SSH 免密HDFS 的远程执行机制Hadoop 集群启动时NameNode 需要远程启动所有 DataNode 进程ResourceManager 需要远程启动 NodeManager。这里的“远程启动”本质上靠 SSH 执行命令。如果每次连接都要求输入密码start-dfs.sh 会在每个节点前停下来等密码分布式集群完全无法实现一键启动。这就是必须配 SSH 免密登录的原因。SSH 免密登录的核心是密钥对每台机器生成一对公钥和私钥把公钥分发到需要被登录的机器的 ~/.ssh/authorized_keys 文件里。登录时客户端用自己的私钥签名服务端用存放的公钥验签验签通过就放行。整个过程不传输密码也就避免了密码泄露的风险。集群规模不大时我会采用最朴素的做法master 生成一对密钥把公钥分发给所有节点包括 master 自己。这样从 master 上 ssh slave1、ssh slave2 都不需要密码。3.2 生成密钥对并批量分发从 Master 到 Slave 一条命令打通我习惯在 master 节点上统一生成密钥对不搞“每台机器各自生成再互发”的复杂流程。因为学习环境的信任模型很简单master 是控制端点从 master 能免密登录所有节点就够了。执行下面的命令# 在 master 节点执行-t 指定算法-N 表示空 passphrase-f 指定输出路径 ssh-keygen -t rsa -b 4096 -N -f ~/.ssh/id_rsa # 把公钥追加到 master 自己的 authorized_keys并设置正确权限 cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys # 将公钥分发到 slave1 和 slave2命令执行过程中输入一次密码即可 ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop192.168.30.101 ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop192.168.30.102生成密钥时我把 passphrase 设为空这是不得已的取舍。带 passphrase 的私钥安全性更好但每次 SSH 连接都要输入私钥口令start-dfs.sh 依然会被卡住。测试环境用空 passphrase 是主流做法生产环境则应改用 SSH agent 或者更严格的安全机制。rsa 和 ed25519 都可以我选 rsa 一是兼容性好二是个别 Hadoop 相关脚本在特殊环境下对 ed25519 的识别会有问题。chmod 700 和 chmod 600 这两条权限设置不能跳过sshd 对 authorized_keys 权限有严格校验权限过宽会直接忽略这个文件。批量分发完成后用 ssh slave1 hostname 验证一下。第一次连接会出现 yes/no 指纹确认输入 yes 回车之后就不会再问。如果这一步报 Permission denied最常见原因是分发公钥时写到了别的用户目录下比如当前用户是 hadoopssh-copy-id 却连到了 root 用户导致公钥落在 /root/.ssh/authorized_keys。后面避坑章节会专门讲权限问题。3.3 JDK 安装OpenJDK 8 还是 11版本坑比你想的多Hadoop 是 Java 写的JDK 版本直接决定能不能启动。Hadoop 3.x 官方支持 Java 8 和 Java 11社区里跑得最稳的组合是 OpenJDK 8。我遇到过有人装 JDK 17 然后 HDFS 启动直接抛 UnsupportedClassVersionError 的情况这不是 Hadoop 不支持新特性而是编译字节码版本超过了 JVM 能加载的版本。用 Ubuntu 的 apt 装 OpenJDK 11 是一个不折腾的选择# 更新软件源索引并安装 OpenJDK 11 sudo apt update sudo apt install -y openjdk-11-jdk # 查看安装路径后续 JAVA_HOME 要用 which java sudo update-alternatives --config javaupdate-alternatives --config java 会列出所有已安装的 JDK 以及各自的路径。Ubuntu 上 OpenJDK 默认装在 /usr/lib/jvm/java-11-openjdk-amd64这个路径待会要直接写进 hadoop-env.sh。安装完成后运行 java -version 确认版本如果系统里同时装了 JRE 和多个 JDK一定要检查默认 java 指向的是哪个Hadoop 脚本认的是 JAVA_HOME 而不是 PATH 里的 java。为什么不用 Oracle JDK因为 Hadoop 学习环境用不上 Oracle JDK 的商用特性OpenJDK 和它在 Hadoop 场景下几乎没有性能区别。装 Oracle JDK 反而要手工解压、配置软链接多一堆麻烦。如果你所在的公司强制要求 Oracle JDK至少选择 8u201 以上版本避免 2019 年之前版本里的 Java 序列化漏洞影响 Hadoop IPC 通信。3.4 环境变量设置与 PATH 生效JAVA_HOME 别只写在终端里JDK 装好后要把 JAVA_HOME、PATH、HADOOP_HOME 写进 ~/.bashrc。有一个常见误区只在当前终端 export JAVA_HOME然后换一个终端就失效了。正确做法是写进用户的环境变量文件让每个新开的 shell 都自动加载。我通常用下面这段# 编辑 ~/.bashrc在文件末尾追加 cat ~/.bashrc EOF export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 export PATH$JAVA_HOME/bin:$PATH export HADOOP_HOME/usr/local/hadoop export PATH$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop EOF # 使配置立即生效 source ~/.bashrc # 验证三个关键变量 echo $JAVA_HOME echo $HADOOP_HOME java -versionHADOOP_HOME 指向 Hadoop 解压目录我统一放在 /usr/local/hadoop避免不同用户目录下的路径把环境变量搞乱。PATH 里同时加 bin 和 sbinbin 提供 hdfs、yarn 命令sbin 提供 start-dfs.sh、stop-dfs.sh 等启动脚本。HADOOP_CONF_DIR 设成 etc/hadoop后面写配置文件时Hadoop 会优先读取这个环境变量指向的目录。这里有个坑source ~/.bashrc 只在当前 shell 生效。之后如果通过 SSH 免密远程执行启动命令SSH 连接是非交互式 shell默认不会加载 .bashrc。到时候从 master SSH 到 slave 去执行 hadoop-daemon.sh可能提示 command not found。所以环境变量不仅要写进 ~/.bashrc我还会确认 /etc/profile.d/ 下有一个全局的 hadoop.sh或者直接把这些 export 写进 /etc/profile保证 SSH 非交互登录也能加载。具体操作我会在 Hadoop 配置章节一并给出。4. Hadoop 安装与配置改好 5 个文件启动真正的分布式集群4.1 安装包解压与安装目录规划用户、目录权限、版本一致性一次说清Hadoop 的安装目录规划看起来简单但目录权限问题经常会引发 DataNode 启动失败。我建议把所有 Hadoop 相关文件都放在 hadoop 用户下避免用 root 启动 HDFS。HDFS 进程如果以 root 身份运行DataNode 写入数据块目录时会把目录所有者变成 root下次用普通用户启动就直接抛权限异常。新建一个专门的用户然后解压安装包# 创建 hadoop 用户并设置密码后面所有节点都用这个用户 sudo useradd -m hadoop -s /bin/bash sudo passwd hadoop # 解压 Hadoop 二进制包到 /usr/local并统一目录名 sudo tar -zxf /mnt/hgfs/software/hadoop-*.tar.gz -C /usr/local sudo mv /usr/local/hadoop-* /usr/local/hadoop # 把 /usr/local/hadoop 的所有者改为 hadoop 用户 sudo chown -R hadoop:hadoop /usr/local/hadoop # 创建 HDFS 数据目录和临时目录 sudo mkdir -p /data/hdfs/namenode /data/hdfs/datanode /data/hdfs/tmp sudo chown -R hadoop:hadoop /data/hdfs这里把 hadoop 的 tgz 包放在共享文件夹 /mnt/hgfs/software 下正好用上了第二章挂载的共享目录。所有节点必须使用同一个 Hadoop 版本版本不一致会让 DataNode 与 NameNode 之间的 RPC 协议不兼容表现为 DataNode 注册失败。存储路径我不放在默认的 /tmp/hadoop-* 下因为 /tmp 目录在系统重启后可能被清理NameNode 的持久化文件一旦丢失整个集群就失去元数据。目录规划里namenode 和 datanode 分目录存放tmp 目录是 Hadoop 的默认临时目录。等会配置 core-site.xml 里的 hadoop.tmp.dir 时我直接指向 /data/hdfs/tmpNameNode 的格式化文件也会写到这个目录下面。4.2 core-site.xml 与 hdfs-site.xmlNameNode 地址、数据目录与副本数进入 /usr/local/hadoop/etc/hadoop先改 core-site.xml。这个文件决定文件系统入口也就是客户端连接 HDFS 时该找谁。分布式模式下NameNode 的地址必须用 master 节点的主机名加 8020 端口。配置如下!-- core-site.xml核心文件系统参数 -- configuration !-- NameNode 的 RPC 通信地址hadoop-master 是主机名 -- property namefs.defaultFS/name valuehdfs://hadoop-master:8020/value /property !-- Hadoop 运行时临时目录必须提前创建好 -- property namehadoop.tmp.dir/name value/data/hdfs/tmp/value /property !-- 控制 HDFS 文件系统的缓冲区大小默认 4KB 太小 -- property nameio.file.buffer.size/name value131072/value /property /configurationfs.defaultFS 这个值决定了你在任意一台节点上执行 hdfs dfs -ls / 访问的是哪套文件系统。所有节点都要配置成 hdfs://hadoop-master:8020不能写成 localhost否则 DataNode 向 localhost 注册会连到本机集群就变成单点。hadoop.tmp.dir 直接影响 NameNode 的 fsimage 和 DataNode 的 data 目录位置我用固定路径避免系统 /tmp 清理。接着改 hdfs-site.xml这里面重点是副本数和 NameNode/DataNode 数据目录!-- hdfs-site.xmlHDFS 存储与副本策略 -- configuration !-- 副本数设置为 2三节点集群能容忍一台机器故障 -- property namedfs.replication/name value2/value /property !-- NameNode 元数据存储目录 -- property namedfs.namenode.name.dir/name value/data/hdfs/namenode/value /property !-- DataNode 数据块存储目录多个目录用逗号分隔 -- property namedfs.datanode.data.dir/name value/data/hdfs/datanode/value /property !-- 关闭 HDFS 权限检查学习环境省去大量排错 -- property namedfs.permissions.enabled/name valuefalse/value /property /configurationdfs.replication 默认是 3集群一共三个节点理论上可以设为 3。但我建议设成 2因为副本数设 3 时一个节点宕机后 HDFS 会把这个节点上的副本判定为丢失并立即开始复制补副本在只有 3 个节点的小集群里容易触发集群进入安全模式的连锁反应。设成 2 反而更稳既能覆盖单点故障又不会让补副本机制在资源不足时反复挣扎。dfs.permissions.enabled 在生产环境不要关但在学习环境关掉能少踩很多 ACL 的坑后面避坑章节会提到。4.3 yarn-site.xml 与 mapred-site.xml资源调度和计算框架的绑定YARN 负责资源调度mapred-site.xml 负责 MapReduce 运行时框架。先看 yarn-site.xml关键是把 ResourceManager 所在节点指到 master并告诉 NodeManager 如何聚合日志!-- yarn-site.xmlYARN 资源调度核心参数 -- configuration !-- ResourceManager 所在节点主机名 -- property nameyarn.resourcemanager.hostname/name valuehadoop-master/value /property !-- NodeManager 依赖的辅助服务 -- property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property !-- shuffle 服务的类名MapReduce 任务数据传输的关键 -- property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property !-- 每个容器允许的最大内存默认值在小内存虚拟机上容易 OOM -- property nameyarn.nodemanager.resource.memory-mb/name value3072/value /property /configurationyarn.resourcemanager.hostname 如果漏配ResourceManager 会绑定到每个节点自己的主机名从 slave 上提交作业时会发现连不上 ResourceManager。aux-services 这段是 MapReduce 跑在 YARN 上的关键漏掉后作业提交会在 Running 状态卡住日志报 ShuffleHandler 找不到。内存参数我给 3072MB这是根据每台虚拟机 4GB 内存估出来的留 1GB 给操作系统和 HDFS。如果机器只有 2GB 内存这里要降到 2048并同步调整下面的 mapred-site.xml。mapred-site.xml 在 Hadoop 2.x 之后默认没有这个文件只有一个 mapred-site.xml.template需要先复制一份# 复制模板为正式配置文件 cp /usr/local/hadoop/etc/hadoop/mapred-site.xml.template \ /usr/local/hadoop/etc/hadoop/mapred-site.xml!-- mapred-site.xml指定 MapReduce 运行在 YARN 之上 -- configuration !-- 运行框架必须是 yarn否则 MR 任务会跑在独立模式 -- property namemapreduce.framework.name/name valueyarn/value /property !-- Map Task 最大堆内存必须小于 YARN 容器内存 -- property namemapreduce.map.memory.mb/name value1024/value /property !-- Reduce Task 最大堆内存 -- property namemapreduce.reduce.memory.mb/name value1024/value /property /configurationmapreduce.framework.name 不设成 yarn作业提交后会尝试在本地跑 MapReduce你会发现明明启动了三个节点作业却只在提交的那台机器上执行。map 和 reduce 的内存分别设成 1024MB两个任务并发时占用 2GB加上 HDFS 和系统本身4GB 虚拟机能跑但不能同时开太多作业。如果是学习环境经常报“Container is running beyond physical memory limits”优先检查这里而不是 YARN 的总内存。4.4 hadoop-env.sh 与环境变量JAVA_HOME 必须写成绝对路径/etc/hadoop/hadoop-env.sh 里有一个被无数人忽略的配置。文件开头的注释里写了 JAVA_HOME 的示例默认是 export JAVA_HOME${JAVA_HOME}这会把系统里 PATH 能找到的 java 当作 JAVA_HOME。问题是 SSH 非交互登录拿不到 ~/.bashrc 里的 export就会变成空的然后 Hadoop 启动时找不到 java。我把 JAVA_HOME 直接写成绝对路径# 编辑 $HADOOP_HOME/etc/hadoop/hadoop-env.sh找到 JAVA_HOME 行改为 export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64同时把上一章说的全局环境变量写进 /etc/profile.d/hadoop.sh这样即使 SSH 远程执行启动脚本也能找到 hadoop 和 yarn 命令# 创建 /etc/profile.d/hadoop.sh所有用户登录时都会加载 sudo tee /etc/profile.d/hadoop.sh /dev/null EOF export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 export HADOOP_HOME/usr/local/hadoop export PATH$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop EOF # 切到 hadoop 用户后重新登录或执行 source source /etc/profile.d/hadoop.shhadoop-env.sh 里还可以顺手把 HDFS 的 JVM 参数加一点。默认情况下 HDFS 各进程的堆内存根据机器内存自动计算但虚拟机的可用内存会被 YARN 吃掉NameNode 经常拿不到足够堆内存。生产环境会单独配 HADOOP_NAMENODE_OPTS 和 HADOOP_DATANODE_OPTS学习环境保持默认即可遇到频繁 GC 导致 NameNode 进入安全模式再加。4.5 格式化与首次启动先启动 DFS再启动 YARN所有配置完成后第一件不能省的事是格式化 NameNode。格式化会生成集群 ID 和文件系统元数据。但在多节点集群里我必须提醒你格式化只需要在 master 上执行一次不要对已经跑过的集群反复格式化否则 DataNode 的 clusterID 会和 NameNode 不一致这是后面避坑章节第一个要讲的大坑。# 在 master 节点格式化 NameNode hdfs namenode -format # 启动 HDFS start-dfs.sh # 启动 YARN start-yarn.sh # 在 master 上查看进程 jpsstart-dfs.sh 会读取 /etc/hadoop/workers 文件这个文件写每台从节点的主机名。Hadoop 3.x 里它叫 workersHadoop 2.x 叫 slaves。文件里要写全集群所有节点包括 master 自己。写完后每行一个主机名不要带多余空格和注释# 编辑 $HADOOP_HOME/etc/hadoop/workers hadoop-master hadoop-slave1 hadoop-slave2jps 命令输出里master 上应该有 NameNode、SecondaryNameNode、ResourceManagerslave 上应该有 DataNode 和 NodeManager。看到这些进程后再执行 hdfs dfsadmin -report 检查 DataNode 是否都注册成功。如果 jps 里少了进程第一件事是去看 $HADOOP_HOME/logs/ 下对应进程的日志比如 hadoop-hadoop-datanode-hadoop-slave1.log。这个日志文件是排错的第一现场比网上搜报错更直接。5. 避坑Ubuntu 下 Hadoop 环境搭建频率最高的 6 个故障点5.1 SSH 免密失败Permission denied (publickey,password)现象在 master 上执行 ssh hadoop-slave1输入密码后能连上但 ssh-copy-id 之后再用密钥连接仍然提示 Permission denied (publickey)。检查 ~/.ssh/authorized_keys 文件公钥确实在里面。原因~/.ssh 目录或 authorized_keys 文件的权限过宽。sshd 要求用户主目录是 755、.ssh 是 700、authorized_keys 是 600任何一项多了组用户和其他用户的可写权限OpenSSH 出于安全考虑就会拒绝使用这个密钥文件。解决在每台被登录的节点上执行 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys。如果是 root 用户被拒绝还要检查 /etc/ssh/sshd_config 里是否设置了 PermitRootLogin no。另外别忽略主机名解析因素/etc/hosts 里必须把 hadoop-slave1 映射到正确 IP否则 SSH 可能连到了同名但不同 IP 的机器。5.2 NameNode 格式化失败目录已存在且非空现象第二次执行 hdfs namenode -format 时报错日志显示 NameNode is already formatted或者是 namenode 目录下存在 current/VERSION 文件无法覆盖。原因第一次格式化已经把集群 ID 写入 /data/hdfs/namenode/current。Hadoop 3.x 会拒绝在非空目录里重复格式化防止误操作把现有集群元数据清掉。很多人想通过重复格式化解决 DataNode 注册问题结果越格式化越乱。解决在确定要重建集群时手动删除所有 HDFS 数据目录再重新格式化顺序是stop-all.sh 停掉所有进程删除 /data/hdfs/namenode 和 /data/hdfs/datanode 下的全部内容然后在 master 上执行 hdfs namenode -format。不要用 -force 参数跳过检查因为你真正要解决的不是 NameNode 目录而是 NameNode 与 DataNode 之间 clusterID 不一致的问题。5.3 DataNode 进程消失Incompatible clusterID 与注册失败现象集群启动后 master 上的 jps 有 NameNodeslave 上的 jps 没有 DataNode查看日志报 java.io.IOException: Incompatible clusterIDs或者 DataNode 反复连接 NameNode 失败。原因DataNode 的 data 目录里保存了它第一次连接 NameNode 时拿到的 clusterID。如果 NameNode 被重新格式化过clusterID 变了旧 DataNode 就不认账。常见场景是第一次格式化后启动过集群后来因为某个配置错误重新格式化却没有清掉 DataNode 的数据目录。解决停止所有服务后登录每个 slave 节点删除 /data/hdfs/datanode 下的所有文件和目录保留空目录即可然后重新启动 HDFS。DataNode 启动时会从 NameNode 获取新的 clusterID 并写入自己的数据目录。如果是学习环境直接删除所有节点的 /data/hdfs 下内容是唯一最省事的办法。5.4 JDK 版本不兼容UnsupportedClassVersionError 和 GC 配置报错现象Hadoop 启动脚本执行到一半报 UnsupportedClassVersionError或者 NameNode 进程启动后数十秒内就退出日志里出现 Java HotSpot 无法识别的 VM 参数。原因Hadoop 3.3 用 Java 11 编译如果系统默认 Java 是 8版本低的一方无法读取高版本字节码反过来 Hadoop 3.1 用 Java 8 编译在 Java 17 上运行时又会出现某些反射或模块访问被拒的错误。日志里的 VM 参数报错则是 Hadoop 脚本检查到 Java 版本后设置了不兼容的 GC 参数。解决统一集群所有节点的 JDK 版本我自己的选择是 OpenJDK 11。在每一台节点上执行 java -version 确认默认版本再确认 hadoop-env.sh 里 JAVA_HOME 是绝对路径。如果系统里同时有多个 JDK用 update-alternatives --config java 把默认版本切到 11。这个故障最隐蔽的地方在于有时 master 是 JDK 11slave 是 JDK 8start-dfs.sh 在 master 上能启动但 slave 的 DataNode 就是起不来一定要逐台检查。5.5 共享文件夹挂载后目录为空或写入失败现象/mnt/hgfs 存在但 ls 看不到任何共享目录或者能看到目录但创建文件时报 Operation not permitted。原因虚拟机开机后 vmhgfs-fuse 没有自动挂载或者 VMware 共享文件夹设置没有被 open-vm-tools 识别。写入失败则多半是挂载时没加 allow_other 和 uid/gid 参数导致挂载点归 root 所有其他用户无法写入。解决先执行 vmware-hgfsclient 确认虚拟机确实能看到共享目录再手动执行 vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other,uid1000,gid1000。如果手动挂载成功再考虑开机自动挂载。开机自动挂载我推荐 systemd 而不是 fstab因为 vmhgfs-fuse 依赖 open-vm-tools 的服务systemd 可以设置 Afteropen-vm-tools.service。写一个 /etc/systemd/system/mnt-hgfs.serviceExecStart 填完整的挂载命令enable 后重启测试。不要直接把共享文件夹挂载为 HDFS 数据目录FUSE 文件系统和本地 xfs/ext4 在写入语义上有差异HDFS 在这种文件系统上跑容易出奇奇怪怪的延迟。5.6 虚拟机重启后环境变量与服务全部丢失现象虚拟机重启后手动执行 hadoop version 提示 command not foundstart-dfs.sh 也找不到之前明明配置过环境变量。原因环境变量写在了 ~/.bashrc 里但 Hadoop 节点间远程执行启动命令走的是 SSH 非交互 shell默认不加载 ~/.bashrc。另外如果使用图形界面重启桌面进程继承了 gnome-session 的环境变量而终端新开的 shell 又重新加载了一次 bashrc造成“有的终端有命令有的终端没有命令”的割裂感。解决把环境变量统一放到 /etc/profile.d/hadoop.sh这个文件在登录 shell 和 SSH 非交互登录时都会被 /etc/profile 间接加载。然后确认各节点 /etc/hosts 里的主机名映射不依赖于 DHCP 分配的动态 IP。虚拟机重启后 IP 可能变化而 Hadoop 配置里全是主机名IP 一变节点间通信就断。最稳的办法是把所有虚拟机网络改为 NAT 模式下的固定 DHCP 保留地址或者在 netplan 里配置静态 IP。6. 集群配好了先别急着提交作业一套从进程到数据读写的验收清单环境搭建完成不是“能启动就行”我会强制自己跑完一整套验收流程再判断环境是否真正可用。第一层是进程检查用 jps 看每个节点进程是否齐全。我不只盯着 master 看而是分别 ssh 到每台 slave 上执行 jps确认 DataNode 和 NodeManager 都存在。这一步能顺手验证 SSH 免密登录在非交互 shell 下是否正常如果哪台机器需要手动输入密码才能执行 jps说明前面配置的 profile.d 环境变量或 SSH key 还没覆盖全。第二层是 Web UI。HDFS 的 NameNode 页面在 http://hadoop-master:9870YARN 的 ResourceManager 页面在 http://hadoop-master:8088。浏览器访问时把地址里的主机名换成宿主机能解析到的 IP192.168.30.100:9870。这两个页面打开后重点看 Datanode 列表里的节点数和 Live Nodes 是否等于 workers 文件里的节点数以及 YARN 页面的 Active Nodes 数。如果页面能打开但节点数少了说明网络通信没问题问题出在注册和端口上。第三层是实际数据读写。我习惯先创建一个测试目录再上传一个文件然后下载回来比对 MD5。HDFS 的数据块分布在多个节点上这一步能同时验证客户端、NameNode、DataNode 三方协作是否正常hdfs dfs -mkdir -p /test hdfs dfs -put /mnt/hgfs/sample_data.log /test/sample_data.log hdfs dfs -cat /test/sample_data.log | head -n 5 hdfs dfs -get /test/sample_data.log /tmp/sample_data_backup.log md5sum /mnt/hgfs/sample_data.log /tmp/sample_data_backup.logMD5 不一致说明数据在写入或传输过程中出了问题最常见的元凶是副本数配置和 DataNode 磁盘目录权限冲突。这一套跑完后我还会提交一个 WordCount 作业验证 MapReduce 的完整调度链路。WordCount 的 jar 在 Hadoop 安装包的 share/hadoop/mapreduce 目录下提交命令参考官方示例参数里指定输入输出路径。注意输出路径必须事先不存在否则作业会直接报 FileAlreadyExistsException。第一次作业运行会从 HDFS 拉一堆依赖 jar日志看似卡住其实是在初始化容器启动后自然加速。最后一个技巧是打快照。在格式化 NameNode 之前给每台虚拟机打一个干净快照。后续配置调坏、想重新拉集群直接回滚到快照比重新装系统省半个小时。我自己搭测试集群时也常用 Cloudera 或 Apache 发行版但基于 Ubuntu 手工搭一遍能让你把配置文件的参数真正理解透。遇到玄学问题就比着日志一步步查不要急着重装Hadoop 的日志已经把答案写得很清楚了。希望这些步骤和踩坑记录对你有用环境跑通了之后你自然会开始琢磨副本摆放策略和参数调优那时候这套环境就是你的实验场。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑