
1. 为什么我劝你亲手搭一遍Hadoop完全分布式集群刚入行那会儿我对Hadoop的理解长期停留在“伪分布式跑通WordCount就算会了”的阶段。直到有一次帮朋友处理一个日志分析的小项目数据量大概几十个GB单机跑得吭哧吭哧我才意识到伪分布式和完全分布式之间隔着的不是几行配置而是一整套关于进程调度、数据分布、容错机制的真实认知。后来我花了整整两个周末用三台虚拟机从零搭了一套完全分布式集群踩了无数坑也终于把NameNode、DataNode、ResourceManager、NodeManager这些概念从“背下来的名词”变成了“看得见摸得着的东西”。这篇内容就是那次折腾的完整复盘。我会把三台机器的规划、JDK与Hadoop的安装、核心配置文件的每一处改动、格式化与启动顺序、以及我踩过的那些坑全部摊开讲清楚。适合谁看如果你是刚接触大数据的在校学生或者是从开发转数据方向的工程师又或者你已经在用云上的托管服务但想搞明白底层到底怎么回事那这篇内容应该能帮你省下不少查文档和试错的时间。我尽量不堆术语每个配置项都告诉你为什么这么改改错了会出什么现象。需要提前说明的是我用的环境是三台Linux虚拟机Hadoop版本选的是3.x系列3.3.xJDK用8或者11都可以我实测11更省心。整套流程在物理机上同样适用只是网络配置部分需要根据你的实际网段调整。下面进入正题。2. 集群规划与前置准备三台机器怎么分工2.1 节点角色分配与硬件建议完全分布式集群最少需要三台机器这是Hadoop自身副本机制决定的——默认副本数是3如果只有两台副本永远无法达到理想分布也就失去了分布式的意义。我的规划是这样的主机名IP示例角色内存建议node1192.168.10.101NameNode、DataNode、ResourceManager、NodeManager4GB起node2192.168.10.102DataNode、NodeManager、SecondaryNameNode2GB起node3192.168.10.103DataNode、NodeManager2GB起这里有个新手常问的问题为什么NameNode和ResourceManager放在同一台答案很简单小规模集群里这两个主控进程的资源消耗并不大分开反而增加管理成本。但要注意NameNode和ResourceManager都是内存大户如果数据量真的上来了该拆还是要拆。SecondaryNameNode我放在了node2它的作用是定期合并fsimage和edits日志减轻NameNode重启时的压力注意它不是NameNode的热备别搞混了。内存分配上我给每台机器留了至少1GB给操作系统剩下的给YARN和Hadoop进程。如果你机器内存紧张可以把YARN的容器内存调小但NameNode的堆内存别低于1GB否则元数据一多就容易OOM。2.2 网络与主机名配置三台机器要能互相通过主机名通信这是后面所有配置的基础。我习惯先改hostname再改hosts文件。在node1上执行hostnamectl set-hostname node1另外两台分别改成node2、node3。然后每台机器的/etc/hosts都要加上三行192.168.10.101 node1 192.168.10.102 node2 192.168.10.103 node3改完记得ping node2测试一下能通才行。这里有个坑有些系统的防火墙默认开着会导致后面DataNode连不上NameNode。我一般直接关掉防火墙和SELinux测试环境没必要给自己找麻烦systemctl stop firewalld systemctl disable firewalld setenforce 0setenforce 0是临时关闭SELinux要永久关闭得改/etc/selinux/config里的SELINUXdisabled。这一步不做后面启动集群时会出现各种莫名其妙的连接拒绝排查起来很费时间。2.3 SSH免密登录配置Hadoop的启动脚本依赖SSH在集群间分发指令所以必须配置免密登录。在node1上生成密钥对ssh-keygen -t rsa一路回车即可。然后把公钥复制到三台机器包括自己ssh-copy-id node1 ssh-copy-id node2 ssh-copy-id node3验证一下ssh node2能直接进去就说明成功了。我建议三台机器之间两两都配一遍虽然理论上只需要node1能免密登录其他节点但后面调试时你会经常在node2上直接操作配全了省事。另外ssh-copy-id如果提示命令不存在手动把~/.ssh/id_rsa.pub的内容追加到目标机器的~/.ssh/authorized_keys里也行效果一样。3. JDK与Hadoop安装版本选择与目录规划3.1 JDK安装与版本选择Hadoop 3.x对JDK版本有要求JDK 8和JDK 11都支持但JDK 11在性能和新特性上更有优势我实测下来也更稳定。我选的是OpenJDK 11用包管理器装最省事yum install -y java-11-openjdk-devel或者用apt的话就是apt install openjdk-11-jdk。装完用java -version确认一下。然后配置环境变量编辑/etc/profile在末尾加上export JAVA_HOME/usr/lib/jvm/java-11-openjdk export PATH$JAVA_HOME/bin:$PATH注意JAVA_HOME的路径要根据你实际安装位置调整用which java再readlink -f可以找到真实路径。改完source /etc/profile生效。三台机器都要做这一步别偷懒只做一台。3.2 Hadoop下载与目录结构Hadoop我选的是3.3.6版本这个版本比较稳定社区文档也全。下载地址用官方镜像就行下载完传到node1的/opt/software目录下然后解压到/opt/moduletar -zxvf hadoop-3.3.6.tar.gz -C /opt/module/解压完的目录结构值得了解一下后面配置会经常用到bin/客户端命令比如hdfs、hadoop、yarnsbin/集群管理命令比如start-dfs.sh、start-yarn.shetc/hadoop/所有配置文件都在这里核心中的核心share/示例jar包和文档lib/依赖库配置Hadoop环境变量同样在/etc/profile里加export HADOOP_HOME/opt/module/hadoop-3.3.6 export PATH$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATHsource之后用hadoop version验证。到这里node1上的准备工作就差不多了但先别急着往下走把node1上的/opt/module/hadoop-3.3.6整个目录分发到node2和node3scp -r /opt/module/hadoop-3.3.6 node2:/opt/module/ scp -r /opt/module/hadoop-3.3.6 node3:/opt/module/环境变量也要在node2和node3上配一遍或者直接把/etc/profile也scp过去再source。这一步做完三台机器的软件环境就一致了。4. 核心配置文件逐项拆解每个参数为什么这么改4.1 core-site.xml集群的全局门牌号这个文件定义集群的全局配置最关键的是fs.defaultFS它告诉客户端默认的文件系统地址是什么。编辑/opt/module/hadoop-3.3.6/etc/hadoop/core-site.xmlconfiguration property namefs.defaultFS/name valuehdfs://node1:8020/value /property property namehadoop.tmp.dir/name value/opt/module/hadoop-3.3.6/data/tmp/value /property /configurationfs.defaultFS里的8020是NameNode的RPC端口客户端读写文件都走这个口。hadoop.tmp.dir是Hadoop的临时目录NameNode和DataNode的元数据默认都放这里。为什么要显式指定因为默认值在/tmp下系统重启可能被清空到时候集群直接起不来元数据全丢。这个坑我踩过一次格式化重来花了半小时所以强烈建议改到一个持久化目录。4.2 hdfs-site.xml副本与数据目录这个文件控制HDFS的具体行为核心参数有三个configuration property namedfs.replication/name value3/value /property property namedfs.namenode.name.dir/name value/opt/module/hadoop-3.3.6/data/namenode/value /property property namedfs.datanode.data.dir/name value/opt/module/hadoop-3.3.6/data/datanode/value /property property namedfs.namenode.secondary.http-address/name valuenode2:9868/value /property /configurationdfs.replication设成3因为我们正好三台DataNode每个块存三份任何一台挂了数据都不丢。dfs.namenode.name.dir和dfs.datanode.data.dir分别指定元数据和数据块的存储路径同样是为了避开/tmp。dfs.namenode.secondary.http-address指定SecondaryNameNode跑在node2上端口9868是它的Web访问端口。这里有个细节dfs.namenode.name.dir可以配多个目录用逗号分隔实现元数据的冗余存储。生产环境建议至少配两个不同磁盘的目录但测试环境一个就够了。4.3 yarn-site.xml资源调度的大脑YARN负责集群的资源管理和任务调度配置如下configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.resourcemanager.hostname/name valuenode1/value /property property nameyarn.nodemanager.resource.memory-mb/name value2048/value /property property nameyarn.scheduler.maximum-allocation-mb/name value2048/value /property /configurationyarn.nodemanager.aux-services必须设成mapreduce_shuffle这是MapReduce任务运行的前提不配的话任务会卡在shuffle阶段。yarn.resourcemanager.hostname指定ResourceManager所在节点。yarn.nodemanager.resource.memory-mb是每个NodeManager能支配的总内存我设的2048MB因为虚拟机内存有限。yarn.scheduler.maximum-allocation-mb是单个容器能申请的最大内存不能超过上面的值。这两个参数要根据你机器的实际内存调整设大了会OOM设小了任务跑不起来。4.4 mapred-site.xml与workers文件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 /configurationmapreduce.framework.name设成yarn表示MapReduce任务跑在YARN上。mapreduce.application.classpath指定任务运行时的类路径不配的话任务会报ClassNotFound。最后是workers文件旧版本叫slaves里面列出所有DataNode和NodeManager节点node1 node2 node3注意node1也在里面因为node1同时承担DataNode和NodeManager角色。这个文件决定了start-dfs.sh和start-yarn.sh会在哪些机器上启动从进程。配置改完后把etc/hadoop目录同步到另外两台机器scp -r /opt/module/hadoop-3.3.6/etc/hadoop node2:/opt/module/hadoop-3.3.6/etc/ scp -r /opt/module/hadoop-3.3.6/etc/hadoop node3:/opt/module/hadoop-3.3.6/etc/5. 格式化与集群启动顺序错了全白搭5.1 NameNode格式化与启动流程配置全部就位后第一件事是格式化NameNode。在node1上执行hdfs namenode -format看到Storage directory ... has been successfully formatted就说明成功了。这里有个铁律格式化只能做一次。如果你后面改了配置想重新格式化必须先把所有节点上的data目录和logs目录删干净否则会导致NameNode和DataNode的clusterID不一致DataNode起不来。我第二次搭的时候就是没删干净DataNode一直报Incompatible clusterIDs排查了半天。格式化完成后启动HDFSstart-dfs.sh这个脚本会读取workers文件在node1启动NameNode在三台机器启动DataNode在node2启动SecondaryNameNode。启动完用jps检查进程node1上应该有NameNode、DataNodenode2上有DataNode、SecondaryNameNodenode3上有DataNode。如果少了哪个去对应机器的logs目录看日志。接着启动YARNstart-yarn.shnode1上会出现ResourceManager和NodeManager另外两台出现NodeManager。同样用jps确认。5.2 Web UI验证与常见启动问题进程都起来后打开浏览器访问http://node1:9870这是HDFS的Web界面能看到集群概览、DataNode列表、存储使用情况。如果页面打不开先检查防火墙再检查NameNode进程是否真的起来了。访问http://node1:8088是YARN的界面能看到ResourceManager状态和任务队列。我遇到过几个典型问题一是start-dfs.sh报Permission denied原因是SSH免密没配好回头检查authorized_keys权限必须是600二是DataNode启动后马上挂掉多半是clusterID不一致或者数据目录权限问题三是Web UI能打开但DataNode列表为空通常是workers文件里写了主机名但hosts没配对应IP。这些问题在日志里都有明确提示关键是知道去哪个日志找——NameNode的日志在logs/hadoop-*-namenode-*.logDataNode的日志在logs/hadoop-*-datanode-*.log。6. 功能验证与踩坑实录跑通才算数6.1 用WordCount验证集群可用性集群起来了不代表能用得跑个任务验证。Hadoop自带WordCount示例先创建一个测试文件echo hello hadoop hello world /opt/test.txt hdfs dfs -mkdir -p /input hdfs dfs -put /opt/test.txt /input/然后提交任务hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /input /output跑完后查看结果hdfs dfs -cat /output/part-r-00000应该输出每个单词的计数。如果任务卡在ACCEPTED状态不动多半是YARN内存配置太小容器申请不到资源如果报Container killed去NodeManager日志看是不是内存超了。我第一次跑的时候把yarn.nodemanager.resource.memory-mb设成了1024结果MapReduce的默认容器要1536MB直接卡死改成2048后秒过。6.2 常见问题速查表现象可能原因排查方向DataNode启动即挂clusterID不一致删除data目录重新格式化Web UI打不开防火墙未关检查firewalld和SELinux任务卡在ACCEPTEDYARN内存不足调大nodemanager内存SSH连接被拒免密未配好检查authorized_keys权限NameNode无法启动元数据损坏查看namenode日志必要时重新格式化副本数始终为1只有一台DataNode检查workers文件和jps输出6.3 几个让我印象深刻的坑第一个坑是主机名解析。我一开始只在node1的hosts里配了三台机器的映射node2和node3没配结果node1能启动集群但node2上的DataNode连不上NameNode日志里全是UnknownHostException。后来三台机器都配齐才解决。第二个坑是hadoop.tmp.dir没改。第一次搭的时候用的默认值结果虚拟机重启后集群直接起不来元数据全没了。从那以后我养成了习惯所有持久化目录都显式指定并且定期备份NameNode的元数据目录。第三个坑是时间同步。三台机器的时间如果差太多会导致HDFS的租约机制出问题表现为文件写入卡住。我后来在每台机器上配了NTP同步虽然测试环境不配也能跑但生产环境这是必须的。6.4 集群停止与日常维护停止集群的顺序和启动相反先停YARN再停HDFSstop-yarn.sh stop-dfs.sh日常维护中我建议定期用hdfs dfsadmin -report查看集群状态用yarn node -list查看节点健康度。如果某个DataNode挂了修好后直接hdfs --daemon start datanode单独启动即可不用重启整个集群。另外hdfs balancer命令可以在DataNode之间平衡数据分布新加节点后跑一下很有必要。7. 我个人在实际操作中的体会这套集群我前后搭了三次第一次花了整整一天第三次只用了四十分钟。差别不在于手速而在于对每个配置项的理解深度。我最大的体会是别怕报错怕的是不知道去哪看日志。Hadoop的日志写得非常详细几乎每个错误都有明确的提示关键是要养成先看日志再动手改的习惯。另外配置文件改完后一定要同步到所有节点我吃过只改node1结果node2行为不一致的亏。最后分享一个小技巧把整个搭建过程写成一个shell脚本下次换环境直接跑省时省力还能保证一致性。这个集群后续还可以扩展比如加一台机器做高可用或者集成Hive、Spark那又是另一个话题了。