ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Hadoop 3.x伪分布式集群搭建:从环境配置到排错的全流程讲解

Hadoop 3.x伪分布式集群搭建:从环境配置到排错的全流程讲解 我见过太多人栽在Hadoop安装这道坎上。网上的教程一抓一大把但大多只告诉你“敲什么命令”不告诉你“为什么这么敲”。于是很多人照着一篇文章配完环境start-dfs.sh一执行报错一个接一个——NameNode起不来、DataNode闪退、端口被占、JAVA_HOME找不到……最后只能对着屏幕干瞪眼。这篇文章我打算换个讲法不只是给命令而是把Hadoop安装与搭建全流程从头到尾拆开揉碎把每个关键节点的原理讲透。不管你是刚接触大数据的初学者还是被环境折腾到怀疑人生的老倒霉蛋跟着这篇保姆级教程走一遍应该能把伪分布式集群稳稳跑起来。我会以Hadoop 3.x为例因为这是当前最主流、资料也最好找的版本。1. 安装前先想清楚你究竟需要哪种Hadoop很多人下载完压缩包就急着解压其实这是最容易埋雷的地方。Hadoop有三种部署模式不同模式对应不同的配置文件、启动方式和资源需求选错了后面全是坑。1.1 三种部署模式的区别本地模式Local Mode不需要启动任何守护进程Hadoop直接用本机文件系统跑MapReduce适合快速跑通官方示例、验证业务逻辑但看不到完整的HDFS和YARN体系。伪分布式模式Pseudo-Distributed Mode是单台机器上模拟集群NameNode、DataNode、ResourceManager、NodeManager都以独立Java进程跑在同一台机器上。HDFS和YARN完全可用能完整体验“分布式”的启动、存储、调度全流程学习阶段性价比最高。完全分布式模式Fully-Distributed Mode至少需要3台机器是生产环境的标配形态但这涉及节点规划、网络配置、机架感知等复杂问题不适合第一次接触Hadoop的人上手。所以我给大多数学习者的建议很直接第一遍一定要从伪分布式搭起。用一台普通的8G内存虚拟机或者本地电脑就够先把整个链路跑通再考虑扩展到多节点。1.2 版本怎么选版本选型是个容易被忽略但影响深远的问题。现在市面上主流的有Apache社区版、CDH发行版、HDP发行版。我这里只推荐Apache社区版原因很简单学习资料最多、踩坑案例最全、升级路径最清晰。至于CDH和HDP它们解决的是企业级部署和运维问题对初学者反而是额外的复杂度。Apache Hadoop的版本号选择也有讲究。2.x系列已经明显过时很多默认端口、配置项和3.x完全不同网上教程如果混着用大概率会翻车。3.x我建议选3.3.x的稳定版本比如3.3.6或者3.3.4。不要一看到官网有最新版就冲刚发布的R.C版本Release Candidate可能存在未知问题教材和社区讨论还没跟上出了问题很难查到解决方案。下载渠道方面官网的下载页面默认会跳转到Apache镜像站国内用户建议直接用清华源或者华为云镜像下载速度会比国外源快很多。下载的时候记得确认下载的是二进制发行包通常是hadoop-x.y.z.tar.gz而不是源码包hadoop-x.y.z-src.tar.gz。2. JAVA环境准备Hadoop最容易被忽视的第一道坎Hadoop是基于JVM运行的JDK配不好后面所有步骤都白搭。但这一环节恰恰是很多教程一句话带过的地方实际操作中翻车率极高。2.1 JDK版本到底选哪个Hadoop 3.x官方文档写的支持范围是Java 8和Java 11但我在实际使用中强烈建议用Java 8也就是OpenJDK 1.8。原因很简单Hadoop生态里很多周边组件Hive、Spark、HBase等对Java 8的兼容性最稳定而且绝大多数踩坑帖和解决方案都基于Java 8环境。你用Java 11也不是不行但遇到诡异报错时网上可查的资料会少一大截。安装JDK不用非得去Oracle官网下载直接用系统包管理器装OpenJDK最省事。Ubuntu和Debian系的命令是sudo apt update sudo apt install openjdk-8-jdk -yCentOS和RHEL系是sudo yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel -y装完验证一下java -version javac -version两个命令都能正常输出版本号说明JDK装好了。2.2 JAVA_HOME配置最容易翻车的点JDK装完之后需要把JAVA_HOME写进系统环境变量。很多教程会告诉你编辑/etc/profile文件在末尾加上这几行export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export PATH$PATH:$JAVA_HOME/bin然后执行source /etc/profile让配置生效。这本身没错但这里藏着一个大坑Hadoop的启动脚本自己有一套环境变量加载机制它不会自动读取/etc/profile。如果只配置了系统环境变量启动Hadoop时报错JAVA_HOME is not set或者找不到Java命令的几率非常高。正确的做法是双保险不仅在/etc/profile里配还要在hadoop-env.sh里显式指定JAVA_HOME。这个文件在$HADOOP_HOME/etc/hadoop/目录下找到里面的一行注释配置# export JAVA_HOME去掉注释并改成本机的JDK路径export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64这个细节真的很重要。我见过不止一个学员/etc/profile配置得妥妥的java -version在终端里也正常但一执行start-dfs.sh就报Java环境错误最后定位下来就是hadoop-env.sh里的JAVA_HOME没设置。检查JAVA_HOME路径可以用这个命令能精准输出JDK安装位置which java dirname $(dirname $(readlink -f $(which java)))第二个命令在Ubuntu上通常能直接给出类似/usr/lib/jvm/java-8-openjdk-amd64的完整路径。拿不准的时候用它不要凭感觉写。3. SSH免密登录伪分布式集群的“地基”你可能觉得奇怪我就一台机器为什么要配SSH免密这就是很多人对Hadoop伪分布式理解不到位的地方——虽然是一台物理机器但Hadoop在逻辑上仍然把它当作“一个主节点加多个从节点”的集群来管理。主节点启动从节点上的守护进程时是通过SSH远程连接的方式去执行的。3.1 为什么伪分布式也需要SSH免密启动HDFS时NameNode节点会通过SSH连接到workers文件里列出的所有主机名伪分布式情况下就是localhost远程拉起DataNode进程。如果不配置SSH免密每次启动都会提示你输入密码而且是在脚本执行过程中弹的提示输入密码慢了、输错了整个启动过程就卡住或者失败。生产环境集群规模大更不可能手动输密码。所以SSH免密的本质是让主节点能“无感知”地访问从节点这是Hadoop集群能自动拉起所有进程的基础。3.2 密钥生成与本地授权配置过程其实不复杂分两步。第一步生成密钥对第二步把公钥加入授权列表。首先生成密钥一路回车即可ssh-keygen -t rsa生成完成后密钥默认存放在~/.ssh/目录下id_rsa是私钥id_rsa.pub是公钥。然后把公钥内容追加到~/.ssh/authorized_keys文件里cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys如果有多台机器需要互相免密只需要把目标机器的公钥追加到对方的authorized_keys里。但本文聚焦伪分布式单机搞定这两步就够了。3.3 验证与权限雷区配置完成后验证一下执行ssh localhost如果不需要输入密码直接进入说明配置成功。这里有一个必须提醒的权限问题.ssh目录的权限不能太开放否则SSH会出于安全策略拒绝读取authorized_keys。具体权限要求是chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys很多时候免密配置明明没错但ssh localhost还是要输密码十有八九就是权限设置不到位。检查完权限再测试一次通常就能解决。如果是在CentOS或者带SELinux的系统上还可能遇到SELinux拦截SSH读文件的情况遇上了可以用ausearch -m avc -ts recent查一下拦截日志或者临时把SELinux切到permissive模式验证是不是它的锅。这个不算高频问题但排查时心里要有这根弦。4. 核心配置文件逐行拆解读懂比照抄重要一万倍环境就绪后进入真正的核心环节——配置Hadoop。配置文件全部在$HADOOP_HOME/etc/hadoop/目录下伪分布式需要修改的其实只有几个XML文件和hadoop-env.sh。我建议你不要直接照抄网上的模板而是跟着下面的逻辑亲手改一遍。4.1 core-site.xml设置HDFS入口这个文件主要配置Hadoop核心参数最关键的当属fs.defaultFS它决定客户端通过哪个地址访问HDFS。默认是本地文件系统要改成HDFS的访问入口configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property /configuration端口9000是NameNode RPC通信的默认端口除非被占用否则不需要改。理解fs.defaultFS的价值在于以后你执行hdfs dfs -ls /这样的命令时Hadoop客户端就是通过这个配置找到NameNode的。如果这个值配错客户端会报java.net.ConnectException不知道去哪里找集群。有些教程还会顺手加hadoop.tmp.dir这个属性用来配置存储临时数据的根目录。这个参数非常关键我建议你把默认路径改掉原因见第6章的排坑内容。配置如下property namehadoop.tmp.dir/name value/data/hadoop/tmp/value /property注意这个目录需要在系统中预先创建并给足写权限比如执行sudo mkdir -p /data/hadoop/tmp sudo chown -R $USER:$USER /data/hadoop。不改这个参数默认会用/tmp/hadoop-${user.name}这在Linux纯属定时炸弹——系统重启会清理/tmp目录你的元数据就丢了。4.2 hdfs-site.xml决定数据块的行为这个文件控制HDFS自身的行为。伪分布式必须改的一个参数是副本数dfs.replication默认值是3意思是每个数据块存三份。伪分布式环境下只有一台DataNode三份副本根本放不下启动时会一直报块副本不足的告警。改成1property namedfs.replication/name value1/value /property有人可能会问生产环境的3副本和这里的1副本到底差在哪3副本是为了容错数据块同时存在不同机器上一台机器挂了数据不会丢。伪分布式只有一台机器即使设了3副本物理上也只有一份存储所以设1副本不仅够用还避免大量告警噪音。另一个可选但推荐配置的是NameNode和DataNode的数据存放路径。之前core-site.xml里设置了hadoop.tmp.dirNameNode的元数据和DataNode的数据块默认会放在这个目录的子目录里但有些版本还是需要显式指定更保险property namedfs.namenode.name.dir/name value/data/hadoop/namenode/value /property property namedfs.datanode.data.dir/name value/data/hadoop/datanode/value /property这两个目录在格式化NameNode之前必须不存在或者为空否则会出clusterID冲突问题。这个坑在第5章的启动环节会具体讲这里先记着。4.3 mapred-site.xml与yarn-site.xml打通计算与调度Hadoop 3.x的伪分布式模式MapReduce框架要显式指定由YARN来调度。先改mapred-site.xmlproperty namemapreduce.framework.name/name valueyarn/value /property然后是yarn-site.xml重点配置NodeManager的辅助服务。MapReduce任务在执行过程中需要Shuffle把Map端输出拉取到Reduce端这个过程的辅助服务必须显式声明property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property新版YARN如果开启容器化执行还要配yarn.nodemanager.env-whitelist之类的参数这些属于进阶内容伪分布式学习阶段不需要管。4.4 workers文件告诉主节点从节点是谁Hadoop 3.x把原来2.x里的slaves文件改名为workers用于定义集群中有哪些从节点。伪分布式下只需要写入localhost如果这个文件配置错了启动HDFS时主节点不知道该去连哪些机器DataNode和NodeManager就不会被拉起。有些教程还停留在2.x时代让你改slaves文件注意3.x里这个文件已经失效改了没用。4.5 Java路径再强调一次hadoop-env.sh里的JAVA_HOME在第2章已经改过这里不重复。但我要多提醒一句每次Hadoop升级或者换JDK版本后这个文件都需要重新检查因为它保存的是绝对路径不会跟随系统环境变量自动变化。5. 启动流程与首次验证如何确认集群真的“活”了配置写完终于到了启动环节。这一步很多人容易急着敲命令但启动顺序和验证逻辑是有门道的。5.1 格式化NameNode只能成功一次的操作第一次启动HDFS之前必须格式化NameNode。格式化的作用是初始化文件系统的元数据存储空间生成最初始的FSImage。执行命令hdfs namenode -format看到日志输出Storage directory /data/hadoop/namenode has been successfully formatted说明格式化完成。这里一定要记住正常使用过程中格式化只能执行一次。为什么不建议格式化第二次因为格式化会生成新的clusterID和namespaceID而DataNode那边已经记录了一开始分配给他的clusterID。如果你再次格式化NameNode会导致NameNode和DataNode的clusterID不一致DataNode启动时会觉得“这不是我的集群”而拒绝注册表现为DataNode进程反复启动又反复退出。如果实在碰到了需要重新格式化的场景正确做法是停止所有Hadoop进程手动删除dfs.namenode.name.dir和dfs.datanode.data.dir目录下的全部内容然后重新格式化。删除旧数据这一步绝对不能省否则格式化完照样报clusterID冲突。5.2 启动HDFS和YARN格式化成功后先启动HDFS再启动YARN顺序不要反start-dfs.sh start-yarn.sh如果想一次性启动全部组件也可以直接用start-all.sh但这个脚本在3.x里已经不建议使用了我建议还是分步启动。分步启动还有一个好处如果某一步出错你能更快定位是哪块的问题。启动过程中你会看到日志提示连接localhost、启动NameNode、DataNode、SecondaryNameNode等全部显示为starting且没有明显ERROR基本上就成功了一大半。停止集群的时候顺序相反先停YARN再停HDFSstop-yarn.sh stop-dfs.sh5.3 双通道验证jps和Web UI启动完成后不要急着高兴一定要验证。第一个验证手段是jps命令这是JDK自带的一个工具能列出当前用户启动的Java进程。正常的伪分布式集群应该有5个进程NameNode DataNode SecondaryNameNode ResourceManager NodeManager这5个进程缺一不可。少了DataNode大概率是clusterID冲突或者数据目录权限问题少了ResourceManager多半是yarn-site.xml配置有问题主进程根本没起来则回头检查JAVA_HOME和格式化日志。第二个验证手段是Web UI。Hadoop 3.x的NameNode Web界面地址变成了http://localhost:9870和2.x时代的50070完全不一样别找错端口。YARN的资源管理页面在http://localhost:8088。两个页面能正常打开说明HDFS和YARN的Web服务都在为你服务了。5.4 用WordCount跑通全链路光看进程和页面还不够我还建议你跑一个真实的MapReduce任务这是验证“计算存储”全链路的最佳方式。Hadoop发行包自带了一系列示例Jar包可以直接拿来跑。在$HADOOP_HOME/share/hadoop/mapreduce/目录下找到hadoop-mapreduce-examples-*.jar。先在HDFS上创建测试目录然后上传一个本地文件hdfs dfs -mkdir -p /wordcount/input echo hello hadoop hello world /tmp/test.txt hdfs dfs -put /tmp/test.txt /wordcount/input/接着提交WordCount任务hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /wordcount/input /wordcount/output任务执行期间可以看到Map阶段和Reduce阶段的进度条。完成后查看结果hdfs dfs -cat /wordcount/output/part-r-00000能输出各单词的出现次数说明你的Hadoop安装、配置、启动、调度全链路完全正常。这一步跑通后整台机器的Hadoop环境才算是真正“活”了。6. 新手最容易踩的坑清单与完整排查思路即便按上面流程走也难免遇到各种意外。下面这些坑是我自己踩过、以及帮别人排查过程中反复遇到的每个都给出完整的排查链路不是直接甩结论。6.1 NameNode一直起不来从日志里找真凶NameNode是HDFS的大脑它起不来整个文件系统就瘫痪。遇到这种情况第一步永远不是改配置而是看日志。Hadoop的日志默认在$HADOOP_HOME/logs/目录下NameNode对应的日志文件是hadoop-user-namenode-hostname.log。用tail -50查看末尾的报错信息常见的几种报java.io.IOException: NameNode is not formatted说明你忘了执行格式化或者格式化后改了数据目录路径。回到第5.1节重新检查。报Address already in use端口9000被其他程序占用。用netstat -tlnp | grep 9000看看是谁占的如果是有残留Hadoop进程杀掉再启动。报文件系统目录不存在或无权访问对应的dfs.namenode.name.dir路径有问题确认目录已创建且当前用户有写权限。日志文件是排障的第一现场比你在网上盲搜报错靠谱一万倍。6.2 DataNode闪退九成是clusterID冲突伪分布式最常见的问题之一就是DataNode启动后马上就退出了。排查方法是看DataNode日志cat $HADOOP_HOME/logs/hadoop-user-datanode-hostname.log如果日志里出现Incompatible clusterIDs妥妥就是clusterID冲突了原因大概率是格式化NameNode格式化了两次以上或者不同步地清除了数据目录。解决方法按严格顺序执行停止所有Hadoop进程stop-all.sh删除NameNode和DataNode的整个数据目录rm -rf /data/hadoop/namenode /data/hadoop/datanode重新格式化NameNodehdfs namenode -format重启HDFS和YARN注意第2步必须把两个目录都删干净只删一个还会冲突。6.3 磁盘分区莫名其妙的满了伪分布式默认会把一些中间结果、临时文件写到/tmp下。如果你没有按第4.1节修改hadoop.tmp.dir运行多次MapReduce任务后/tmp目录很可能被塞爆导致任务提交失败或者节点健康检查报错。排查时用df -h du -sh /tmp/*如果发现/tmp/hadoop-*目录占了好几个G别犹豫停掉集群后把它删了然后按第4章的配置把hadoop.tmp.dir改到数据盘。这也是我为什么一开始就强调把这个参数改掉——很多教程不写这个改法但实际使用中太容易踩了。6.4 Web UI在浏览器里打不开进程都在、jps也没问题但浏览器访问http://localhost:9870就是不通。先别急着怀疑Hadoop配置从这几步排查在服务器本机执行curl http://localhost:9870如果通说明Hadoop没问题问题在防火墙或者网络层面。如果虚拟机用的NAT模式宿主机访问虚拟机的服务需要配置端口转发。检查防火墙sudo ufw statusUbuntu或sudo firewall-cmd --list-allCentOS确认9870和8088端口放行。还有一种隐蔽情况某些云服务器的安全组默认只开放少数端口需要去控制台放行。6.5 从“跟着走”到“自己会排错”最后我想说一点和学习方法有关的体会。安装Hadoop这件事最大的价值不是让你成功跑起一个伪分布式集群而是逼你去理解分布式系统的基本组件是怎么协作的。NameNode管元数据、DataNode管数据块、ResourceManager管资源分配、NodeManager管单机任务执行——这套模型搞懂了以后学Hive、Spark、Flink很多概念都是相通的。所以在排错的时候我强烈建议你自己多走几步别报错就截图问别人。先看日志日志是最诚实的朋友再理清组件的角色关系DataNode起不来就去找DataNode自己的日志ResourceManager挂了就去看YARN的日志最后再想配置哪里和默认值不一样。这套思路在伪分布式和未来完全分布式里完全通用。如果你是从零开始我建议先在虚拟机里完整过一遍上面的流程再用Docker试一次最后再考虑扩展多节点。每换一种部署方式你对Hadoop这套生态的理解都会深一层。等哪一天你看着几十行报错日志能在几分钟内定位出问题出现在哪一层那你这个集群才算真建明白。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进