☰
Hadoop 3.1.0安装实战:从配置避坑到WordCount跑通
2026/10/27 5:26:29 网站建设 项目流程

折腾 Hadoop 3.1.0 安装这件事,我前后做过不下十遍,从最早的虚拟机三节点到后来的物理机小集群,每次都会冒出几个新问题。这套东西放到今天看,组件版本不算新,可它在很多离线数据处理的教学场景、日志归档链路、以及一些内部批处理任务里依然在被使用,尤其是那些跑在老硬件上、又不方便整体升级的存量环境。Hadoop 3.1.0 安装的难点从来不在“敲几条命令”,而在于四个 XML 文件里的十几项配置彼此咬合,一处写错,表现出来可能是一个进程起不来,也可能是一个任务卡在 ACCEPTED 状态半小时不动。这篇内容面向的是手上有一到三台机器、想从零搭出一套能跑通 WordCount 的分布式环境的人,无论你是刚接触大数据组件的学生,还是被临时派活要把一套测试环境支起来的工程师,下面的步骤和坑都能直接拿去用。我会把每个配置为什么这么写讲清楚,参数怎么算讲清楚,出错时先看哪里也讲清楚。

1. 动手前先想清楚:集群形态与版本选型

1.1 为什么锁定 3.1.0 这个版本

先说我为什么不去追更新的版本。Hadoop 3.x 这条线上,3.1.0 是相当早期的一个正式发布版,它把 2.x 时代很多攒着的改动一次性落地了:默认端口从 50070 换成了 9870,slaves文件改名成workers,shell 启动脚本被整体重写,NameNode 支持多目录与联邦的配置方式也做了调整。这些改动对新手不太友好,因为你在网上找到的大量 2.x 时代的配置片段放到 3.1.0 上会直接失效,比如还写着dfs.http.address的参数名,在新版本里已经不认了。

那为什么还要用它?一个很现实的原因是生态兼容性。不少老版本的 Hive、Spark 预编译包在打包时针对的就是 3.1.x 这条线,你换到更新的 3.x 小版本,理论上兼容,实际跑起来偶尔会遇到依赖冲突,排查成本比直接锁定一个已知能用的版本高得多。另一个原因是硬件门槛,3.1.0 对 JDK 的要求就是 JDK 8,不需要额外配置模块化参数,几台 8G 内存的老机器就能撑起来,而新版对内存和 JDK 版本的要求会更高一些。

所以这里的取舍逻辑很简单:如果目标是“搭一套能跑通、能演示、能验证业务逻辑”的环境,锁定一个生态验证过的版本比追新更划算。我在实际项目里见过因为追求最新版本,结果卡在某个依赖的 Protobuf 版本冲突上耗掉两天的案例,最后退回 3.1.0 半小时就跑通了。

注意:3.1.0 是早期版本,它的一些默认值在后续小版本里被改过。你从别处抄配置时,一定先确认那段配置是哪个小版本的,参数名对不对得上。

1.2 伪分布式、完全分布式、高可用怎么挑

部署形态的选择直接决定了后面要写多少配置文件。我把三种形态的实际差别列出来,你对着自己的机器数量挑就行。

形态机器数量需要动的配置文件启动的进程适用场景
单机伪分布式1 台4 个 XML + 1 个 envNameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager学习 API、验证配置写法、跑通流程
完全分布式3 台起4 个 XML + 1 个 env + workers分散在三台机器上演示真实的数据分片、副本、任务调度
高可用集群5 台起上述基础上再加 HA 与 QJM 配置双 NameNode、JournalNode、ZKFC生产环境、需要容忍单点故障

绝大多数人的第一次安装都会从伪分布式起步,这个选择没问题,但有个认知要先建立起来:伪分布式能验证配置文件语法是否正确,验证不了网络、免密、分发这些真正容易出问题的环节。我建议的路径是先在一台机器上把伪分布式跑通,确认四个 XML 没写错,然后把同样的配置分发到三台机器上改成完全分布式。这样出问题的时候你能快速判断是配置本身的问题,还是多机通信的问题。

三台机器的角色分配,我习惯这样切:第一台同时放 NameNode 和 ResourceManager,第二、三台放 DataNode 和 NodeManager,SecondaryNameNode 单独放到第三台,避免它和 NameNode 抢同一块磁盘的 IO。机器配置如果没有特殊要求,8G 内存 4 核是最低舒适线,2G 内存的机器跑起来会非常吃力,光三个 JVM 就把内存吃满了。

1.3 资源与端口的账要提前算

很多人装到一半卡住,是因为端口被占了或者内存不够。这两笔账在动手前算清楚,能省掉大量排查时间。

端口方面,3.1.0 的默认端口和 2.x 差别很大,我把关键几个列出来:

服务默认端口说明
NameNode RPC8020客户端读写 HDFS 走的端口
NameNode Web UI98702.x 时代是 50070,别记混
SecondaryNameNode Web98682.x 是 50090
DataNode 数据与 Web9864 起多节点会自动往后顺延
ResourceManager Web8088任务进度页面入口
NodeManager Web8042单节点资源与容器信息
JobHistoryServer19888需要单独启动
MapReduce Shuffle13562NodeManager 内部使用

动手前先在每台机器上执行一遍端口占用检查,尤其要留意 8020 和 8088,这两个被别的服务占用的概率最高。如果你之前的机器上装过别的东西,或者有容器平台在跑,很可能已经占掉了。

内存方面要算的是给 YARN 留多少。一台 8G 内存的机器,操作系统本身要吃掉 1G 到 1.5G,NameNode 或 DataNode 的 JVM 大概占 1G 到 1.5G,留 1G 的缓冲,剩下的才是 YARN 能用的。这个数字要写进yarn.nodemanager.resource.memory-mb,后面第 3 章我会给出具体算法。

磁盘这块提醒一句:hadoop.tmp.dir的默认值在/tmp下面,很多系统的/tmp是 tmpfs,也就是挂在内存上的,机器一重启数据全没了,而且会默默吃掉你的内存。这个目录必须改到真实的磁盘路径上,这是新手最常踩的坑之一。

2. 系统底座的准备:别把坑留到后面

2.1 JDK 与 SSH 免密这两件事

JDK 版本这块,3.1.0 用 JDK 8 是最稳的,JDK 11 也能跑但要额外加一串--add-opens参数,没必要给自己找麻烦。安装方式我倾向于用包管理器装好,然后手动配JAVA_HOME,不要依赖系统自带的java命令指向哪个版本,因为你可能在机器上装了好几个 JDK。装完之后执行一次版本确认,把输出记下来。

JAVA_HOME的写法有个细节:在hadoop-env.sh里配置时,早期版本很多教程写的是export JAVA_HOME=$(readlink -f $(which java) | sed 's:/bin/java::')这种动态推导,看起来聪明,实际上如果你的 PATH 里有多个 java,推导出来的可能是错的。更稳的做法是直接写死绝对路径,比如/opt/module/jdk1.8.0_xxx,同时把PATH里也加上。

SSH 免密是另一个必做项。完全分布式下,启动脚本靠 SSH 到各台机器上拉起进程,没有免密就会卡在输密码上。生成密钥对之后,要把公钥追加到本机和另外两台机器的authorized_keys里。这里有个容易被忽略的点:第一次 SSH 到某台机器时会问yes/no,如果你在脚本里跑,这个交互会直接让脚本挂住。解决办法是提前手动 SSH 一遍,或者把目标机器加进known_hosts。我习惯的做法是先把三台机器互相 SSH 一遍,全部确认免密通了再往下走。

还有个小坑值得提:authorized_keys的权限必须是 600,.ssh目录必须是 700,权限过宽 SSH 服务会拒绝使用这个密钥,而且报错信息很含糊,只说认证失败。如果你明明公钥追加进去了却还是要密码,先去看这两个权限。

2.2 主机名、hosts 与防火墙的处理顺序

主机名这块,我建议用有意义的名字,比如 master、worker01、worker02,不要用默认的 localhost 或者一串随机串。改主机名之后必须同步改/etc/hosts,把三台机器的 IP 和主机名对应关系写进去。这一步看着简单,但它导致的故障特别隐蔽:配置里写的是master:8020,如果 hosts 没配好,客户端解析不到,报出来的错是UnknownHostException或者连接超时,你可能会误以为是 NameNode 没起来。

防火墙的处理顺序我建议是这样:先在关闭防火墙的状态下把整个集群跑通,确认所有功能正常,再回头按需开放端口。反过来做的话,你会在“到底是配置错了还是端口被拦了”这两个可能性之间反复横跳。关闭之后记得把状态确认一遍,有些系统上有两套防火墙管理工具,关了一个另一个还在跑。

SELinux 也是同理,先设成 permissive 模式,跑通之后再考虑要不要开。它拦截的时候不会明确告诉你是它拦的,只会表现为连接被拒绝。

另外提醒一句关于主机名解析的细节:/etc/hosts里127.0.0.1那一行如果同时写了主机名,某些情况下 NameNode 会绑定到回环地址上,导致其他机器连不上。稳妥的写法是127.0.0.1 localhost单独一行,真实 IP 和主机名另起一行。这个细节我吃过亏,明明是分布式部署,结果只有本机能访问。

2.3 时间同步、文件句柄数与透明大页

这三项在教程里经常被跳过,但它们是那种“不出问题则已,一出问题极难定位”的类型。

时间同步这件事,集群里各节点时间差超过几十秒,会出现什么现象?任务提交上去一直处于 ACCEPTED 状态不动,日志里看不出明显错误,只有 ResourceManager 的日志里偶尔会有关于认证时间戳的警告。原因是各节点之间的通信带有时间戳校验。解决方式很简单,装个时间同步服务,让所有机器指向同一个时间源,然后用timedatectl确认同步状态。虚拟机环境还有个额外坑:挂起恢复之后时间会漂移,长期不开机的测试环境尤其要注意。

文件句柄数默认通常是 1024,跑起来之后 DataNode 打开的文件数很容易超,超了之后会报Too many open files。修改方式是在 limits 配置里把软硬限制都提到 65535,然后重新登录使配置生效。注意这个配置对已经登录的会话不生效,改完必须重新开一个会话。

透明大页这个选项,在部分内核上开启会导致 JVM 的 GC 停顿时间变长,表现出来就是 NameNode 偶尔卡顿几秒。检查方式是看/sys/kernel/mm/transparent_hugepage/enabled的状态,如果显示always,建议改成never。这一项对测试环境影响不大,但如果你的机器上还跑着别的服务,值得顺手改掉。

3. 四个 XML 配置文件逐项拆解

3.1 core-site.xml:整个集群的地基

这个文件只配几项,但每一项都是全局性的,写错了后面全盘皆输。核心是三项:默认文件系统地址、临时目录、以及 HTTP 静态用户。

<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://master:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/module/hadoop-3.1.0/data/tmp</value> </property> <property> <name>hadoop.http.staticuser.user</name> <value>hadoop</value> </property> </configuration>

fs.defaultFS这里必须写主机名而不是 IP,写 IP 也能跑,但换机器或者 IP 变动之后要改配置,写主机名的话只改 hosts 就行。端口用 8020,这是 3.x 的默认值,如果你在别处看到 9000,那是 2.x 时代的写法,虽然改回 9000 也能用,但没必要跟默认值对着干。

hadoop.tmp.dir是整个集群的临时目录基座,NameNode 的元数据、DataNode 的数据块、各种运行时产生的临时文件默认都会落在它下面。所以这个路径必须有足够空间,而且必须是真实磁盘。我一般的做法是单独挂一块盘,路径写成/data/hadoop/tmp这种一眼能看懂的。

hadoop.http.staticuser.user这项配的是 Web UI 浏览文件时使用的用户名,不配的话默认是 dr.who,你从 9870 端口点进去看文件目录会遇到权限问题。配成你实际使用的用户名就行。

提示:这个文件在 3.1.0 里还支持fs.defaultFS配多个地址做联邦,但单集群场景不要碰这个,配错了会非常难排查。

3.2 hdfs-site.xml:副本、目录与 SecondaryNameNode

这个文件决定数据怎么存。核心是副本数、两个数据目录、以及 SecondaryNameNode 的地址。

<configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/opt/module/hadoop-3.1.0/data/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/opt/module/hadoop-3.1.0/data/data</value> </property> <property> <name>dfs.namenode.secondary.http-address</name> <value>worker02:9868</value> </property> </configuration>

dfs.replication这项,伪分布式下必须改成 1,否则你上传一个文件会一直有警告说副本数不足,因为只有一个 DataNode 凑不齐三个副本。完全分布式三台机器的话,3 是合理值。这里有个判断逻辑:这个数字设得比实际 DataNode 数量大,HDFS 不会报错,只是会一直处于“复制中”的状态,日志里刷副本不足的警告。

dfs.namenode.name.dir和dfs.datanode.data.dir我强烈建议和hadoop.tmp.dir分开写,不要都塞在 tmp 下面。原因很实际:格式化 NameNode 的时候,如果数据和元数据在同一个目录树里,你删目录重来的时候容易误删不该删的东西,分开写职责清晰。另外这两个目录都支持配多个路径用逗号分隔,配多个的话 NameNode 会把元数据同时写到每个目录,相当于做了份冗余,这是一个低成本的保护措施。

dfs.namenode.secondary.http-address配的是 SecondaryNameNode 的位置。要澄清一个常见误解:它不叫“备用 NameNode”,它做的是定期合并 Edits 日志和 FsImage,减轻 NameNode 启动时的压力。它不能接替 NameNode 工作,真正的故障切换要靠 HA 架构。伪分布式下它和 NameNode 在同一台机器上,完全分布式下建议放到不同的机器上。

3.3 yarn-site.xml 与 mapred-site.xml:让任务真的跑起来

这两个文件是一对,yarn 决定资源怎么分,mapred 决定 MapReduce 任务怎么接入 YARN。

<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>master</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>4096</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> </property> <property> <name>yarn.nodemanager.resource.cpu-vcores</name> <value>6</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property> <property> <name>yarn.nodemanager.env-whitelist</name> <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value> </property> </configuration>

yarn.nodemanager.aux-services这项写死mapreduce_shuffle,少这一项 MapReduce 任务能提交但会卡在 shuffle 阶段失败,报错信息很难懂。

内存参数怎么算,我给一个具体的推导过程。假设一台机器 8G 物理内存:操作系统和基础服务占 1.5G;DataNode 或 NameNode 的 JVM 占 1G;再留 1.5G 作为缓冲,防止突发占用把机器压垮。剩下 4G,写成 4096。这就是yarn.nodemanager.resource.memory-mb的来源。

然后在 4096 之内,单个容器最大给多少?这个值不能等于总量,因为同时要跑 ApplicationMaster 和实际任务,至少得能容纳两个容器。我一般设为总量的一半,也就是 2048。设成等于总量的话,会出现一个任务占满所有资源,其他任务全排队的情况。

vmem-check-enabled这项我建议关掉。YARN 默认会检查虚拟内存,而 JVM 启动时会预留大量虚拟地址空间,实际物理内存用得很少,很容易被误判超限然后容器被杀,报一个Container killed on request. Exit code is 137。这个现象特别迷惑人,因为你的任务内存明明没超。测试环境下直接关掉,生产环境要配合调整虚拟内存比例。

env-whitelist这项是 3.x 的新增项,作用是允许哪些环境变量从 NodeManager 传递到容器里。如果你不配,MapReduce 任务容器里可能拿不到HADOOP_MAPRED_HOME,报找不到 MapReduce 的类。这个坑很隐蔽,因为 AM 容器能起来,真正的 Map 任务起不来。

mapred-site.xml 配套写:

<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>yarn.app.mapreduce.am.env</name> <value>HADOOP_MAPRED_HOME=/opt/module/hadoop-3.1.0</value> </property> <property> <name>mapreduce.map.env</name> <value>HADOOP_MAPRED_HOME=/opt/module/hadoop-3.1.0</value> </property> <property> <name>mapreduce.reduce.env</name> <value>HADOOP_MAPRED_HOME=/opt/module/hadoop-3.1.0</value> </property> </configuration>

后面三项是 3.x 必须显式声明的,不写的话容器里找不到 MapReduce 的 jar 包路径。路径要写你实际的 Hadoop 根目录,别照抄。

3.4 hadoop-env.sh 与 workers:最容易被忽略的两处

hadoop-env.sh里至少要改两处:JAVA_HOME和几个用户变量。用户变量这块是 3.x 相比 2.x 最大的变化,也是新手最常卡住的地方。

export JAVA_HOME=/opt/module/jdk1.8.0_xxx export HDFS_NAMENODE_USER=root export HDFS_DATANODE_USER=root export HDFS_SECONDARYNAMENODE_USER=root export YARN_RESOURCEMANAGER_USER=root export YARN_NODEMANAGER_USER=root

如果你用 root 用户跑,不配这几项,执行start-dfs.sh会报HDFS_DATANODE_USER is not defined之类的错误直接退出。原因是 3.x 重写了启动脚本,脚本里会用这些变量去决定用哪个用户身份启动进程。这不是权限问题,纯粹是变量没定义。

从安全角度讲,我不建议直接用 root 跑,建一个专用用户更规范。但测试环境里为了省事用 root 也不是不行,知道这个坑在哪就行。

workers文件(2.x 叫slaves)里写的是 DataNode 的主机名,一行一个:

worker01 worker02

这个文件决定了start-dfs.sh会 SSH 到哪些机器上拉起 DataNode 和 NodeManager。写错了会表现为只有一台机器起了 DataNode,其他机器没反应,而启动脚本本身不报错。判断方法是去 9870 端口看 DataNode 数量,跟你预期对不上就是这里的问题。

提示:这个文件里不要写 localhost,也不要写 127.0.0.1,要写和 hosts 里对应得上的主机名。

配置改完,用分发脚本同步到另外两台机器。同步之后随便挑一台机器,把四个 XML 和 env 文件各打开看一眼,确认内容一致。我见过因为只分发了一半,导致某台机器配置和其他不一样,集群表现诡异的案例。

4. 格式化、启动与验证的完整流程

4.1 第一次格式化 NameNode 之前必须确认的三件事

格式化这个动作,本质是初始化 NameNode 的元数据目录。它只应该做一次,做多了会出问题。执行前先确认三件事:

第一,dfs.namenode.name.dir指向的目录是空的,或者不存在。如果里面已经有上一次的元数据,格式化会覆盖掉,之前的文件就找不回来了。第二,hadoop.tmp.dir的路径已经建好且有写权限。第三,hadoop-env.sh里的 JAVA_HOME 没问题。第三项可以先用hadoop version命令验证一下,这个命令能把 Java 环境和 Hadoop 版本都打出来,能跑通说明基础环境没问题。

执行格式化的命令:

hdfs namenode -format

输出里重点看两行:一行是Storage directory ... has been successfully formatted,另一行是生成的clusterID,把它记下来,后面排查 DataNode 起不来的问题会用到。

4.2 启动脚本与进程核对

启动分两步,先 HDFS 再 YARN:

start-dfs.sh start-yarn.sh

在 master 上执行完之后,用jps命令在每台机器上核对进程。master 上应该有 NameNode 和 ResourceManager,worker 上应该有 DataNode 和 NodeManager。SecondaryNameNode 在你配置指定的那台机器上。数量对不上就是配置或分发出了问题。

进程核对完之后,浏览器打开http://master:9870,看两处:Overview 里的 Live Nodes 数量,以及 Utilities 里的 Browse the file system。前者确认 DataNode 都注册上了,后者确认 HDFS 能正常读写。再开http://master:8088看 ResourceManager 页面,确认集群资源总量跟你算的那个数字对得上。

如果 9870 打不开,先在本机用curl试一下,区分是服务没起还是网络不通。这个诊断顺序很重要,能省掉一半排查时间。

4.3 上传下载与 WordCount 验证

先建目录、传文件,验证 HDFS 的读写链路:

hdfs dfs -mkdir -p /input hdfs dfs -put /opt/data/words.txt /input hdfs dfs -ls /input hdfs dfs -cat /input/words.txt

这套命令跑通说明 HDFS 没问题。然后跑 WordCount 验证 YARN 和 MapReduce:

hadoop jar /opt/module/hadoop-3.1.0/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.0.jar wordcount /input /output

两个细节要注意:输出目录/output在跑之前必须不存在,存在的话任务会直接失败,报Output directory already exists。这不是 bug,是 MapReduce 的设计,防止覆盖已有结果。另外这个 jar 包的版本号要跟你装的版本对上,路径别写错。

任务跑起来之后,8088 页面上能看到应用状态从 ACCEPTED 变成 RUNNING 再变成 FINISHED。跑到 ACCEPTED 卡住不动,一般是资源不够或者调度器没配好。跑完用hdfs dfs -cat /output/part-r-00000看结果,能正常输出词频统计就说明整条链路通了。

5. 踩过的坑与排查实录

5.1 端口冲突与进程起不来

进程起不来的第一现场永远是日志,位置在$HADOOP_HOME/logs/下面,文件名带进程名和日期。我在实际排查里遇到最多的是端口冲突,报错形如BindException: Problem binding to master/192.168.x.x:8020。这种错误其实很友好,它明确告诉你端口被占了。

排查方式是用ss -lntp或者netstat -lntp看端口占用,找到进程之后决定是杀掉还是改配置。我倾向于改 Hadoop 的端口而不是杀别人的进程,因为那个进程可能是系统里其他在跑的服务,杀掉了会引发新的问题。

还有一种情况是端口没被占但起不来,报Cannot assign requested address。这个通常是主机名解析问题,配置里写的主机名解析到了一个机器上没有的 IP 上,导致服务绑不上。回到 hosts 文件检查一遍就行。

启动脚本跑完之后没有任何输出,进程也没有。这种情况一般是脚本没找到配置文件,或者 SSH 不通。先把启动脚本加-x跑一遍看执行到哪一步中断了。

5.2 DataNode 启动后秒退:clusterID 不一致

这个现象很有迷惑性:start-dfs.sh执行完,jps能看到 DataNode,过几秒钟再看就没了。日志里会有一句关键信息,大意是ClusterID和 NameNode 的对应不上。

触发原因几乎都是同一个:NameNode 被格式化了不止一次,但 DataNode 的数据目录没有清理。DataNode 启动时会读到旧的 clusterID,跟 NameNode 当前的对比不一致,于是自己退出保护数据。

处理方式有两种。第一种是把 DataNode 的数据目录整个删掉,重新启动让它自动注册,这种方式简单但会丢掉已有的块数据,测试环境无所谓。第二种是手动把 DataNode 目录下current/VERSION文件里的clusterID改成和 NameNode 一致,这种方式保留数据但要小心操作。我一般测试环境直接走第一种,生产环境的思路是第二种,但事先一定备份。

顺带说一句,格式化 NameNode 之前养成习惯先看一眼数据目录是不是空的,这个动作能杜绝八成的重复格式化问题。

5.3 容器被杀与内存相关的几个典型报错

内存相关的报错长得都差不多,但成因差别很大,我把见过的几类列在这:

第一类是Container killed on request. Exit code is 137,这个退出码表示进程被强制终止,最常见原因是物理内存超出容器限制,被系统 OOM Killer 干掉了。也可能是虚拟内存检查误判,这时候关掉vmem-check-enabled就能解决。怎么区分?看 NodeManager 日志里有没有Killing container以及前后文,如果提到 physical memory 就是真超了,提到 virtual memory 就是误判。

第二类是任务一直处于 ACCEPTED 状态。这个不是内存不够,而是队列里排不上。可能是yarn.nodemanager.resource.memory-mb设得太小,连一个 AM 容器都放不下;也可能是yarn.scheduler.maximum-allocation-mb设得比单个任务申请的内存还小,任务永远申请不到资源。

第三类是 Map 任务报找不到类,报错里带ClassNotFoundException。这时先检查mapreduce.map.env里配的HADOOP_MAPRED_HOME路径对不对,再检查env-whitelist里有没有放行相关变量。这两处都对了还报,就去看mapreduce.application.classpath是不是被某个配置覆盖掉了。

5.4 常见问题速查表

把上面这些整理成一张表,出问题时按现象查:

现象最可能原因排查入口处理方式
9870 打不开NameNode 没起来或端口被占logs/hadoop-*-namenode-*.log看 BindException,改端口或杀占用进程
DataNode 秒退clusterID 不一致DataNode 日志的 ClusterID 行清数据目录重启,或手工对齐 VERSION
上传文件报副本不足副本数大于 DataNode 数dfs.replication配置伪分布式改为 1
任务卡 ACCEPTED资源不足或最大容器内存太小8088 页面与 RM 日志调大 memory-mb 与 maximum-allocation-mb
容器 137 退出物理内存超限或虚拟内存误判NodeManager 日志调大容器内存或关闭 vmem 检查
启动脚本报 USER not defined3.x 用户变量未定义hadoop-env.sh补上五组 USER 变量
只有一台 DataNodeworkers 文件写错workers内容改成正确主机名并重新分发
任务找不到 MapReduce 类环境变量没传进容器mapred-site.xml补 am/map/reduce 三处 env 配置

再补一个经验性的提醒:hadoop.tmp.dir配在/tmp下导致的故障特别难查,因为它的表现是“重启之后集群状态莫名回到初始”,你会以为是配置被改了,实际上只是数据被系统清掉了。这个坑我建议直接在配置阶段就规避掉,别等到出问题再去想。

还有一个我在实际使用中养成的小习惯:每次改完配置重启集群,先用hdfs dfsadmin -report看一遍集群状态,确认容量、剩余空间、DataNode 数量都对,再提交任务。这个命令的输出很直观,比直接去跑任务再报错要高效得多。另外hdfs dfsadmin -safemode get可以查安全模式状态,集群刚启动时会短暂进入安全模式,这时候写操作会被拒绝,等它自动退出或者确认没有块在恢复之后手动-safemode leave退出就行。踩过几次坑之后我的判断标准很简单:凡是“配置明明对但就是不生效”的问题,先怀疑环境变量没加载,执行一次source /etc/profile或者重开会话,问题往往就消失了。

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

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

立即咨询