前阵子有个朋友问我手里有几台Linux机器想搞个Hadoop集群但网上教程大多是用CentOS写的他自己装了Ubuntu照着改了半天愣是起不来。这话题我太熟悉了——Ubuntu和CentOS在用户、命令、目录结构上都有差异直接照搬确实容易翻车。今天我就以“基于Ubuntu下hadoop集群搭建”为主线把从规划、环境准备、配置、启动到验证的完整过程捋一遍。这篇内容适合两类人看一类是刚接触大数据想在自己电脑上用虚拟机搭一个最小集群练手另一类是在公司内网申请了几台物理机或云主机需要搭一个能跑业务任务的生产级实验集群。不管你是哪种读完你都能得到一份可以直接落地执行的方案而且我会重点解释每个关键配置背后的理由——有些坑不是配置写错而是你没搞懂它为什么这么配。1. 集群规划与设计思路1.1 为什么要用Hadoop集群而不是单机很多人在入门阶段会问我在笔记本上装个单机版Hadoop也能跑WordCount为什么非得搭集群这个问题值得先想清楚。单机版Hadoop本质上是把所有守护进程跑在同一台机器上数据存储和计算都受限于单机磁盘和内存。一旦数据量达到TB级别单机磁盘装不下、单进程计算太慢这时候就需要把数据分散到多台机器的磁盘上、把计算任务分散到多台机器的CPU上——这就是Hadoop集群解决的问题。我这次搭建的是一个经典的3节点集群由1个主节点和2个工作节点组成。主节点运行NameNode和ResourceManager负责管理文件系统的元数据和资源调度工作节点运行DataNode和NodeManager负责实际存储数据块和执行计算任务。3个节点是最小规模的“真实”集群既能体现出分布式特性配置和维护成本又不至于太高。1.2 操作系统和软件版本选型操作系统我选了当前较新的Ubuntu LTS版本22.04或24.04均可LTS意味着长期维护支持对服务器场景比较稳妥。相比CentOSUbuntu的包管理用apt安装依赖时会自动处理大部分软件包之间的依赖关系省去很多编译和依赖的烦恼。软件版本上我采用的是Hadoop 3.3.x版本搭配JDK 8或JDK 11。Hadoop 3.x较2.x有诸多改进包括支持HDFS纠删码、YARN资源类型的精细化、以及默认的副本数变为3等。JDK版本一定不能选太高JDK 17虽然新但和Hadoop 3.3.x的组合容易踩到模块化相关的坑不是不能用是没必要给自己添堵。版本选型这件事我的原则很简单要么选生态里最新稳定的组合要么选经过时间验证的经典组合。Hadoop 3.3.x JDK 8就是后者社区资料最全遇到问题基本都能搜到答案。1.3 网络、主机名和用户规划集群里每台机器都要能通过主机名互相访问这一步很多人会漏。我在搭建时规划了三个主机名主节点叫master两个工作节点叫worker1和worker2。在每台机器的/etc/hosts里写上三台机器的IP和主机名映射这样后续配置和命令执行都简洁很多。另外建议全程用同一个系统用户操作生产中常见做法是创建一个专用的hadoop用户。我这次直接用了一个普通用户非root因为Hadoop的部分脚本对root用户有限制比如某些启动脚本检测到root会拒绝执行。如果你不想额外创建用户至少在root下需要额外配置才能正常跑不如规规矩矩建个普通用户省心。用户规划和网络规划是后续所有步骤的地基这一步做扎实了会省掉后面大量排查时间。2. 基础环境准备2.1 系统更新与必要工具安装拿到一台全新的Ubuntu服务器我会先执行系统更新sudo apt update sudo apt upgrade -y然后安装一些排查和操作必备的工具sudo apt install -y vim net-tools openssh-server ssh pdsh这里pdsh是个容易被忽略但很实用的工具它可以同时在多台机器上执行相同的命令比如同时在三台机器上执行jps查看进程状态不用一台一台登录明显提高后续运维效率。虚拟机环境有一个必须检查的点确保每台机器的网络模式一致且IP地址固定。DHCP分配的IP可能在重启后变化导致hosts映射失效。我习惯在Ubuntu上用netplan配置静态IP文件在/etc/netplan/目录下具体文件名每台机器可能不一样。配置静态IP看起来是基础操作但整个集群的稳定性就依赖IP稳定。2.2 JDK安装与JAVA_HOME配置Hadoop是用Java写的所以JDK是硬依赖。在Ubuntu上安装OpenJDK很简单sudo apt install -y openjdk-8-jdk安装完成后需要确认JDK的实际安装路径readlink -f $(which java)我在机器上得到的路径是/usr/lib/jvm/java-8-openjdk-amd64这个路径后面配置JAVA_HOME时要用。可以用sudo vim /etc/environment在文件中追加一行JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64然后执行source /etc/environment使其生效。注意这里的路径以你机器实际输出为准不同的Ubuntu版本和架构可能路径不同比如32位系统是java-8-openjdk-i386。这一步看起来简单但很多新手会把JAVA_HOME配到用户家目录的.bashrc里而Hadoop的守护进程启动时是通过/etc/environment或hadoop-env.sh读取的如果两者不统一会出现“Java路径找不到”的报错。建议直接在hadoop-env.sh里再显式指定一次双保险。2.3 配置SSH免密登录Hadoop主节点需要远程启动工作节点上的守护进程这是通过SSH实现的。如果每次启动都要输密码那自动化就成了空话所以必须配置SSH免密登录。在三台机器上分别执行ssh-keygen -t rsa -b 4096 -N 这里-N 表示空密码这样生成的密钥才能用于免密登录。然后把我主节点的公钥分发给三台机器包括主节点自己ssh-copy-id -i ~/.ssh/id_rsa.pub hadoopmaster ssh-copy-id -i ~/.ssh/id_rsa.pub hadoopworker1 ssh-copy-id -i ~/.ssh/id_rsa.pub hadoopworker2这里用户和主机名替换成你自己实际的。分发完成后在主节点测试ssh master hostname ssh worker1 hostname ssh worker2 hostname如果每条命令都能直接返回对应的主机名而不提示输密码说明免密配置成功。关于SSH配置有一个权限细节必须强调。~/.ssh目录权限必须是700authorized_keys文件的权限必须是600或644权限太宽松会导致SSH直接忽略这个文件。我在一台机器上曾经遇到过反复配置免密都不生效最后发现是~/.ssh目录的权限是777chmod修正后立刻正常。这类小问题在文档里写得少但在实践中非常常见建议配置完成后顺手检查一下权限。3. Hadoop配置文件的实战拆解3.1 下载解压与环境变量配置我这次使用的是Hadoop 3.x版本的稳定发行包。下载解压到/opt/hadoop目录下并将Hadoop的bin和sbin目录加入PATH环境变量。在~/.bashrc中追加export HADOOP_HOME/opt/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin然后source ~/.bashrc使配置生效。Hadoop的配置集中在$HADOOP_HOME/etc/hadoop/目录下。虽然新版Hadoop将部分配置抽取到了hadoop-env.sh等env脚本中但核心的五个配置文件仍是core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml和workers旧版本叫slaves。下面我一个一个拆解。3.2 core-site.xml与hdfs-site.xml配置core-site.xml负责全局参数核心是设置默认文件系统。configuration property namefs.defaultFS/name valuehdfs://master:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop/tmp/value /property /configuration第一个参数把默认文件系统指定为HDFS并指明了NameNode的通信地址和端口。第二个参数指定了Hadoop临时目录这个目录会被NameNode和DataNode用来存放一些运行时数据。这个目录建议手动创建并确保属主正确mkdir -p /opt/hadoop/tmp chown -R hadoop:hadoop /opt/hadoop/tmphdfs-site.xml是HDFS的核心配置设置副本数、NameNode元数据和DataNode数据块的存储路径configuration property namedfs.replication/name value2/value /property property namedfs.namenode.name.dir/name value/opt/hadoop/namenode/value /property property namedfs.datanode.data.dir/name value/opt/hadoop/datanode/value /property /configuration副本数我设置为2因为集群只有两台DataNode副本数设为3会导致第三个副本写入失败。如果后续扩容到3台以上可以改成3。namenode和datanode的数据目录也需要在每台机器上手动创建注意主节点需要创建namenode目录所有节点包括主节点和两个工作节点都要创建datanode目录。这是因为主节点也可以作为DataNode参与存储这里我让主节点也运行DataNode进程以充分利用磁盘资源。这里有一个关键的“为什么”NameNode的数据目录绝对不能和DataNode的数据目录放在同一个物理磁盘上。因为NameNode管理的是整个文件系统的元数据一旦损坏整个集群就废了而DataNode存储的是数据块丢失后还能通过副本恢复。生产环境通常用两块独立磁盘分开放实验环境下至少也要放在不同目录。3.3 yarn-site.xml与mapred-site.xml配置YARN是Hadoop的资源调度器负责给MapReduce或其他计算框架分配CPU和内存。yarn-site.xml里需要设置ResourceManager所在的主机以及NodeManager的资源分配configuration property nameyarn.resourcemanager.hostname/name valuemaster/value /property property nameyarn.nodemanager.resource.memory-mb/name value8192/value /property property nameyarn.nodemanager.resource.cpu-vcores/name value4/value /property property nameyarn.scheduler.maximum-allocation-mb/name value4096/value /property property nameyarn.nodemanager.vmem-check-enabled/name valuefalse/value /property property nameyarn.nodemanager.pmem-check-enabled/name valuefalse/value /property /configuration这里的内存和CPU数值以你的机器实际配置为准。假如每台工作节点有16GB内存、8核CPU那么yarn.nodemanager.resource.memory-mb可以设为12GB预留部分给操作系统和DataNode进程cpu-vcores可以设为6。我把虚拟内存检查和物理内存检查都设为了false这个操作单机跑可能无所谓但在多节点环境里如果某个Container实际占用内存超过设定值NodeManager可能会强制杀掉这个任务导致作业莫名失败。关闭检查可以规避这类问题代价是单个任务可能占用过多内存。如果你完全掌控了任务的资源需求关闭更省心如果集群是多租户共用建议保持默认开启。mapred-site.xml配置MapReduce的运行时框架为YARNconfiguration property namemapreduce.framework.name/name valueyarn/value /property property namemapreduce.jobhistory.address/name valuemaster:10020/value /property /configuration3.4 配置workers文件并同步到所有节点Hadoop 3.x版本的workers文件$HADOOP_HOME/etc/hadoop/workers取代了旧版的slaves文件内容是一行一个主机名这里要写入所有DataNode和NodeManager的主机名master worker1 worker2我让master也作为DataNode和NodeManager参与计算所以也写在workers里。如果你的主节点资源比较紧张可以不把它加入workers只让它跑NameNode和ResourceManager。配置全部完成后用rsync命令把整个配置目录同步到所有节点rsync -avz /opt/hadoop/etc/hadoop/ worker1:/opt/hadoop/etc/hadoop/ rsync -avz /opt/hadoop/etc/hadoop/ worker2:/opt/hadoop/etc/hadoop/这一步千万别省。集群配置不一致导致的诡异问题比代码bug难排查得多。我早期犯过这个错在主节点改了一个参数忘记同步结果两台DataNode行为和主节点不一致现象是部分数据块写入失败但进程都活着排查了很久。4. 集群启动与功能验证4.1 格式化NameNode与首次启动在首次启动之前必须先格式化NameNode。这一步会初始化HDFS的元数据存储目录生成唯一的clusterIDhdfs namenode -format这个命令只需要在主节点上执行一次就行。启动之后DataNode启动时会把自身的clusterID和NameNode的clusterID做比对如果不一致就会拒绝注册表现就是DataNode反复启动然后自动退出。这里必须强调一个很多新手都踩过的坑格式化操作会重新生成clusterID如果你在集群启动之后因为某个故障再次执行了格式化那么DataNode上原有的clusterID就和NameNode新的clusterID对不上了所有DataNode都会起不来。所以格式化nameNode要极其慎重最好在格式化之前确认所有节点都是干净的或者根本没有启动过集群。格式化完成后在主节点依次启动HDFS和YARNstart-dfs.sh start-yarn.sh如果配置正确脚本会通过SSH逐台启动守护进程。一台台地看可以用jps命令检查进程是否都起来了。在主节点应该能看到NameNode、ResourceManager、DataNode、NodeManager四个进程在两个工作节点上应该能看到DataNode和NodeManager。4.2 HDFS命令行验证进程起来了不代表集群真的可用还要验证HDFS的读写功能。首先创建用户目录并查看状态hdfs dfs -mkdir -p /user/hadoop hdfs dfs -ls /然后上传一个本地文件到HDFS我这里直接用了Hadoop自带的配置测试文件hdfs dfs -put /opt/hadoop/etc/hadoop/core-site.xml /user/hadoop/ hdfs dfs -ls /user/hadoop/用hdfs dfsadmin -report查看各DataNode的存储状态hdfs dfsadmin -report输出中会列出每个DataNode的IP、剩余空间、存储容量等信息。如果两个DataNode都在线说明HDFS层已经正常工作。4.3 运行WordCount验证计算能力HDFS能读写文件只是第一步集群的价值在于计算。我用Hadoop自带的WordCount示例做一次端到端测试hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.x.x.jar wordcount /user/hadoop/core-site.xml /user/hadoop/output执行完成后查看输出结果hdfs dfs -cat /user/hadoop/output/part-r-00000如果输出了每个单词的出现次数说明MapReduce任务从提交、分配到执行的整个闭环都打通了。这时候再去访问两个Web界面做进一步确认。通过Web界面可以直观地验证集群状态在浏览器里访问http://master:9870查看NameNode的Web UI能看到HDFS的存储总容量、存活节点数和每个数据块的状态访问http://master:8088查看YARN的集群资源状况能看到Active Nodes数量以及每个节点的可用内存和核数。5. 常见问题与排查实录5.1 DataNode进程反复启动后退出这是在多节点环境下最常见的故障。表现是群启动后主节点和两个工作节点都狂刷日志DataNode进程要么根本起不来要么起来后几秒就自动退出。排查路径查看DataNode日志。tail -100 /opt/hadoop/logs/hadoop-hadoop-datanode-worker1.log如果日志里出现java.io.IOException: Incompatible clusterIDs原因就是我前面说的——NameNode被重复格式化过导致集群ID不一致。这种场景的解决办法有几个我最常用的是保留原有的namenode数据目录直接修改datanode数据目录下的current/VERSION文件里的clusterID使它和NameNode的保持一致然后重启。简单粗暴的办法是同时清理所有节点的namenode和datanode目录然后重新格式化但代价是所有已存储的数据都会丢失生产环境禁用。5.2 SSH免密配置不生效另一种高发问题免密配置完成后执行ssh worker1仍然提示输入密码或者出现Permission denied (publickey)。排查时先确认密钥是否真的分发成功ssh -vvv worker1如果输出显示Offering public key但服务端拒绝了优先检查目标机器上的/etc/ssh/sshd_config是否启用了PubkeyAuthentication yes。Ubuntu默认是开启的如果被改过就要改回来并重启ssh服务。最常见的还是权限问题。用以下命令修正chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys曾经有个项目里所有机器都是某云厂商的镜像它们的sshd配置里加了AuthorizedKeysFile .ssh/authorized_keys但路径没有展开到用户家目录导致所有用户的公钥都无法识别查看日志才发现是模板配置问题。这类问题很难预先预料只能靠经验积累多看一眼sshd_config总是对的。5.3 防火墙与端口不通集群启动后主节点进程都正常但从Windows本机浏览器访问http://master:9870一直超时。排查步骤# 在主节点确认端口监听 sudo netstat -tlnp | grep 9870 # 在三台机器上检查防火墙状态 sudo ufw status如果ufw是active状态要么关闭要么放行所需端口。我用的是放行sudo ufw allow 9870/tcp sudo ufw allow 8088/tcp sudo ufw allow 9000/tcp sudo ufw allow 8020/tcp sudo ufw allow 50010/tcp sudo ufw allow 50020/tcp如果是云主机还要在云平台的安全组规则里放行这些端口。很多云厂商默认只允许22端口其他端口外部无法访问。这一块属于环境差异不同云平台设置位置不同但排查思路是一样的先本机确认监听正常再检查防火墙再检查安全组。5.4 集群启动慢与磁盘空间不足有时候集群不是起不来而是启动过程异常慢或者运行一段时间后任务开始大面积失败。先排查磁盘空间。DataNode存储空间满了会导致文件写入失败上传文件报datanode.DiskOutOfSpaceException。用df -h检查每台机器的磁盘占用如果有机器空间告警及时清理或扩容。内存也是一个隐患。Hadoop守护进程本身占用内存YARN容器又需要额外内存。如果机器内存是8GBYARN堆内存设了6GB操作系统加上NameNode进程就可能把内存吃满触发OOM Killer。这类问题不一定会直接报内存错误而是表现为某个DataNode进程莫名消失。排查时看系统日志dmesg | grep -i oom如果有Out of memory: Kill process的记录说明确实是内存不足。解决思路是重新评估YARN允许分配的内存上限留足系统余量。5.5 常见问题速查表我把上面这些故障和排查方法整理成了一张表方便你在实际遇到问题时快速对照。故障现象可能原因排查命令/方法DataNode启动即退出clusterID不匹配cat /opt/hadoop/datanode/current/VERSION和NameNode的VERSION比对SSH免密不生效权限问题或sshd配置chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys检查sshd_config进程正常但Web UI打不开防火墙或云安全组未放行sudo netstat -tlnp检查监听sudo ufw status检查防火墙Worker节点始终不在线hosts配置错误或网络不通ping worker1检查所有机器的/etc/hosts任务提交后直接失败内存配置过大节点无资源yarn node -list -all查看节点资源确认nodemanager.resource.memory-mb上传文件报磁盘满数据目录所在磁盘空间不足df -h /opt/hadoop/datanode清理或扩展磁盘6. 实操心得与后续扩展建议集群搭建好之后我习惯再花几分钟做几个优化动作这些往往不是教程里必写的但实际用下来很值得。第一件事是确认集群的时间同步。分布式系统的元数据时间戳如果不一致后来的维护和日志排查会非常痛苦。Ubuntu默认装了systemd-timesyncd简单确认一下服务处于active状态即可。第二件事是验证主节点的高可用能力。我搭的虽然是单NameNode集群但至少要知道NameNode挂掉后怎么快速恢复。通常做法是把namenode目录定期备份到远程或者配置SecondaryNameNode定期合并日志。对实验环境来说做到“知道恢复流程”就够了生产环境建议直接上高可用方案。第三件事是提前规划数据目录的空间。Hadoop不像数据库不会主动做容量规划数据写满磁盘是迟早的事。给每个DataNode的/opt/hadoop/datanode单独挂一块大容量盘比让它在系统盘上和其他数据挤在一起要稳得多。如果后续需要扩容可以把新机器装好JDK、配置好SSH免密把主节点配置目录同步到新机器然后启动DataNode和NodeManager进程新节点会自动注册进集群。整个过程不需要重启现有节点这也是Hadoop比较友好的设计之一。最后分享一个小技巧。千万记得给Hadoop配置添加自定义的log4j日志级别调整我在测试阶段习惯把日志级别调高能看到更多任务内部执行细节。等集群稳定运行后再调回WARN级别避免日志刷屏影响排查。关于Ubuntu下Hadoop集群的搭建最核心的一点不是某个配置项怎么写而是把握住“配置一致性”和“权限正确性”这两条底线。前者依靠rsync和统一的配置文件管理后者依靠规范的目录和文件权限。只要这两点做扎实了集群基本不会出什么大乱子。剩下的就是遇到问题别慌按第5节的排查路径一步步看日志、查网络、核配置绝大多数故障都能在半小时内定位。