1. 为什么在虚拟机里装Hadoop,而不是直接上物理机或云服务
“Hadoop安装(虚拟机)”这个标题背后藏着的,不是一句简单的操作指令,而是一整套面向学习者、初探分布式系统的人最务实的技术路径选择。我带过不少刚接触大数据的同学,第一课永远不是讲MapReduce原理,而是先让他们在虚拟机里把Hadoop跑起来——不是因为物理机不行,也不是云平台不香,而是虚拟机是唯一能同时满足“可控、可逆、可观察、可复现”这四个硬性条件的环境载体。
你可能已经试过在笔记本上直接装Linux双系统,结果网卡驱动崩了、显卡黑屏了,折腾三天连SSH都连不上;也可能注册过某云厂商的免费试用集群,点几下就出来三台节点,但根本看不到NameNode日志在哪刷、DataNode怎么心跳、SecondaryNameNode到底干了啥——所有过程被封装成按钮,就像给你一台全自动咖啡机,却禁止你打开后盖看磨豆器怎么转。这不是学Hadoop,这是学点单。
而虚拟机,尤其是VMware Workstation或VirtualBox这类桌面级方案,它给你的是一个“透明玻璃盒”:你能随时暂停虚拟机看进程树,能截取网络包抓HDFS客户端的RPC调用,能故意删掉dfs.name.dir目录然后观察格式化流程如何重建元数据,甚至可以把整个虚拟机快照打包发给同学,说“你直接导入就能看到我刚才出错的现场”。这种颗粒度的掌控力,在真实生产环境里是奢侈的,在公有云上是受限的,唯独在本地虚拟机里,它是默认配置。
关键词“HADOOP”在这里不是指代某个版本号或发行版,而是代表一整套分布式协调范式:主从架构、心跳机制、租约管理、块报告、安全模式、编辑日志与镜像文件分离……这些概念如果只靠PPT讲,听十遍也记不住;但当你在虚拟机里手动改完core-site.xml后,hadoop fs -ls /命令突然报错“Connection refused”,再翻namenode.out日志发现端口被占用,顺藤摸瓜查到是8020被另一个Java进程占了——那一刻,你记住的不是端口号,而是“Hadoop服务启动前必须确保端口空闲”这个血的教训。
所以这个标题的本质,是在说:我们不追求最快上线,而追求最深理解;不要一键部署的幻觉,只要每一步都踩得踏实、看得清楚、改得明白。它适合三类人:高校课程实验的学生、准备跳槽大数据岗位的转行者、以及需要给团队做内部培训的技术负责人。他们共同的需求不是“跑通就行”,而是“出问题时能自己定位”。
我试过用Docker Compose拉起伪分布Hadoop,启动快、隔离好,但学生反馈:“容器里jps看不到进程,log目录进不去,连tail -f都卡住”;我也试过用Ansible批量部署三节点集群,脚本写得漂亮,但一旦某个节点SSH密钥没配对,整个playbook就停在那,没人知道是网络问题还是权限问题。反而是手敲ssh-keygen、scp、hdfs namenode -format这几条命令,在虚拟机里反复失败又重来,最后形成肌肉记忆——这才是入门该有的节奏。
提示:别急着下载Hadoop二进制包。先确认你的虚拟机内存至少分配4GB,CPU核心数不少于2个,硬盘预留30GB以上可用空间。很多初学者卡在第一步不是因为命令写错,而是虚拟机资源不足导致JVM频繁GC甚至直接OOM,日志里满屏“java.lang.OutOfMemoryError: Java heap space”,却误以为是配置文件写错了。
2. 安装前必须厘清的四大底层依赖与逻辑关系
Hadoop不是独立运行的孤岛,它像一栋老式砖混结构小楼,地基、承重墙、水电管线、门窗框架缺一不可。很多人装到一半报错“Unable to load native-hadoop library”,或者start-dfs.sh执行后jps里压根没看到NameNode,根源往往不在Hadoop本身,而在下面这四层支撑体系没搭稳。
2.1 Java环境:不是装了就行,而是版本、位数、路径三者必须咬合
Hadoop 3.x官方明确要求JDK 8u191+ 或 JDK 11,但实际测试中你会发现:JDK 11在某些Hadoop 3.2.1旧版本上会触发ClassCastException,而JDK 17则因移除了部分JNI接口导致libhadoop.so加载失败。这不是玄学,是Hadoop源码里大量使用了sun.misc.Unsafe和javax.xml.bind,这些API在JDK 11之后逐步废弃,直到Hadoop 3.3.0才完成全面适配。
我实测下来最稳的组合是:OpenJDK 8u362(LTS版本) + Hadoop 3.3.6。为什么选OpenJDK而非Oracle JDK?因为后者从Java 11起对商业用途收费,且其JRE打包方式与Hadoop启动脚本中的JAVA_HOME解析逻辑存在兼容性差异——OpenJDK的bin目录结构更“干净”,不会多出jre子目录干扰判断。
关键操作不是apt install openjdk-8-jdk就完事。你必须手动验证三个点:
java -version输出必须含“OpenJDK Runtime Environment (build 1.8.0_362-b09)”字样;which java返回路径必须是/usr/lib/jvm/java-8-openjdk-amd64/bin/java这类标准路径,不能是/usr/bin/java(那是符号链接,Hadoop脚本有时会绕过);echo $JAVA_HOME必须精确指向JDK根目录,比如/usr/lib/jvm/java-8-openjdk-amd64,绝对不能带末尾斜杠——Hadoop的hadoop-env.sh里有一行export JAVA_HOME=${JAVA_HOME},如果JAVA_HOME以/结尾,会导致后续$JAVA_HOME/bin/java拼成/path//bin/java,Linux会把它当两个连续斜杠处理,多数情况能容错,但在某些精简版BusyBox环境中会直接报“command not found”。
注意:别信网上那些“export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))”的万能命令。它在Ubuntu上可能返回
/usr/lib/jvm/java-8-openjdk-amd64/jre,多了一层jre,导致Hadoop找不到tools.jar。最保险的方式永远是手动写死路径,并加到~/.bashrc末尾,然后source ~/.bashrc。
2.2 SSH无密码登录:不是为了省事,而是Hadoop进程通信的底层信道
Hadoop启动脚本(如start-dfs.sh)本质是一串SSH命令的集合体。它会依次向每个配置好的主机名(包括localhost)发起SSH连接,然后在远程执行hadoop-daemon.sh start namenode这类命令。如果你没配好SSH免密,脚本会在第一个节点卡住,等你输密码——而它根本不会提示“请输密码”,只会静默超时,最后告诉你“starting namenode, logging to …”但jps里啥都没有。
这里有个极易被忽略的细节:Hadoop读取的是$HADOOP_CONF_DIR/slaves文件里的主机名列表,而不是core-site.xml里的fs.defaultFS地址。也就是说,即使你只打算跑伪分布式(所有服务都在localhost),slaves文件里也必须写localhost,且ssh localhost必须能免密登录。很多人写成127.0.0.1,结果ssh 127.0.0.1通了,ssh localhost却提示“Permission denied”,因为SSH的known_hosts是按主机名记录的,localhost和127.0.0.1被视为两个不同主机。
实操时建议分三步走:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa:生成密钥时不设密码(-P ''),否则每次SSH仍要输密码;ssh-copy-id -i ~/.ssh/id_rsa.pub localhost:把公钥拷到localhost的authorized_keys里;ssh -o StrictHostKeyChecking=no localhost echo ok:加参数跳过首次连接确认,确保脚本能静默执行。
提示:检查
~/.ssh/authorized_keys权限必须是600(chmod 600 ~/.ssh/authorized_keys),目录~/.ssh必须是700。Linux对SSH密钥权限极其敏感,权限过宽(比如755)会导致SSH直接拒绝读取密钥,错误信息却是模糊的“Permission denied (publickey)”。
2.3 主机名与hosts映射:分布式系统的“DNS简易替代方案”
Hadoop节点间通信高度依赖主机名解析。NameNode启动后会把自己的主机名(不是IP)广播给DataNode,DataNode再用这个主机名反向连接NameNode。如果你的虚拟机hostname是ubuntu,但/etc/hosts里没把127.0.0.1映射到ubuntu,就会出现DataNode注册失败,日志里反复打印“Failed to connect to ubuntu/127.0.0.1:9820”。
正确做法是三统一:
hostname命令输出的值(如hadoop-master);/etc/hosts里对应IP的那行主机名(127.0.0.1 hadoop-master);core-site.xml中fs.defaultFS的主机名部分(hdfs://hadoop-master:9000)。
我见过最典型的坑是:虚拟机克隆后hostname自动变成ubuntu-clone,但/etc/hosts还写着老名字,导致Hadoop服务启动后互相找不到。解决方法不是改配置文件,而是先统一主机名:
sudo hostnamectl set-hostname hadoop-master echo "127.0.0.1 hadoop-master" | sudo tee -a /etc/hosts注意tee -a是追加,别用>覆盖整个hosts,否则会删掉原有的127.0.0.1 localhost映射,导致本地回环失效。
2.4 文件系统权限与用户隔离:避免“权限地狱”的前置防御
Hadoop默认以当前用户身份运行所有进程。如果你用root用户启动,那么所有HDFS数据块文件都会属于root,后续普通用户(比如hadoop)就无法读写。更麻烦的是,HDFS的安全模式(Safe Mode)在检测到文件系统权限异常时会自动激活,拒绝一切写操作,而错误日志里只写“NameNode is in safe mode”,不告诉你为啥。
因此,强烈建议创建专用用户:
sudo adduser --disabled-password --gecos "" hadoop sudo usermod -aG sudo hadoop sudo chown -R hadoop:hadoop /opt/hadoop这样做的好处不仅是安全,更是调试便利:当你发现DataNode起不来,可以直接sudo -u hadoop tail -f /opt/hadoop/logs/hadoop-hadoop-datanode-*.log,不用切用户再查日志,避免权限混乱。
实操心得:别把Hadoop解压到
/home/hadoop/目录下。因为/home分区通常空间较小(尤其虚拟机默认只分20GB),而HDFS数据目录(dfs.data.dir)默认在/opt/hadoop/data,一旦数据量上来,/home爆满会导致整个系统卡死。最佳实践是解压到/opt/hadoop,然后在hdfs-site.xml里显式指定dfs.name.dir和dfs.data.dir到大容量分区,比如/data/hadoop/namenode和/data/hadoop/datanode。
3. 四配置文件逐行精解:不只是填参数,更要懂每行背后的约束条件
Hadoop的配置不是填空游戏,而是构建一套分布式契约。core-site.xml定义“我们用什么协议访问”,hdfs-site.xml定义“数据怎么存、存几份、谁管元数据”,mapred-site.xml定义“计算任务怎么调度”,yarn-site.xml定义“资源怎么分配”。漏掉任意一行,或填错一个值,都可能让整个集群陷入“半瘫痪”状态——服务看似在跑,但提交作业就失败,或者上传文件成功却列不出来。
3.1 core-site.xml:HDFS访问入口的“门牌号”与“邮编”
这个文件只做一件事:告诉所有Hadoop客户端,“HDFS的根地址在哪”。但它隐含三个关键约束:
- 协议必须是hdfs://,不能是file://或http://:
file://是本地文件系统,http://是Web UI,只有hdfs://才触发DistributedFileSystem客户端; - 主机名必须可解析,且端口必须与NameNode实际监听端口一致:默认9000,但Hadoop 3.x已改为9820(NameNode RPC端口),9000现在是旧版兼容端口;
- 路径必须是根路径
/,不能带子目录:hdfs://hadoop-master:9820/mydata是非法的,HDFS路径由后续API调用时指定。
标准配置如下:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop-master:9820</value> <description>HDFS namenode URI</description> </property> </configuration>为什么用9820而不是9000?因为Hadoop 3.x将RPC端口(NameNode与DataNode通信)和HTTP端口(Web UI)做了严格分离。9000端口在新版本中已被弃用,强行使用会导致DataNode注册失败,日志里报“Call From hadoop-master/127.0.0.1 to hadoop-master:9000 failed on connection exception”。这个错误信息极具迷惑性——它没说端口废弃,只说连接异常,新手往往去查防火墙,其实根本没开防火墙,是端口本身就不存在。
注意:
fs.defaultFS的value值里不能有空格、不能有换行、不能用中文注释。XML对空白字符极其敏感,一个不小心粘贴进来的全角空格,会导致Hadoop解析XML失败,报错“Content is not allowed in prolog”,这个错误指向XML声明之前的内容,但实际就是value值里混入了不可见字符。
3.2 hdfs-site.xml:数据存储的“宪法”,规定副本、目录、安全模式阈值
如果说core-site.xml是门牌号,hdfs-site.xml就是整栋楼的建筑规范。它强制约定:
- 每个文件块必须存几份(dfs.replication);
- 元数据存在哪(dfs.namenode.name.dir);
- 数据块存在哪(dfs.datanode.data.dir);
- 安全模式退出条件(dfs.namenode.safemode.threshold-pct)。
标准配置(伪分布式):
<configuration> <property> <name>dfs.replication</name> <value>1</value> <description>Default block replication. Should be 1 for pseudo-distributed mode.</description> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:/opt/hadoop/data/namenode</value> <description>Path on the local filesystem where the NameNode stores the namespace and transactions.</description> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/opt/hadoop/data/datanode</value> <description>Comma separated list of paths on the local filesystem of a DataNode.</description> </property> <property> <name>dfs.namenode.safemode.threshold-pct</name> <value>0.999</value> <description>Specifies the percentage of blocks that should satisfy the minimal replication requirement.</description> </property> </configuration>重点解释dfs.namenode.safemode.threshold-pct:它的默认值是0.999(99.9%),意思是NameNode启动后,必须等到99.9%的数据块达到最小副本数(即dfs.replication值),才会自动退出安全模式。在伪分布式环境下,只有一个DataNode,所有块都只能存1份,所以只要有一个块没报告上来,就卡在安全模式。此时hadoop fs -ls /会报“Safe mode is ON”,而hdfs dfsadmin -safemode get返回“ON”。
解决方案不是调低这个阈值(虽然hdfs dfsadmin -safemode leave能强制退出),而是确保DataNode真正启动并完成块报告。常见原因是dfs.datanode.data.dir目录权限不对,DataNode进程无法在该目录下创建current子目录,导致块报告失败。检查方法:ls -ld /opt/hadoop/data/datanode,必须是hadoop用户可写。
实操心得:
dfs.replication设为1仅限学习环境。生产环境必须≥3,因为HDFS的设计哲学是“用冗余换可靠”。设为1意味着任何一个磁盘故障,数据就永久丢失——这违背了HDFS存在的根本意义。所以你在虚拟机里练熟了replication=1,下一步必须立刻改成3,并在三台虚拟机上部署真集群,否则永远不懂“机架感知”和“副本放置策略”。
3.3 mapred-site.xml:MapReduce计算框架的“交通管制图”
这个文件定义MapReduce作业如何被调度执行。Hadoop 2.x之后引入YARN,MapReduce退化为YARN上的一个计算框架,因此mapred-site.xml的核心作用是告诉MapReduce客户端:“去找YARN要资源”。
关键配置只有两行:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> <description>Execution framework setting.</description> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>mapreduce.framework.name必须是yarn,不能是local(本地模式)或classic(旧版JobTracker)。设错会导致hadoop jar命令报“Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name”,字面意思是“无法初始化集群”,实际就是找不到YARN ResourceManager。
第二行mapreduce.application.classpath常被忽略,但它决定了MapReduce任务运行时能加载哪些JAR包。如果为空或路径错误,运行WordCount会报“ClassNotFoundException: org.apache.hadoop.mapreduce.Mapper”,因为Mapper类所在的hadoop-mapreduce-client-core-*.jar没被加载。
提示:Hadoop 3.x的classpath变量名已从
$HADOOP_HOME变为$HADOOP_MAPRED_HOME,但很多教程还沿用旧写法。你可以在终端执行echo $HADOOP_MAPRED_HOME确认路径,通常是/opt/hadoop/share/hadoop/mapreduce。
3.4 yarn-site.xml:资源调度的“中央调度室”规则
YARN是Hadoop的资源管理层,它把集群资源(CPU、内存)抽象成Container,由ResourceManager统一分配,NodeManager负责执行。yarn-site.xml就是ResourceManager的“宪法”。
核心配置:
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop-master</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>512</value> </property> </configuration>yarn.resourcemanager.hostname必须与core-site.xml里的主机名完全一致,否则NodeManager启动后无法注册到ResourceManager,日志里会疯狂刷“Connection refused on port 8031”,因为8031是ResourceManager的ResourceTrackerService端口。
yarn.nodemanager.aux-services设为mapreduce_shuffle,这是MapReduce任务Shuffle阶段必需的服务。如果漏掉,运行MapReduce作业时会报“Invalid auxService:mapreduce_shuffle”,因为NodeManager不知道该启动哪个辅助服务来处理Map输出的中间数据。
内存参数yarn.nodemanager.resource.memory-mb必须小于虚拟机总内存。我给虚拟机分了4GB内存,这里设2048MB(2GB),留2GB给系统和其他Hadoop进程(NameNode、DataNode、ResourceManager本身)。如果设成4096,NodeManager启动时会直接OOM崩溃,日志里只有“Killed process”,没有具体原因——这是Linux内核OOM Killer干的,它会杀掉占用内存最多的进程,而NodeManager恰好符合。
注意:YARN的Web UI默认端口是8088,但Hadoop 3.x已改为8088(旧版是8088,新版没变,但有些文档写错成8032)。访问
http://hadoop-master:8088能看到集群概览、正在运行的应用、NodeManager状态。这是你判断YARN是否真跑起来的最直观依据。
4. 启动、验证与排错全流程:从黑屏到绿灯的每一步现场记录
安装配置只是铺路,真正的考验在启动那一刻。我整理了一份按时间线排列的完整操作日志,包含每一步的预期输出、常见异常、以及我当时是怎么一步步定位的。这不是教科书式的理想流程,而是真实发生过的“踩坑-分析-修复”全过程。
4.1 格式化NameNode:第一次心跳前的“奠基仪式”
在首次启动HDFS前,必须执行格式化,这相当于给HDFS的“大脑”(NameNode)初始化元数据存储。命令很简单:
hdfs namenode -format预期输出最后几行应该是:
Storage directory /opt/hadoop/data/namenode has been successfully formatted.但如果看到:
ERROR: Cannot create directory /opt/hadoop/data/namenode/current说明/opt/hadoop/data/namenode目录不存在,或hadoop用户没有写权限。此时不要慌着sudo mkdir,而是先检查:
ls -ld /opt/hadoop/data # 如果显示 drwxr-xr-x 3 root root ...,说明是root创建的,hadoop用户没权限 sudo chown -R hadoop:hadoop /opt/hadoop/data更隐蔽的错误是:
ERROR: java.io.IOException: Cannot create directory /opt/hadoop/data/namenode/current at org.apache.hadoop.hdfs.server.common.Storage$StorageDirectory.clearDirectory(Storage.java:412)这通常是因为/opt/hadoop/data/namenode目录下已有残留文件(比如上次格式化失败留下的in_use.lock),Hadoop拒绝覆盖。解决方案是手动清空:
rm -rf /opt/hadoop/data/namenode/*提示:格式化命令会生成
/opt/hadoop/data/namenode/current/VERSION文件,里面记录了clusterID。这个ID必须与后续DataNode的clusterID一致,否则DataNode无法注册。所以格式化只需执行一次,集群运行期间严禁重复执行,否则所有DataNode都会报“Incompatible clusterIDs”。
4.2 启动HDFS服务:观察jps与日志的“双盲验证法”
格式化成功后,启动HDFS:
start-dfs.sh预期行为:终端输出类似:
Starting namenodes on [hadoop-master] hadoop-master: starting namenode, logging to /opt/hadoop/logs/hadoop-hadoop-namenode-hadoop-master.out hadoop-master: starting datanode, logging to /opt/hadoop/logs/hadoop-hadoop-datanode-hadoop-master.out但光看这个不够,必须立即验证:
第一步:jps检查进程
jps应看到至少三个进程:
2134 NameNode 2256 DataNode 2389 Jps如果只有Jps,说明服务根本没起来。此时不要重试,先看日志:
第二步:日志定位(最有效)
- NameNode日志:
tail -100f /opt/hadoop/logs/hadoop-hadoop-namenode-*.log - DataNode日志:
tail -100f /opt/hadoop/logs/hadoop-hadoop-datanode-*.log
常见日志错误:
java.net.BindException: Address already in use:端口被占,用sudo lsof -i :9820查是谁,然后kill -9 PID;org.apache.hadoop.hdfs.server.common.InconsistentFSStateException:clusterID不匹配,删掉/opt/hadoop/data/datanode目录重新格式化;java.io.FileNotFoundException: /opt/hadoop/data/datanode/current/VERSION:DataNode目录为空,说明dfs.datanode.data.dir路径配置错误或权限不足。
我遇到过一次诡异问题:jps能看到NameNode和DataNode,但hadoop fs -ls /报“Connection refused”。查日志发现NameNode启动后立即关闭,原因是/etc/hosts里hadoop-master解析到了IPv6地址::1,而Hadoop默认只监听IPv4。解决方案是在hadoop-env.sh里加一行:
export HADOOP_OPTS="-Djava.net.preferIPv4Stack=true"实操心得:别依赖
start-dfs.sh的输出。我养成的习惯是,执行完启动命令后,立刻开三个终端窗口:一个jps,一个tail -f namenode.log,一个tail -f datanode.log。三窗口并排,眼睛扫过去,哪个窗口在刷日志,哪个进程在闪退,一目了然。这种“多窗口监控法”比任何自动化脚本都可靠。
4.3 启动YARN服务:资源调度器的“点火测试”
HDFS跑通后,启动YARN:
start-yarn.sh预期jps新增两个进程:
2512 ResourceManager 2634 NodeManager验证方式:
- 访问
http://hadoop-master:8088,应该能看到YARN Web UI,显示“Cluster Overview”和“Nodes”; - 执行
yarn node -list,应返回类似:
Total Nodes:1 Node-Id Node-State Node-Http-Address Number-of-Running-Containers hadoop-master:45454 RUNNING hadoop-master:8042 0如果Web UI打不开,先检查端口:
netstat -tuln | grep 8088 # 应该有 java 进程监听 0.0.0.0:8088如果没监听,说明ResourceManager没起来。查/opt/hadoop/logs/yarn-*-resourcemanager-*.log,最常见的错误是:
ERROR org.apache.hadoop.yarn.server.resourcemanager.ResourceManager: Error starting ResourceManager java.lang.RuntimeException: java.net.UnknownHostException: hadoop-master这又回到hosts配置问题——ResourceManager启动时会尝试解析yarn.resourcemanager.hostname,解析失败就直接退出。此时ping hadoop-master应该通,不通就改/etc/hosts。
注意:YARN的NodeManager默认监听端口是8042(Web UI)和8040(IPC),如果
yarn node -list返回空,大概率是NodeManager的yarn.nodemanager.address配置错误,或者防火墙阻止了8040端口。虚拟机里一般没防火墙,所以优先查配置。
4.4 运行WordCount验证:从上传文件到看到结果的端到端链路
所有服务启动后,用经典WordCount验证端到端是否通畅:
# 1. 创建HDFS输入目录 hadoop fs -mkdir -p /input # 2. 上传本地文件(假设当前目录有test.txt) hadoop fs -put test.txt /input # 3. 运行WordCount(Hadoop自带示例) hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /input /output # 4. 查看输出 hadoop fs -cat /output/part-r-00000如果第3步报错:
Application application_1234567890_0001 failed 2 times due to AM Container for appattempt_1234567890_0001_000002 exited with exitCode: -1000:这是YARN资源不足,检查yarn.nodemanager.resource.memory-mb是否设得太小,或者虚拟机内存真的不够;java.io.IOException: Failed to replace a bad datanode...:DataNode没注册成功,回到4.2节排查;File does not exist: /input/test.txt:上传失败,用hadoop fs -ls /input确认文件是否存在。
最让我印象深刻的一次失败:所有服务都正常,jps进程齐全,日志也没报错,但WordCount一直卡在“ACCEPTED”状态,不进入“RUNNING”。查YARN Web UI发现ApplicationMaster容器启动失败,日志里只有一行:
Container exited with a non-zero exit code 143Exit Code 143是Linux的“SIGTERM”信号,说明容器被主动杀死。最终定位到是yarn.scheduler.maximum-allocation-mb没配置,默认值太小(1024MB),而WordCount的ApplicationMaster需要1536MB内存。解决方案是在yarn-site.xml里加:
<property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> </property>实操心得:WordCount不是终点,而是起点。每次配置调整后,我都用它跑一遍,因为它短平快,5秒内出结果或报错。比写Shell脚本检查端口、比curl API更直接。而且它的输出
part-r-00000文件内容,能让你一眼看出MapReduce是否真在工作——如果输出是乱码或空,说明Shuffle环节出问题;如果输出有单词但计数全为1,说明Combiner没生效或输入文件太小。
5. 常见问题速查表与独家避坑指南:那些文档里不会写的真相
以下是我过去三年在虚拟机里装Hadoop踩过的所有坑,按出现频率排序,每一条都附带真实日志片段、根本原因、以及一招制敌的解决方案。这不是理论推演,而是血泪经验。
| 问题现象 | 典型日志/错误信息 | 根本原因 | 一招解决 |
|---|---|---|---|
start-dfs.sh执行后jps看不到NameNode | tail -f namenode.log显示java.lang.IllegalArgumentException: Does not contain a valid host:port authority: file:///opt/hadoop/data/namenode | core-site.xml中fs.defaultFS的value写成了file:///开头,而不是hdfs:// | 检查fs.defaultFS,确保协议是hdfs://,主机名正确,端口是9820 |
DataNode启动后立即退出,日志里反复刷Failed to report blocks | datanode.log中WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Problem connecting to server: hadoop-master/127.0.0.1:9820 | NameNode的RPC端口(9820)未监听,或DataNode配置的fs.defaultFS端口与NameNode实际端口不一致 | netstat -tuln | grep 9820确认NameNode是否监听;检查core-site.xml和hdfs-site.xml端口是否统一 |
| YARN Web UI打不开(8088端口拒绝连接) | netstat -tuln | grep 8088无输出;yarn.resourcemanager.webapp.address默认是0.0.0.0:8088,但某些虚拟机网络模式下绑定失败 | ResourceManager默认绑定0.0.0.0,但在NAT模式虚拟机里可能绑定到127.0.0.1,导致外部无法访问 | 在yarn-site.xml中显式配置<name>yarn.resourcemanager.webapp.address</name><value>hadoop-master:8088</value> |
hadoop fs -ls /报Safe mode is ON,但hdfs dfsadmin -safemode get返回ON,hdfs dfsadmin -safemode leave无效 | namenode.log中INFO org.apache.hadoop.hdfs.server.namenode.FSNamesystem: Safe mode is ON.后紧跟INFO org.apache.hadoop.hdfs.server.namenode.FSNamesystem: Number of live datanodes '0' | DataNode根本没注册成功,NameNode收不到任何块报告,安全模式永远无法退出 | 检查datanode.log,90%概率是dfs.datanode.data.dir目录权限不对,或/etc/hosts里hadoop-master解析失败 |
运行MapReduce作业时,ApplicationMaster容器反复重启,日志里只有Container exited with exitCode: 143 | yarn logs -applicationId application_1234567890_0001输出Killed by signal 15 (SIGTERM) | NodeManager内存不足,OOM Killer杀掉了AM容器 | 调大yarn.nodemanager.resource.memory-mb,并确保yarn.scheduler.maximum-allocation-mb≥ AM所需内存(通常1536MB) |
独家避坑技巧1:永远用
hadoop version和hadoop classpath两条命令开局。前者确认Hadoop二进制包加载正确,后者确认所有依赖JAR都在classpath里。如果`hadoop class