Hadoop完全分布式集群搭建实战:从原理到故障排查
先交代一个前提我写这篇东西不是让你照着敲一遍命令就完事而是希望你理解每一步到底在干什么。Hadoop完全分布式搭建这件事网上教程满天飞但很多人照着抄完还是起不来或者起来了一次、重启就挂了。原因基本都一样只知其然不知其所以然。所以我这篇会把重点放在“为什么要这么配”和“配错了会看到什么现象”上最后再给你一张可以直接照着干的配置清单。这套环境我前前后后搭过不下十次从两台机器到几十台节点的生产集群都碰过。下面这些内容是我觉得最适合入门、又能让你真正理解Hadoop运行机制的一条路径。1. 搭建前的核心认知完全分布式到底在解决什么问题1.1 从伪分布式到完全分布式差的不是数量而是架构很多初学者是从伪分布式Pseudo-Distributed入门的也就是在一台机器上同时跑NameNode、DataNode、ResourceManager、NodeManager。这种方式的好处是让你快速感知Hadoop的组件构成但代价是它掩盖了分布式系统最核心的复杂性——网络通信、节点间协调、故障隔离。完全分布式Fully Distributed集群指的是把不同角色部署到不同的物理或虚拟机器上。NameNode和ResourceManager作为主节点DataNode和NodeManager作为从节点它们之间通过RPC和HTTP协议通信。当你有3台以上的机器时才能真正模拟出一个生产环境的运行形态。我自己带人的经验是如果只玩过伪分布式就直接去面大数据岗位面试官一问“DataNode宕机了会发生什么”基本就露馅了。因为你没在真实的多节点环境里观察过这个过程。完全分布式的搭建本质上是让你亲手构建一个微缩版的数据中心哪怕只有三台机器也能完整走一遍“数据分块—副本放置—任务调度—容错恢复”的全流程。1.2 版本选型别一上来就追最新版Hadoop的版本选择是个老生常谈的话题但每次都有新人踩坑。目前主流的分支是Apache Hadoop 3.x系列但3.3.x和3.4.x之间也有差异。我的建议是学习阶段直接选Apache Hadoop 3.3.6或3.3.4这两个版本经过了大量生产验证网上的踩坑资料最多遇到问题基本都能搜到解决方案。不要选CDH或HDP这类商业发行版虽然它们封装得好但会隐藏太多底层细节不适合学习。也不要追最新的3.4.x因为一些生态组件比如Spark、Flink的某些版本对它的兼容性还有待验证。JDK版本方面Hadoop 3.x要求JDK 8或JDK 11。我推荐JDK 8具体是8u202或更高不是因为老而是因为Hadoop生态里大量组件对JDK 8的兼容性最稳。用JDK 11也可以但有些老项目的MapReduce程序会踩到模块化相关的坑对新手不友好。1.3 集群规划三台机器是最低配也是最佳学习配置最少需要几台机器才能叫“完全分布式”答案是3台。原因很简单HDFS默认副本数是3如果你只有2台DataNode那么第三个副本会全部堆在某一台机器上无法体现“机架感知”和“副本分散”的策略。3台节点刚好可以形成一个最小的、逻辑完整的集群。三台机器怎么分工我建议这样规划主机名IP角色node1192.168.10.101NameNode、ResourceManager、SecondaryNameNodenode2192.168.10.102DataNode、NodeManagernode3192.168.10.103DataNode、NodeManager为什么不把SecondaryNameNode放到node2或node3这块后面细说先记住一个原则主节点角色尽量不扎堆但学习环境资源有限时NameNode和ResourceManager挤在一起是能接受的妥协。硬件配置方面每台机器建议至少2核CPU、4GB内存、40GB磁盘。如果你是用虚拟机VMware或VirtualBox都行网络模式选“仅主机模式”或“NAT模式”都可以但三台机器要在同一个网段、能互通。这里有个小技巧虚拟机内存设成2GB也可以跑起来但NameNode和ResourceManager的堆内存要相应调小否则很容易OOM。2. 基础环境配置宁可慢一点也要一次做对2.1 节点通信与hosts映射这一步看似简单但至少三成的人在这里埋下了隐患。核心要求有两条一是三台机器的主机名不能相同二是hosts文件里必须把三个节点的主机名和IP的映射关系写全。以CentOS 7.9为例修改主机名的命令是hostnamectl set-hostname node1三台机器分别执行改成node1、node2、node3。然后编辑每台机器的/etc/hosts文件写入如下内容192.168.10.101 node1 192.168.10.102 node2 192.168.10.103 node3这里特别提醒要把hosts里自带的127.0.0.1那一行中跟主机名相关的部分处理干净。很多人在启动HDFS时看到java.net.UnknownHostException就是hosts文件里残留了旧的映射导致的。我个人习惯是直接把127.0.0.1行只保留为127.0.0.1 localhost不跟任何主机名绑定。2.2 JDK安装与JAVA_HOME配置JDK的安装方式有不少但我推荐用tar包手动解压的方式原因有两个一是版本可控二是能清楚知道JDK装在了哪里后面配置Hadoop时不会搞错路径。tar -zxvf jdk-8u202-linux-x64.tar.gz -C /opt/ mv /opt/jdk1.8.0_202 /opt/jdk8然后配置环境变量。这里要说明一下环境变量配置在/etc/profile里是所有用户生效配在~/.bashrc里是当前用户生效。如果你是用hadoop这个专用用户来跑集群强烈建议不要用root跑Hadoop那就配在该用户的~/.bashrc里export JAVA_HOME/opt/jdk8 export PATH$PATH:$JAVA_HOME/bin配置完执行source ~/.bashrc然后用java -version验证。这一步的重点是三台机器都要装JDK且版本必须一致路径最好也一致都放/opt/jdk8否则后面启动YARN时会遇到各种诡异问题。2.3 SSH免密登录不止是省事更是Hadoop的正常运行前提很多人以为SSH免密只是省得每次输密码这个理解不够。Hadoop的守护进程在启动时NameNode需要通过SSH连到各个DataNode去远程执行启动脚本。如果免密没配好启动过程要么卡住要么失败。配置方法分两步。第一步在node1上生成密钥对ssh-keygen -t rsa -P -f ~/.ssh/id_rsa第二步把公钥分发到三台机器包括node1自己ssh-copy-id node1 ssh-copy-id node2 ssh-copy-id node3为什么node1也要给自己做免密因为NameNode节点上也有DataNode进程吗不对node1不跑DataNode的话理论上不需要免密到node1。但SecondaryNameNode和ResourceManager都在node1上某些管理操作仍需本机回环连接所以建议node1自身也配置免密以防后续扩展时踩坑。验证方式很简单在node1上执行ssh node2和ssh node3能直接登录就是成功。2.4 时钟同步与防火墙处理这两个点经常被忽略但它们引发的故障极具迷惑性。时钟同步如果各节点时间差超过一定阈值Kerberos认证如果开了安全模式和一些RPC调用会直接失败。即使没开安全模式时间不一致也会导致日志时间线错乱排查问题极其痛苦。学习环境最简单的做法是用yum install -y ntpdate安装后让三台机器都执行ntpdate ntp.aliyun.com手动同步一次。如果你有更严格的需求可以搭NTP服务端做周期性同步但学习阶段手动同步就够了。防火墙很多教程上来就说“直接systemctl stop firewalld”这在学习环境没问题但你要明白你在做什么。关闭防火墙只是为了让集群通信不被打扰生产环境必须开防火墙并配置放行规则。Hadoop相关的端口包括但不限于8020HDFS RPC、9870NameNode Web UI、8088YARN Web UI、8042NodeManager、9000HDFS RPC可选。学习环境图省事就关掉firewalld和SELinuxsystemctl stop firewalld systemctl disable firewalld sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config setenforce 0改完SELinux建议重启机器因为setenforce 0是临时方案重启后如果没改配置文件会重新启用。3. Hadoop安装与配置文件逐项拆解3.1 下载解压与目录约定去Apache官网或镜像站下载hadoop-3.3.6.tar.gz传到node1上然后解压tar -zxvf hadoop-3.3.6.tar.gz -C /opt/ mv /opt/hadoop-3.3.6 /opt/hadoop目录约定这块说说我的习惯。Hadoop默认的配置在$HADOOP_HOME/etc/hadoop下运行时的临时数据默认在/tmp下。但是/tmp目录在系统重启时会被清理所以必须把数据目录指向一个持久化的路径。我通常会在/opt/hadoop下建这些目录/opt/hadoop/tmp存放HDFS的元数据和DataNode的数据块/opt/hadoop/pid存放守护进程的PID文件/opt/hadoop/logs存放运行日志配置环境变量时把HADOOP_HOME和HADOOP_PID_DIR都指过去。这里有个经验之谈不要用/root/hadoop这类路径也不要用带空格的路径否则后续配置会踩很多莫名其妙的坑。3.2 六个核心配置文件逐个说透Hadoop的配置虽然文件多但核心就六个。我把每个文件的关键项及含义写清楚这些都是你面试时能直接讲出“为什么”的东西。第一个是hadoop-env.sh。这个文件主要设置JAVA_HOME和HADOOP_HOME的环境变量。在Hadoop 3.x中你还需要关注HDFS和YARN的守护进程内存设置export JAVA_HOME/opt/jdk8 export HADOOP_HOME/opt/hadoop export HADOOP_PID_DIR/opt/hadoop/pid export HDFS_NAMENODE_USERroot export HDFS_DATANODE_USERroot export HDFS_SECONDARYNAMENODE_USERroot export YARN_RESOURCEMANAGER_USERroot export YARN_NODEMANAGER_USERroot最后四行是很多新手容易遗漏的。Hadoop 3.x默认启用了HDFS_NAMENODE_USER等用户检查如果你用root启动却不在这个文件里显式声明允许的账号就会报“Attempting to operate on hdfs namenode as root”错误。第二个是core-site.xml。这个文件配置的是集群级别的核心属性最重要的就是fs.defaultFSconfiguration property namefs.defaultFS/name valuehdfs://node1:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop/tmp/value /property property namehadoop.http.staticuser.user/name valueroot/value /property /configurationfs.defaultFS定义了NameNode的RPC通信地址客户端和DataNode都会通过这个地址联系NameNode。hadoop.tmp.dir是所有临时数据的根目录注意这个目录会被NameNode和DataNode共用但它们的实际存储路径还要看hdfs-site.xml中的具体配置。第三个是hdfs-site.xml。这个文件直接决定了HDFS的副本策略和主节点元数据存储位置configuration property namedfs.namenode.name.dir/name valuefile:///opt/hadoop/tmp/dfs/name/value /property property namedfs.datanode.data.dir/name valuefile:///opt/hadoop/tmp/dfs/data/value /property property namedfs.replication/name value3/value /property property namedfs.namenode.http-address/name valuenode1:9870/value /property property namedfs.permissions.enabled/name valuefalse/value /property /configurationdfs.replication设为3这是HDFS的默认副本数。因为我们刚好有2个DataNode这里要提个醒如果集群只有2个DataNode而副本数设为3数据写入时会提示“Not Enough Replicas”因为第三个副本确实没地方放。所以要么加节点要么把副本数临时调成2。不过我建议维持3因为这样能让你直观看到副本不足的报错理解副本机制的含义。dfs.permissions.enabled设为false是为了避免权限问题打断学习节奏。生产环境必须开启但学习阶段可以先关上有些教程不告诉你这个你拿着root上传文件都可能报Permission denied。第四个是mapred-site.xml。这个文件决定MapReduce运行在什么框架上configuration property namemapreduce.framework.name/name valueyarn/value /property property namemapreduce.application.classpath/name value$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*/value /property /configuration在Hadoop 3.x中如果mapreduce.application.classpath配得不全运行WordCount时会报“ClassNotFoundException: org.apache.hadoop.yarn.util.ConverterUtils”这个坑我见过无数人踩。第五个是yarn-site.xml。这个文件配置资源调度器相关参数configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property property nameyarn.resourcemanager.hostname/name valuenode1/value /property property nameyarn.nodemanager.env-whitelist/name valueJAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_HOME,PATH,LANG,TZ/value /property /configurationyarn.nodemanager.aux-services是关键中的关键。MapReduce任务运行时的Shuffle阶段需要通过这个辅助服务来传输Map输出数据。如果你漏配任务会在Reduce阶段卡在88%左右不动。第六个是workers文件在Hadoop 3.x中叫workers在2.x中叫slaves。这个文件列出所有DataNode和NodeManager的主机名node2 node3注意不要把node1写进去因为node1只跑NameNode和ResourceManager。如果你把node1也写进去它会变成一个既是主又是从的“四不像”虽然没有致命错误但不推荐。3.3 配置分发一键同步到所有节点配置文件在node1上改完后需要同步到node2和node3。最简单的方式是用scp命令scp -r /opt/hadoop node2:/opt/ scp -r /opt/hadoop node3:/opt/这里要注意同步的是整个hadoop安装目录因为里面包含了配置文件和依赖包。如果你的JDK路径在三台机器上一致就不需要额外同步JDK。如果JDK路径不同那就要去每台机器的hadoop-env.sh里单独修改JAVA_HOME。顺便再说一句环境变量也要同步。在node2和node3的~/.bashrc里添加和node1一样的Hadoop相关配置就行了。4. 初始化与启动最激动人心也最容易翻车的环节4.1 格式化NameNode一次性的操作别手滑执行两遍正式开始之前先执行一次NameNode的格式化。这个操作会在元数据目录中生成初始的fsimage文件同时会生成一个随机的clusterId。hdfs namenode -format看到输出中有一行“Storage directory ... has been successfully formatted”就是成功了。重点提醒这个命令只能执行一次。如果你在执行完、已经启动集群后因为某些故障又执行了一遍那么NameNode的clusterId会变化而DataNode里存的是旧的clusterId启动时DataNode会发现不匹配拒绝注册。现象是NameNode一直处于SafeModeDataNode的日志一直刷“Incompatible clusterIDs”。如果你真的不小心格式化了两次解决办法是把/opt/hadoop/tmp目录下所有节点包括DataNode的清空然后重新格式化。注意是所有节点的不是只清NameNode一台。4.2 启动HDFS和YARN先看进程再看日志格式化完成后在node1上执行start-dfs.sh start-yarn.sh启动成功后分别在每台机器上执行jps命令查看Java进程。正常情况下node1NameNode、SecondaryNameNode、ResourceManagernode2DataNode、NodeManagernode3DataNode、NodeManager新手最容易犯的错是只站在node1上执行jps然后觉得“怎么只有NameNode”。一定要去每台机器上看。如果某个进程没有启动先别急着重启先去日志目录看日志tail -100 /opt/hadoop/logs/hadoop-xxx-namenode-node1.log日志文件命名规则是hadoop-用户名-角色-主机名.log。看日志是排查问题的基本功这比在网上盲搜问题描述高效得多。4.3 Web UI验证用浏览器直观确认集群状态Hadoop启动后可以通过Web界面验证集群状态HDFS界面http://node1:9870这里能看到NameNode状态、DataNode列表、集群存储容量YARN界面http://node1:8088这里能看到ResourceManager的调度情况、已提交的应用程序列表如果你是在虚拟机里装的LinuxWindows宿主机访问不到那就先在Linux本机用curl http://node1:9870验证一下。我建议直接把hosts文件里的映射加到Windows的C:\Windows\System32\drivers\etc\hosts里这样直接浏览器输入node1:9870就能访问省去记IP的麻烦。4.4 跑通第一个测试用例WordCount不是孤例集群启动只是第一步跑通一个真正的MapReduce任务才算验证了整个链路。Hadoop自带的示例jar包就在/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar里。先创建测试目录并上传文件hdfs dfs -mkdir -p /test/input echo hello world hello hadoop | hdfs dfs -put - /test/input/test.txt然后提交WordCount任务hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /test/input /test/output执行完后查看结果hdfs dfs -cat /test/output/part-r-00000正常会输出hadoop 1 hello 2 world 1第一次能完整跑通这个流程你对Hadoop的认知会从“概念层面”落到“实操层面”。如果中途任务失败去YARN的Web UI找到失败的Application点进去查看日志这是定位问题的最快途径。5. 常见问题与排查技巧实录5.1 DataNode启动后立刻消失症状start-dfs.sh后node1的NameNode正常但node2和node3的DataNode一启动就退出。排查思路不要盯着终端输出看直接看日志tail -100 /opt/hadoop/logs/hadoop-root-datanode-node2.log最常见的原因是clusterId不一致也就是前面说的——你格式化操作执行了两次以上。解决方法是清空所有节点的/opt/hadoop/tmp目录然后只格式化一次再启动。另一个常见原因是dfs.datanode.data.dir指定的目录没有写权限或者目录的属主不是启动用户。比如用root启动但目录属主是hadoop用户也会报权限错误。5.2 ResourceManager能在node1启动但NodeManager连不上症状node2和node3的NodeManager一直显示“Unhealthy”或者连接被拒。排查思路先确认node2和node3的yarn-site.xml里的ResourceManager地址是不是node1。有些人在复制配置时把yarn.resourcemanager.hostname也原封不动地写成了其他机器导致NodeManager去连接一个不存在的ResourceManager。另外注意yarn.nodemanager.env-whitelist里的配置项如果该列表缺少必要的环境变量NodeManager启动容器时会报“Invalid environment”错误。把你看到的那一行直接抄过去基本就没问题了。5.3 网络通信问题排查症状能够启动进程但HDFS客户端连接超时或DataNode发送心跳失败。排查思路先在node1上执行ping node2和ping node3看基础网络是否通。然后检查防火墙是否关闭。最后检查hosts文件的映射是否一致——注意是所有节点都要有一致的映射如果你只在node1上写了映射node2上没写那么node2解析不了node1也会出问题。另一个比较容易忽略的地方是虚拟机的网络模式发生了漂移。比如你配置的时候用的是NAT模式但克隆的时候变成了桥接模式导致IP变了。这个坑在克隆虚拟机时特别常见建议每次克隆完都检查三台机器的IP和hosts是否还对得上。5.4 磁盘空间不足导致数据块写入失败症状往HDFS上传数据时提示“There are X missing blocks”但集群看起来一切正常。排查思路很可能是DataNode磁盘满了。HDFS的副本策略会尽量平均分布数据但如果某台机器的DataNode目录空间不足它会尝试换一个目录或节点而如果都没有空间就会报missing blocks。用df -h检查各节点的磁盘使用率清理掉日志文件或大文件即可。还有一个隐藏因素hadoop.tmp.dir默认的数据目录在/tmp下系统重启后该目录被清理但NameNode和DataNode的目录结构还在会导致启动异常。把你core-site.xml里的hadoop.tmp.dir改到持久化目录能彻底规避这个问题。5.5 常见问题速查表现象可能原因解决办法NameNode启动失败提示元数据目录不存在未执行格式化或格式化失败检查dfs.namenode.name.dir路径执行hdfs namenode -formatDataNode启动失败日志提示clusterId不匹配格式化执行了多次清空所有节点的tmp目录重新格式化一次MapReduce任务卡在Reduce 88%yarn-site.xml中aux-services未配置添加mapreduce_shuffle配置并重启YARN上传文件报Permission denieddfs.permissions.enabled为true学习阶段改为false或使用hdfs用户操作NodeManager状态为Unhealthy本地磁盘目录不可写或空间不足检查/opt/hadoop/tmp目录权限清理磁盘5.6 经验之谈日志才是最好的老师这节放到最后是因为它比任何一条具体故障都有价值。很多人在集群出问题时第一反应是去搜索引擎复制报错信息这没错但你至少应该先看一眼日志文件的报错上下文。我见过有人把同一个故障在网上搜了一下午其实日志里就已经明明白白写了具体原因比如“Permission denied”或者“No such file or directory”。Hadoop的日志做得相当详细几乎每个组件都有独立的日志文件遇到问题先做这两步找到对应节点的/opt/hadoop/logs/目录下跟涉及角色相关的日志用tail -200查看报错后20~50行的完整堆栈这两步能解决80%的问题。剩下20%的情况再去搜索引擎搜报错关键字你会发现自己搜得也更精准。6. 启动验证与冷备要点让集群生命周期更稳定6.1 常用启停命令小结集群的启停命令关键在于执行位置和顺序。启动HDFS在NameNode所在节点node1上执行start-dfs.sh它会自动通过workers文件启动所有DataNode。 启动YARN同样在node1上执行start-yarn.sh自动启动所有NodeManager。 停止集群在node1上执行stop-dfs.sh、stop-yarn.sh。有些版本的教程会让你在每台机器上单独执行命令那太原始了。Hadoop自带的start/stop脚本就是设计来分布式管理守护进程的前提就是SSH免密配置好。另外如果你修改了配置文件不需要重启整个集群。HDFS的配置可以动态刷新hdfs dfsadmin -refreshNodesYARN的配置动态加载yarn rmadmin -refreshQueues但这不包括修改了端口、地址这类必须重启才生效的参数。学习阶段改完配置直接重启集群是最保险的。6.2 SecondaryNameNode的冷备价值很多教程里SecondaryNameNode往往被一笔带过但它在HDFS的元数据安全中扮演的角色值得单独说。它所做的“定期合并fsimage和edits log”操作本质上是为NameNode减负防止edits log无限增长。如果NameNode发生故障SecondaryNameNode的检查点数据能用来加速恢复但它不是热备不能自动接管服务。所以我的建议是SecondaryNameNode可以放在node2或node3上至少要与NameNode分开这样才能起到“故障分散”的意义。但在我们前面这个三节点规划里node2和node3跑着DataNode如果你还把SecondaryNameNode放过去会增加那台机器的内存压力。所以最务实的做法还是暂时放在node1——学习阶段的单点问题等你理解了集群原理后再去优化。6.3 后续扩展方向搭建完成不等于结束。我强烈建议你在跑通WordCount之后主动做这几件事把副本数从2或3改一次重新上传一个文件观察每个块在不同DataNode上的分布变化手动kill掉一个DataNode进程然后操作文件观察HDFS的容错复制过程在YARN上提交一个自定义的MapReduce程序比如简单的词频统计体会编写和调度的完整链路这三件事做完你对Hadoop的理解才真正从“会搭”迭代到“会用”。写在后面的话搭集群这件事第一次翻车很正常。我见过太多人在格式化、免密、防火墙这些环节反复折腾这恰恰说明你在建立“系统化排查”的能力。什么技术文档都不如自己踩一遍坑学得快。等你把这一套流程跑到行云流水你会发现很多大数据的“高级问题”根子上还是这些基础概念没吃透。如果再往后走你可以在这个集群上装ZooKeeper、HBase、Spark、Flink让这套环境陪伴你走完整条大数据学习路线。但无论后面加什么组件HDFS和YARN这两个地基都不会变。把今天这块地基夯实了后面盖什么楼都不慌。