Hadoop Linux实战指南:从伪分布搭建到WordCount运行
1. 这不是“入门教程”,而是一份 Hadoop 实战者写给真实世界的说明书
你点开这篇内容,大概率不是为了背诵“Hadoop 是一个分布式计算框架”这种教科书定义。你可能刚被领导甩过来一句“把这批日志跑个 WordCount”,也可能在实验室里对着三台虚拟机反复重装 JDK 和 SSH 密钥,又或者在头歌平台提交了第七次失败的 Hadoop 配置作业,系统提示“NameNode 未启动”。这些场景背后,藏着同一个真相:Hadoop 从不考你概念背得有多熟,它只考你能不能在 Linux 终端里敲出那条真正让集群活起来的命令,能不能看懂jps输出里缺了哪个进程,能不能在core-site.xml里把fs.defaultFS的值配对,而不是照着某篇过时博客复制粘贴后发现路径里多了个空格。
Hadoop 的核心关键词从来就不是“高大上”,而是“稳、准、糙”。稳,是 NameNode 和 DataNode 能在后台持续跑满一周不出错;准,是hdfs dfs -ls /真的能列出目录,yarn node -list真的能返回 RUNNING 状态的节点;糙,是你得亲手改 hosts 文件、关 SELinux、调 JVM 堆内存、查/var/log/hadoop/下每一条 WARN 日志——没有图形界面兜底,没有一键安装包保你万无一失。我带过二十多届学生做 Hadoop 实验,也帮三家企业从零搭过生产集群,最深的体会是:所有“安装失败”的背后,90% 是环境细节没抠死,不是技术原理没搞懂。这篇内容,就是把那些藏在官方文档犄角旮旯、被博客作者一笔带过的“糙活儿”,掰开揉碎,配上实操截图级的逻辑和参数依据,告诉你为什么必须这么干,以及不这么干会当场报什么错。它不讲 MapReduce 的 shuffle 机制有多精妙,但会告诉你mapred-site.xml里mapreduce.framework.name错配成local会导致你的 WordCount 任务永远卡在 ACCEPTED 状态;它不画 YARN 的资源调度流程图,但会手把手教你用yarn top看清哪个 Container 占着内存不放,拖垮整个集群。如果你正卡在“Linux 系统下 Hadoop 安装与使用(4 学时)”的实验报告里,或者正在阿里云 ECS 上部署三机集群却连hdfs namenode -format都通不过,那你需要的不是另一份概念复述,而是一份能让你终端里echo $?返回 0 的操作手册。
2. 项目整体设计与思路拆解:为什么必须从“单机伪分布”开始,而不是直接上“高可用集群”
2.1 伪分布模式不是妥协,而是唯一可靠的起点
很多初学者看到“Hadoop 高可用集群搭建”“Ambari 部署 Hadoop 集群”这类热搜词,第一反应是跳过基础,直奔 HA(High Availability)。这就像学开车先研究 F1 赛车的空气动力学,却连离合器半联动都找不到。Hadoop 的核心价值在于其分布式架构的容错与扩展能力,但这个能力的前提,是每个组件在单节点上能独立、稳定、可验证地运行。伪分布模式(Pseudo-Distributed Mode)正是这个前提的强制校验场。它把 NameNode、DataNode、ResourceManager、NodeManager 全部跑在同一台机器的不同 JVM 进程里,用localhost模拟网络通信,用本地文件系统模拟 HDFS。这种“自欺欺人”的设计,恰恰是最高效的排错沙盒。
提示:伪分布模式下,
hdfs dfs -ls /和yarn node -list的输出必须完全符合预期,这是后续一切操作的基石。任何一步失败,都意味着你的 Java 环境、SSH 免密、XML 配置或目录权限存在硬伤,此时强行加节点只会把问题放大十倍。
2.2 为什么拒绝“一键脚本”和“Windows 安装”?
网络上充斥着“Hadoop 免费一键安装包”“Hadoop Windows 安装教程”,它们看似省事,实则埋下巨大隐患。Hadoop 的本质是 Linux 生态的原生产物,其进程管理、文件权限、网络栈、JVM 行为都深度绑定于 POSIX 标准。Windows 上的 WSL 或 Cygwin 环境,无法完美复现生产环境的信号处理、进程树关系和磁盘 I/O 行为。我曾见过一个团队在 Windows 上用 WSL 成功跑通 WordCount,结果一上阿里云 CentOS 7 就因ulimit -n(文件描述符限制)默认值过低导致 DataNode 频繁 OOM,排查三天才发现根源。至于“一键脚本”,它把所有配置项硬编码,掩盖了core-site.xml中hadoop.tmp.dir必须指向有足够空间且hadoop用户可写的目录这一关键事实。当你的/tmp分区只有 2GB,而 Hadoop 默认将临时文件存于此处时,namenode -format会静默失败,日志里只有一行java.io.IOException: No space left on device,新手根本无从下手。
2.3 “三机部署”背后的工程逻辑:主从分离与角色隔离
当你从伪分布迈向真正的三机集群(1 Master + 2 Slave),设计的核心不再是“怎么让它们连上”,而是“怎么让它们各司其职、互不干扰”。Hadoop 的经典角色划分在此刻体现得淋漓尽致:
- Master 节点:只运行 NameNode(HDFS 主控)和 ResourceManager(YARN 主控)。它不存储数据,不执行任务,只做决策。因此,它的 CPU 和内存要留足余量给元数据服务和调度器。
- Slave 节点:只运行 DataNode(HDFS 数据块存储)和 NodeManager(YARN 任务执行容器)。它们是真正的“苦力”,需要大容量磁盘和充足内存来缓存数据块和运行 Map/Reduce 任务。
这种物理隔离杜绝了“脑体不分”带来的资源争抢。我曾在一个客户现场遇到故障:所有 Slave 节点的 DataNode 进程频繁挂掉,jps查看发现DataNode进程 PID 每分钟都在变。最终定位到是 Master 节点上误启了SecondaryNameNode,它疯狂向 Slave 发送检查点请求,占满了 Slave 的网络带宽和 CPU,导致 DataNode 心跳超时被 NameNode 主动下线。这就是角色混布的典型代价。
2.4 为什么 Ambari 不是初学者的首选?
Ambari 是 Apache 开源的 Hadoop 集群管理平台,它提供 Web UI,能一键部署、监控、告警。但它是一个“黑盒”封装层。当你在 Ambari UI 上点击“Start All Services”,它背后执行的是数百行 Shell 脚本、Ansible Playbook 和 Python 调用。如果启动失败,Ambari 日志只会告诉你Failed to start HDFS,而真正的根因可能藏在/var/log/hadoop/hdfs/hadoop-hdfs-namenode-master.log里一行java.net.UnknownHostException: master—— 因为你的/etc/hosts文件里master解析错了 IP。初学者绕过底层直接用 Ambari,等于在没学会骑自行车前就去开飞机,仪表盘上的红灯亮了,你连油门和刹车在哪都不知道。我的建议是:先用 Shell 手动搭通三机集群,确保hdfs dfs -put和yarn jar都能成功,再用 Ambari 来接管运维。这时,Ambari 对你而言是效率工具,而非认知拐杖。
3. 核心细节解析与实操要点:从 JDK 到 XML,每一个字符都决定成败
3.1 JDK:版本陷阱与环境变量的生死线
Hadoop 对 JDK 版本极其挑剔。官方文档明确要求:Hadoop 3.x 必须使用 JDK 8u161+ 或 JDK 11,绝对禁止使用 JDK 17+。这不是兼容性问题,而是 Hadoop 的hadoop-common模块大量使用了 JDK 8 的sun.misc.Unsafe类,该类在 JDK 9+ 中被模块化隔离,在 JDK 17 中被彻底移除。如果你在hadoop version命令后看到java.lang.NoClassDefFoundError: sun/misc/Unsafe,那一定是 JDK 版本踩雷了。
环境变量设置更是高频雷区。JAVA_HOME必须精确指向 JDK 的根目录,不能指向 JRE。常见错误是export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.362.b09-1.el7_9.x86_64/jre,这里多了一个/jre后缀。正确路径应为/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.362.b09-1.el7_9.x86_64。验证方法很简单:$JAVA_HOME/bin/java -version必须输出正确的 JDK 版本号。此外,PATH变量中$JAVA_HOME/bin必须排在系统默认java命令之前,否则which java仍会找到/usr/bin/java,导致 Hadoop 启动时加载错误的 JVM。
注意:
hadoop-env.sh文件中的export JAVA_HOME设置,只影响 Hadoop 自身进程,不影响你当前 Shell 的java命令。因此,你必须在~/.bashrc或/etc/profile中全局设置JAVA_HOME,并执行source ~/.bashrc生效。我见过太多人只改了hadoop-env.sh,结果hadoop version报错,却以为是 Hadoop 本身坏了。
3.2 SSH 免密登录:不是“能连上”,而是“连得对”
Hadoop 启动脚本(如start-dfs.sh)的本质,是通过 SSH 在远程节点上执行hadoop-daemon.sh start datanode这样的命令。因此,“免密登录”不是指ssh user@host能不输密码,而是指ssh user@host 'whoami'的输出必须是user,且ssh user@host 'hostname'的输出必须与hostname命令一致。很多初学者卡在这里,原因五花八门:
- 主机名解析错误:
/etc/hosts文件里127.0.0.1 localhost后面,必须加上本机的完整主机名(FQDN),例如127.0.0.1 master.localdomain master。如果只写127.0.0.1 master,ssh master会解析为127.0.0.1,而ssh master.localdomain才能解析为真实 IP。 - 公钥格式错误:
ssh-copy-id生成的id_rsa.pub内容,必须完整、无换行、无空格地追加到~/.ssh/authorized_keys文件末尾。我曾发现一个案例,authorized_keys文件末尾多了一个空行,导致 SSH 认证时读取公钥失败,日志里只显示Permission denied (publickey),毫无头绪。 - SELinux 干扰:CentOS/RHEL 默认开启 SELinux,它会阻止 SSH 读取
~/.ssh/authorized_keys。临时关闭用setenforce 0,永久关闭需修改/etc/selinux/config。更稳妥的做法是执行restorecon -Rv ~/.ssh,重置 SELinux 上下文。
3.3 核心配置文件:XML 里的魔鬼细节
Hadoop 的灵魂藏在四个 XML 文件里:core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml。它们不是模板,而是精确的指令集,每个<property>标签的<name>和<value>都必须严丝合缝。
3.3.1core-site.xml:HDFS 的“地址簿”
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://master:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property> </configuration>fs.defaultFS是 HDFS 的入口地址。master必须是/etc/hosts中能正确解析的主机名,9000是 NameNode 的 RPC 端口(Hadoop 2.x 默认是9000,3.x 默认是8020,务必核对版本!)。如果这里写成hdfs://localhost:9000,Slave 节点将无法连接 Master。hadoop.tmp.dir是 Hadoop 的临时工作目录,NameNode 的元数据、DataNode 的数据块副本都存于此。它必须由hadoop用户拥有且可写。创建命令是sudo mkdir -p /opt/hadoop/tmp && sudo chown -R hadoop:hadoop /opt/hadoop/tmp。如果权限不对,namenode -format会报java.io.IOException: Cannot create directory。
3.3.2hdfs-site.xml:数据存储的“宪法”
<configuration> <property> <name>dfs.namenode.name.dir</name> <value>file:/opt/hadoop/tmp/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/opt/hadoop/tmp/dfs/data</value> </property> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>dfs.namenode.name.dir和dfs.datanode.data.dir是 NameNode 元数据和 DataNode 数据块的物理存储路径。它们必须是file://协议开头的绝对路径,且目录必须存在、权限正确。dfs.replication设为1是伪分布和三机集群的起点,表示每个数据块只存一份。生产环境才设为3。
3.3.3yarn-site.xml:资源调度的“交通管制”
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>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> </configuration>yarn.resourcemanager.hostname必须与core-site.xml中的fs.defaultFS的主机名一致,否则 ResourceManager 无法注册到 HDFS。yarn.nodemanager.aux-services的值必须是mapreduce_shuffle,这是 MapReduce 任务 Shuffle 阶段必需的服务,拼错一个字母(如mapred_shuffle)都会导致 Map 任务无法启动。yarn.nodemanager.resource.memory-mb是 NodeManager 可分配给 Container 的总内存。它必须小于物理内存,且要为操作系统和其他进程(如 DataNode)预留至少 1GB。设得过大,NodeManager 会因 OOM 被系统 kill。
3.3.4mapred-site.xml:MapReduce 的“执行契约”
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </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表示任务提交到 YARN 集群执行;local表示本地模式(单线程),classic已废弃。如果这里错配,你的 WordCount 任务将永远卡在ACCEPTED状态,因为 ResourceManager 根本收不到它的启动请求。mapreduce.application.classpath定义了 MapReduce 任务的类路径。$HADOOP_MAPRED_HOME环境变量必须在hadoop-env.sh中正确定义,例如export HADOOP_MAPRED_HOME=$HADOOP_HOME/share/hadoop/mapreduce。如果路径错误,任务会报ClassNotFoundException。
3.4 目录权限与用户:Linux 底层的无声规则
Hadoop 是一个典型的“以用户为中心”的服务。hadoop-daemon.sh脚本启动进程时,会以当前 Shell 的用户身份运行。因此,所有 Hadoop 目录($HADOOP_HOME、hadoop.tmp.dir、dfs.name.dir、dfs.data.dir)必须由同一个用户(通常是hadoop)拥有。混合使用root和hadoop用户,是Permission denied错误的最大来源。
标准操作流程是:
- 创建专用用户:
sudo useradd -m hadoop - 切换用户:
su - hadoop - 解压 Hadoop:
tar -xzf hadoop-3.3.6.tar.gz -C /opt/ - 创建并授权临时目录:
sudo mkdir -p /opt/hadoop/tmp && sudo chown -R hadoop:hadoop /opt/hadoop/tmp - 修改
hadoop-env.sh:export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
实操心得:永远不要用
sudo ./start-dfs.sh。这会让 NameNode 以root用户启动,而 DataNode 以hadoop用户启动,导致 NameNode 无法识别 DataNode 的心跳。正确的做法是su - hadoop后,再执行./start-dfs.sh。
4. 实操过程与核心环节实现:从格式化到 WordCount,每一步都有回溯依据
4.1 伪分布模式全流程:一次成功的namenode -format是什么样子?
我们以 Hadoop 3.3.6 + JDK 8u362 + CentOS 7 为例,走一遍最精简的伪分布启动流程。所有命令均在hadoop用户下执行。
第一步:环境变量固化编辑~/.bashrc,添加:
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.362.b09-1.el7_9.x86_64 export HADOOP_HOME=/opt/hadoop-3.3.6 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HADOOP_MAPRED_HOME=$HADOOP_HOME export HADOOP_COMMON_HOME=$HADOOP_HOME export HADOOP_HDFS_HOME=$HADOOP_HOME export YARN_HOME=$HADOOP_HOME export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export HDFS_DATANODE_USER=hadoop export HDFS_NAMENODE_USER=hadoop export HDFS_SECONDARYNAMENODE_USER=hadoop export YARN_RESOURCEMANAGER_USER=hadoop export YARN_NODEMANAGER_USER=hadoop执行source ~/.bashrc生效,并验证java -version和hadoop version。
第二步:配置文件精修确保core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml如前文所述配置完毕。特别注意core-site.xml中的fs.defaultFS值为hdfs://localhost:9000(伪分布用localhost)。
第三步:格式化 NameNode这是最关键的一步。执行:
hdfs namenode -format成功输出的最后几行应该是:
Storage directory /opt/hadoop/tmp/dfs/name has been successfully formatted. ... Re-format filesystem in Storage Directory /opt/hadoop/tmp/dfs/name ? (Y or N) Y如果看到Storage directory ... has been successfully formatted.,说明元数据目录初始化成功。此时,/opt/hadoop/tmp/dfs/name/current/目录下会生成VERSION、seen_txid等文件。如果失败,立刻检查hadoop.tmp.dir权限和JAVA_HOME是否正确。
第四步:启动 HDFS 和 YARN
# 启动 HDFS(NameNode 和 DataNode) start-dfs.sh # 启动 YARN(ResourceManager 和 NodeManager) start-yarn.sh执行后,用jps命令检查进程:
[hadoop@master ~]$ jps 2145 DataNode 2289 ResourceManager 2402 NodeManager 1987 NameNode 2521 Jps必须同时看到NameNode、DataNode、ResourceManager、NodeManager四个进程。缺少任何一个,都说明对应服务启动失败。此时,查看/opt/hadoop-3.3.6/logs/下对应的日志文件(如hadoop-hadoop-namenode-master.log),错误通常就在第一行。
第五步:验证 HDFS 可用性
# 创建 HDFS 根目录 hdfs dfs -mkdir -p /user/hadoop # 上传一个测试文件 echo "Hello Hadoop" > test.txt hdfs dfs -put test.txt /user/hadoop/ # 列出文件 hdfs dfs -ls /user/hadoop/ # 输出应为:-rw-r--r-- 1 hadoop supergroup 13 2023-10-20 10:00 /user/hadoop/test.txt # 读取文件内容 hdfs dfs -cat /user/hadoop/test.txt # 输出应为:Hello Hadoop这五步,构成了伪分布模式的黄金闭环。任何一步中断,都意味着你的环境存在一个可定位、可修复的硬伤。
4.2 三机集群部署:Master 与 Slave 的协同密码
假设三台机器 IP 和主机名如下:
- Master:
192.168.1.10, hostnamemaster - Slave1:
192.168.1.11, hostnameslave1 - Slave2:
192.168.1.12, hostnameslave2
第一步:全节点统一环境在三台机器上,重复伪分布的“环境变量固化”和“JDK 安装”步骤。确保java -version和hadoop version输出一致。
第二步:Master 的 SSH 免密分发在 Master 上:
# 生成密钥(一路回车) ssh-keygen -t rsa -P '' # 将公钥分发到所有节点(包括自己) ssh-copy-id hadoop@master ssh-copy-id hadoop@slave1 ssh-copy-id hadoop@slave2验证:ssh hadoop@slave1 'hostname'应输出slave1。
第三步:配置文件差异化core-site.xml在所有节点保持一致:
<value>hdfs://master:9000</value>hdfs-site.xml在所有节点保持一致:
<value>file:/opt/hadoop/tmp/dfs/name</value> <!-- Master --> <value>file:/opt/hadoop/tmp/dfs/data</value> <!-- Slave1 & Slave2 -->workers文件(Hadoop 3.0+ 替代slaves)是关键:
- Master 的
/opt/hadoop-3.3.6/etc/hadoop/workers内容为:slave1 slave2 - Slave1 和 Slave2 的
workers文件可以为空,或只写自己(非必须)。
第四步:Master 启动,Slave 自动加入在 Master 上执行:
# 格式化 NameNode(仅 Master 执行一次!) hdfs namenode -format # 启动 HDFS(Master 启动 NameNode,自动 SSH 到 workers 启动 DataNode) start-dfs.sh # 启动 YARN(Master 启动 ResourceManager,自动 SSH 到 workers 启动 NodeManager) start-yarn.sh此时,jps在 Master 上应看到NameNode和ResourceManager;在 Slave1/2 上应看到DataNode和NodeManager。
第五步:集群状态验证
# 查看 HDFS 状态 hdfs dfsadmin -report # 输出中应包含两个 Live Datanodes,状态为 "In Service" # 查看 YARN 节点状态 yarn node -list -all # 输出中应有两个 NodeManager,状态为 "RUNNING"至此,一个功能完备的三机 Hadoop 集群宣告诞生。它能承载真实的 WordCount 任务,也能作为 Hive、Spark 等上层框架的底层存储和计算引擎。
4.3 WordCount 实战:从代码编写到集群运行的完整链路
“今天的任务完成 wordcount 的代码编写,然后编译打包好放到 hadoop 中运行”,这句话背后是一整套开发-构建-部署-执行的流水线。
第一步:Java 代码编写(WordCount.java)
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; import java.util.StringTokenizer; public class WordCount { public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(Object key, Text value, Context context) throws IOException, InterruptedException { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); } } } public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "word count"); job.setJarByClass(WordCount.class); job.setMapperClass(TokenizerMapper.class); job.setCombinerClass(IntSumReducer.class); job.setReducerClass(IntSumReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }第二步:编译与打包
# 创建目录结构 mkdir -p wordcount/src/main/java mv WordCount.java wordcount/src/main/java/ # 编译(需 Hadoop 的 jar 包) javac -classpath $(hadoop classpath) -d wordcount/classes wordcount/src/main/java/WordCount.java # 打包成 jar jar -cvf wordcount.jar -C wordcount/classes .hadoop classpath命令会输出所有 Hadoop 依赖的 JAR 路径,这是编译时-classpath的唯一正确来源。
第三步:上传输入文件到 HDFS
# 创建输入目录 hdfs dfs -mkdir -p /input # 上传本地文件(假设本地有 input.txt) hdfs dfs -put input.txt /input/第四步:提交任务到集群
# 执行 WordCount hadoop jar wordcount.jar WordCount /input /output # 查看输出 hdfs dfs -cat /output/part-r-00000如果看到类似hadoop 3的键值对,说明任务成功。如果失败,hadoop jar命令的输出会直接打印错误堆栈,这是最权威的调试依据。
5. 常见问题与排查技巧实录:那些让你抓狂的 WARN 和 ERROR,其实都有迹可循
5.1 启动失败类问题速查表
| 现象 | 可能原因 | 排查命令/日志 | 解决方案 |
|---|---|---|---|
start-dfs.sh后jps看不到NameNode | hadoop.tmp.dir目录不存在或权限不足 | ls -ld /opt/hadoop/tmp | sudo mkdir -p /opt/hadoop/tmp && sudo chown -R hadoop:hadoop /opt/hadoop/tmp |
jps看到NameNode,但看不到DataNode | SSH 免密失败,或workers文件主机名解析错误 | ssh hadoop@slave1 'hostname';cat /etc/hosts | 确保workers中的主机名与ssh命令中的完全一致;/etc/hosts中添加正确映射 |
hdfs dfs -ls /报Connection refused | fs.defaultFS端口错误(Hadoop 2.x 用9000,3.x 用8020) | netstat -tuln | grep 8020 | 检查core-site.xml,确认端口与hadoop version版本匹配 |
yarn node -list显示0个节点 | yarn.nodemanager.aux-services值拼写错误 | cat $HADOOP_HOME/etc/hadoop/yarn-site.xml | grep aux-services | 确保值为mapreduce_shuffle,无空格、无大小写错误 |
5.2 运行时异常类问题深度解析
5.2.1 “No route to host”:网络防火墙的隐形之手
当hdfs dfs -ls /报No route to host,而ping slave1是通的,问题几乎一定出在防火墙。CentOS 7 默认启用firewalld,它会拦截9000(或8020)、50070(HDFS Web UI)、8088(YARN Web UI)等端口。临时关闭用sudo systemctl stop firewalld,永久关闭用sudo systemctl disable firewalld。更安全的做法是开放特定端口:sudo firewall-cmd --permanent --add-port=8020/tcp,然后sudo firewall-cmd --reload。
5.2.2 “Safe mode is ON”:NameNode 的自我保护机制
hdfs dfs -put报错org.apache.hadoop.hdfs.server.namenode.SafeModeException,说明 NameNode 处于安全模式。这是 NameNode 启动后的保护状态,它会等待足够多的 DataNode 注册并报告数据块,才会退出。伪分布模式下,DataNode 启动较慢,可手动退出:hdfs dfsadmin -safemode leave。但更根本的解决是检查hdfs-site.xml中dfs.replication是否为1,以及dfs.namenode.name.dir和dfs.datanode.data.dir是否指向同一磁盘分区(避免因磁盘满导致 DataNode 无法上报)。
5.2.3 “Container exited with a non-zero exit code 143”:YARN 的内存杀手
这个错误表明某个 Container 被 YARN 的 NodeManager 主动杀死,原因是内存超限。143是 LinuxSIGTERM信号的退出码。根本原因在于yarn.nodemanager.resource.memory-mb设置过大,而物理内存不足。解决方案是调低该值,并同步调整yarn.scheduler.maximum-allocation-mb。例如,将yarn.nodemanager.resource.memory-mb从2048改为1024,然后重启 YARN。
5.3 日志分析:读懂 Hadoop 的“诊断书”
Hadoop 的日志是解决问题的终极武器,但新手常被海量日志淹没。记住三个黄金法则:
- 看最新日志:
tail -100f $HADOOP_HOME/logs/hadoop-hadoop-namenode-master.log,实时追踪。 - 找 ERROR 和 WARN:
grep -i "error\|warn" $HADOOP_HOME/logs/hadoop-hadoop-namenode-master.log \| tail -20。 - 顺藤摸瓜:日志中出现
Caused by:的行,是真正的根因。例如:
这行java.io.IOException: Failed on local exception: java.io.IOException: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]Caused by明确指出是 Kerberos 认证失败,而非 HDFS 配置问题。
实操心得:我习惯在
~/.bashrc中添加一个别名:alias hlog='tail -100f $HADOOP_HOME/logs/'。这样,hlog hadoop-hadoop-datanode-slave1.log就能快速打开 DataNode 日志,效率提升数倍。
5.4 版本不一致的“幽灵问题”:Kerberos 认证失败的深层逻辑
热搜词中提到“hadoop版本不一致导致kerberos认证问题”,这并非危言耸听。Hadoop 的 Kerberos 认证模块(hadoop-auth)在不同版本间存在细微差异。例如,Hadoop
