ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Linux下Hadoop多节点集群搭建全攻略:从环境配置到故障排查

Linux下Hadoop多节点集群搭建全攻略:从环境配置到故障排查 先交代一个背景我当年第一次在Linux上搭Hadoop集群时因为照着网上老教程配IP、改hostname折腾了三天都没让NameNode正常起来最后发现问题是防火墙没放行端口。所以这篇东西我尽量把为什么也讲清楚而不是只丢一串命令让你复制。这篇内容主要面向刚接触大数据、准备在Linux上自己动手搭一套多节点Hadoop集群的人也适合做完伪分布式后想往真集群迈一步、但对整体配置逻辑还没彻底理顺的开发者。1. 搭建前的资源规划先想清楚要几台机器、各自干什么角色我在不少交流群里看到很多新手一上来就照着官方文档开三台4核8G的云主机结果集群跑起来后发现资源闲置一大半账单倒是挺好看。实际上家庭实验室或者学习环境里用两台、甚至一台机器做逻辑上的多节点也能把集群搭建的完整流程跑通关键是先把节点角色分清。Hadoop集群从物理角色上看核心就三类进程NameNode和ResourceManager一般放在主节点MasterDataNode和NodeManager放在从节点Worker。如果你准备做高可用那还要额外规划备用的NameNode节点一般是第二台机器整体扮演Standby的角色。我习惯用一个表格把角色分配写死免得后期在配置文件里写错hostname主机名IP示例角色master192.168.1.10NameNode、ResourceManagerworker01192.168.1.11DataNode、NodeManagerworker02192.168.1.12DataNode、NodeManager这里有一个容易忽略的点网上很多教程让你把master也配成DataNode这在小集群里没问题但你心里要清楚master上的DataNode是在用系统盘做存储后续如果跑大任务磁盘IO很可能会拖后腿。有条件的话worker节点单独挂数据盘作为dfs.datanode.data.dir的存储路径。操作系统方面我建议统一用同一个Linux发行版别一台CentOS一台Ubuntu混着搭。虽然Hadoop是纯Java写的跨平台本身没毛病但你在排查问题时包管理器、防火墙命令、SELinux行为都不一样会白白增加心智负担。我自己用CentOS 7/8或者Ubuntu Server 20.04都搭过CentOS系列在踩坑排查时网上资料最多Ubuntu则在依赖安装上更省事。另外现在国产Linux发行版比如麒麟、统信UOS也有不少机器在跑大数据。底层是Linux内核JDK与Hadoop同样能跑部署思路一模一样差别主要在systemctl命令的服务名和包安装方式上。2. 环境初始化JDK、SSH免密和防火墙是第一步别急着改配置文件很多教程上来就让你编辑hadoop-env.sh、core-site.xml这是顺序上的大误区。Hadoop的启动和通信依赖底层的Java环境、SSH远程执行机制以及端口互通能力这三样不准备好后面所有配置都白搭。2.1 JDK版本选择Hadoop 3.3.x要求Java 8或者Java 11我用的是JDK 8。这里要提醒一句不要用系统自带的OpenJDK就完事有些Linux仓库里的OpenJDK路径和Hadoop脚本预期路径不一致导致JAVA_HOME明明设了还是起不来。我踩过这个坑之后改成手动解压JDK到指定目录。mkdir -p /opt/java tar -zxvf jdk-8u202-linux-x64.tar.gz -C /opt/java/ cd /opt/java mv jdk1.8.0_202 jdk8然后在/etc/profile里追加export JAVA_HOME/opt/java/jdk8 export PATH$PATH:$JAVA_HOME/bin建议三台机器都执行一遍source /etc/profile之后用java -version确认。为什么非要手动指定全路径因为Hadoop的脚本在找Java时先看JAVA_HOME环境变量如果找不到它会用which java探测而部分Linux发行版把java放在/usr/bin/java这本身是个软链接链到哪去就不好说了机器之间不一致很容易出怪问题。2.2 SSH免密钥配置集群启动时master节点需要远程执行worker节点上的命令比如启动DataNode进程所以master要能免密登录所有节点。这也是为什么配置免密的根本原因。# 在master上执行 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id master ssh-copy-id worker01 ssh-copy-id worker02-P 表示空口令实测过程中有的同学加上引号反而报错直接在交互式回车也是可以的。配置完之后逐一ssh worker01验证如果第一次还需要输密码那就是没配对。2.3 防火墙、SELinux与hosts映射这一步是被忽略得最惨的重灾区。NameNode和DataNode之间的心跳走8020或9820端口YARN的ResourceManager走8088和8030、8032等端口如果防火墙开着你会发现进程都在但Web界面连不上、节点死活不注册。我一开始图省事直接systemctl stop firewalld其实更优雅的做法是放行用到的端口段。大数据集群通常固定在一个内网环境直接禁用防火墙用于学习环境没什么问题生产环境则建议用安全组或防火墙规则精确放行。hosts文件也要统一在三台机器上写同样的映射cat /etc/hosts EOF 192.168.1.10 master 192.168.1.11 worker01 192.168.1.12 worker02 EOF为什么不用云服务器的私有域名或者内网IP直连因为Hadoop的配置里你写hostname比写IP更可读而且后续做HA高可用时虚拟IP与主机名之间的绑定关系更清晰。3. 五个配置文件背后的为什么core-site、hdfs-site、yarn-site、mapred-site与workersHadoop的配置项非常多但你搭一个最基础的三节点集群真正需要动手改的其实就五个文件。而且每个文件的侧重点完全不同core-site管全局hdfs-site管存储yarn-site管资源调度mapred-site管计算框架workers管从节点列表。理解了这层分工你就不容易在改参数时改错文件。3.1 core-site.xml它最重要的是fs.defaultFS这个值决定了整个集群的入口地址。configuration property namefs.defaultFS/name valuehdfs://master:9820/value /property property namehadoop.tmp.dir/name value/data/hadoop/tmp/value /property /configurationhadoop.tmp.dir这里我再三强调一定要改成非默认目录。因为默认的/tmp/hadoop-${user}在系统重启时会被清理一旦清理了NameNode元数据全没了你就得重新格式化之前落进去的文件数据基本就废了。这是很多重启之后集群起不来问题的根源。所以我习惯把临时目录放到专门的/data/hadoop/tmp并在所有节点上建好这个路径。3.2 hdfs-site.xml这个文件里dfs.replication是副本数量我在三节点集群上设置为2。为什么不是3因为三副本至少需要三台DataNode如果master也作为DataNode参与存储那算三台如果master不分担存储三副本在写入时就会出现有节点一直收不到副本的报错提示。初学者用2最省心既保证了一定容错又不至于因为副本数不满足而报异常。另外两个关键参数是NameNode和DataNode的数据目录。官方文档建议这两个路径不要放在系统盘。我在生产环境见过NameNode元数据盘损坏导致整个集群不可用的案例非常惨痛。正确做法是给dfs.namenode.name.dir指定独立目录甚至可以做镜像比如同时写两个磁盘路径逗号分隔这样单个磁盘故障时元数据还在property namedfs.namenode.name.dir/name value/data/hadoop/name/value /property property namedfs.datanode.data.dir/name value/data/hadoop/data/value /property顺带说一下dfs.namenode.secondary.http.address这个参数指定SecondaryNameNode的地址。很多新手以为SecondaryNameNode是NameNode的备份其实它不是热备而是定期合并编辑日志、生成新的镜像文件帮NameNode减轻启动时回放日志的压力。你可以把它放在另外一台机器上。但在小集群里通常就让master自己兼任也不会有太大问题。3.3 yarn-site.xmlYARN负责整个集群的资源管理和任务调度核心是把CPU、内存这些资源抽象出来容器化地分配给MapReduce或其他计算任务。yarn.nodemanager.resource.memory-mb这个值的设置很考验经验我见到过有人在4G内存的机器上给NodeManager分配3G结果系统本身加Java进程直接把内存吃满触发OOM。我一个稳妥的起步建议是如果是4G内存的机器给NodeManager分配2G给操作系统留1G再留出DataNode等进程的余量如果是8G内存分配4G比较安全。同样的还有yarn.nodemanager.resource.cpu-vcores我一般设置为物理核心数减一避免系统本身没CPU可用。property nameyarn.nodemanager.resource.memory-mb/name value4096/value /property property nameyarn.nodemanager.resource.cpu-vcores/name value2/value /property property nameyarn.resourcemanager.hostname/name valuemaster/value /property这里要理解资源是静态分配还是动态调整YARN把每台NodeManager可用的资源写死然后再按照Container粒度去切分。如果你后面在集群上跑Spark任务会觉得内存不够或CPU核数不对首先要排查的就是这里。3.4 mapred-site.xmlMapReduce框架的运行模式在这里配置指定为YARNproperty namemapreduce.framework.name/name valueyarn/value /property还有一个调优参数值得关注mapreduce.jobhistory.address它负责记录已经运行完的作业日志。如果你不配置JobHistory服务你在Web界面上就看不到跑完的MapReduce任务明细日后定位数据倾斜等问题会非常被动。3.5 workers文件与hadoop-env.sh中的JAVA_HOME在Hadoop 3.x里slaves文件已经被改名为workers。这个文件的作用是告诉master节点你要远程到哪些机器上去启动DataNode和NodeManager进程。我在此提醒workers文件里面不要写master自己除非你确实想让master也承担存储和计算角色否则容易出现元数据争用。worker01 worker02而hadoop-env.sh里要显式写上JAVA_HOME这个我前面说过原因。如果你前面已经配置了全局环境变量这一处也可以不写但实际测试下来显式写一遍最稳因为Hadoop的守护进程脚本在通过SSH远程启动节点时不一定能继承你/etc/profile里的全部变量。4. 手把手启停流程从格式化到一键启动前后顺序一步都不能乱环境配置好、参数填完之后不代表你敲几次start-dfs.sh就能成功。很多人第一步就犯了个错在主节点上直接执行了格式化命令但忽略了格式化之后绝对不能再次随意执行hdfs namenode -format否则NameNode的namespaceID会改变DataNode注册时发现ID对不上直接拒绝连接。这种情况的报错信息像java.io.IOException: Incompatible namespaceIDs。这个问题的原理是格式化NameNode相当于给整个文件系统创建了一个全新的身份标识而DataNode启动时会把自己磁盘里的namespaceID和NameNode做比对不一致就报错。解决办法不是反复格式化而是要么找一台干净的DataNode目录删除重建要么在集群初次搭建时就规划好只格式化一次。启动流程我按经验顺序拆成几步在所有节点上执行mkdir -p /data/hadoop/{tmp,name,data}确保HDFS存储目录都存在。在master上首次执行hdfs namenode -format。格式化日志最后一行出现successfully formatted才是成功。执行start-dfs.sh这个脚本会依次在master启动NameNode在workers文件的机器上启动DataNode。执行start-yarn.sh启动ResourceManager和NodeManager。用jps分别在三台机器上检查进程。我见过一种情况jps在master只看到了NameNode没有DataNode。这是因为worker节点上的Java进程启动失败大概率是SSH免密或JAVA_HOME的问题。此时可以单独到worker节点手动执行hdfs datanode看前台打印的报错日志这样排查起来比看分散的日志快得多。至于停止集群顺序反过来先停YARN再停HDFS。生产环境里直接停HDFS会导致未完成的写操作异常虽然系统有恢复机制但能避免就避免。我用stop-all.sh一键全停也单独跑过stop-dfs.sh和stop-yarn.sh习惯上分开跑更稳。HDFS与YARN启动之后一定要看一眼Web界面NameNode管理界面默认是http://master:9870ResourceManager是http://master:8088看到Active节点和Live Nodes数量都正常才算真正启动成功。5. 故障排查的完整思路jps看得懂、日志查得对、端口看得通我见过太多人卡在明明都按教程做了为什么起不来但实际上大部分都是低级问题。这里把我积累的一套排查链路完整写出来你照这个顺序走一遍基本能定位90%的问题。5.1 jps先看进程别急着翻日志在任何节点上jps命令列出的是Java进程如果你看到以下进程说明启动顺利节点应有进程masterNameNode、ResourceManager、SecondaryNameNode如果配置了worker01DataNode、NodeManagerworker02DataNode、NodeManagerMaster有DataNode并非完全错误只是角色分配上的选择问题。但如果你在某台worker上看到了NameNode进程那绝对有问题——说明你workers或masters文件里配置乱了或者你在这台机器上手动执行启动脚本。YARN和HDFS的启动脚本不同start-dfs.sh只会启动NameNode和DataNodestart-yarn.sh只会启动ResourceManager和NodeManager这点也可以帮你判断是哪一块启动失败的。5.2 日志文件在哪里看Hadoop的日志默认放在$HADOOP_HOME/logs/目录下。每次启动后日志文件名通常带日期和进程名如hadoop-hadoop-datanode-worker01.log。查看日志时我习惯先grep -i error过滤效率更高。最常见的几类报错报错关键字原因解决方案NameNode is not running格式化后未成功启动或端口被占用查看NameNode日志确认端口冲突问题Incompatible namespaceIDsDataNode目录中的namespaceID与NameNode不一致删除DataNode的数据目录后重新启动ConnectException: 8020防火墙拦截或hosts配置不对检查master的IP、hosts映射、防火墙java.io.IOException: Permission denied目录权限不对或非hadoop用户操作将目录属主切换为hadoop用户UnsupportedClassVersionErrorJDK版本与Hadoop不兼容换用JDK8或JDK11我在实验环境里最频繁碰到的是权限问题。Hadoop进程在非root用户下启动但/data/hadoop目录是我用root建的导致DataNode启动时无法写入直接退出。解决办法很简单chown -R hadoop:hadoop /data/hadoop。5.3 端口测试是定位网络问题最快的方式如果进程都在但节点之间连不上优先用telnet或者nc测端口。# 在worker01上测试能否连通master的NameNode RPC端口 telnet master 9820如果连接失败看三件事IP是否ping得通、hosts是否映射正确、防火墙是否拦截了端口。在Hadoop 3.x中老教程里的50070端口早就改了现在NameNode UI是9870别照旧教程等50070那样Web界面永远打不开。这是版本升级带来的常见坑我见过不止一个人卡在这里以为集群没起来。5.4 免密登录失效的隐蔽原因ssh localhost通了不代表配置成功要ssh master和ssh worker01都各自验证一遍。我自己遇到过.ssh目录权限不对导致免密失效的情况authorized_keys文件需要是600权限.ssh目录需要是700权限。如果权限太开放SSH出于安全考虑会拒绝读取公钥文件。这个用chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys修一下就行。6. 集群验证与跑通第一个MapReduce任务启动以后最直接的验证方式是跑一个实际任务。官方自带的WordCount是经典入门样例完成单词统计的分布式计算。首先你需要在HDFS上准备输入数据。我习惯用以下命令创建一个测试目录并上传一个本地文件hdfs dfs -mkdir -p /input hdfs dfs -put /opt/words.txt /input/hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /input /output执行完这条命令以后你会看到一串Map和Reduce的进度输出100%跑完后去查看结果hdfs dfs -cat /output/part-r-00000如果能看到每个单词及次数的统计列表说明整个HDFS存储、YARN调度、MapReduce计算框架已经彻底打通。这种实打实跑通任务的成就感比看到网页上显示Live Nodes:2还要强因为它验证的是整条链路。跑完任务后要注意/output目录如果已经存在再次运行wordcount会报错。因为MapReduce的输出目录在作业启动前必须是空的这是框架的安全设计防止覆盖结果数据。删掉旧目录再跑即可hdfs dfs -rm -r /output7. 搭建完成之后的下一步HA、Spark整合与节点扩容方向集群能跑通WordCount只是起步。很多人在这一步停下然后感叹集群好难、生态太复杂其实接下来完全可以往实战方向延伸。首先是高可用HA。前面这套方案里NameNode是单点一旦master宕机整个HDFS不可用。生产环境一定会部署两个NameNodeActive/Standby配合ZooKeeper做自动故障切换。你看到热搜词里大量出现hadoop和zookeeper整合实战就是因为在真实场景中ZooKeeper扮演了协调者的核心角色。搭建完基础集群后在原有环境上部署ZooKeeper集群再把NameNode的元数据通过JournalNode共享就可以把集群升级为HA模式。这个过程的本质是从单点故障可接受升级到持续对外服务数据不丢、服务不断。其次是计算框架的整合。热搜词里同时出现spark集群搭建不是偶然因为Hadoop生态里存储HDFS和计算YARNMapReduce解耦之后Spark完全可以跑在YARN上直接读取HDFS数据。这样同一个集群既能跑MapReduce批处理又能跑Spark内存计算还能接Flink做实时流处理。集群的计算边界彻底打开了。这时你会发现前面配置YARN时的内存参数、CPU核数分配变得极其重要因为不同计算框架会争抢资源。再者是节点扩容。集群挂在生产环境之后数据量一上来磁盘和内存总会先到瓶颈。扩容的流程和搭建节点差不多准备一台新机器配好JDK、SSH免密改好hosts和防火墙然后把新节点的主机名追加到master的workers文件里直接在新节点上单独启动DataNode和NodeManager刷新NameNode的Web界面就能看到新节点加入。注意扩容DataNode不需要重新格式化只要保持集群的namespaceID一致即可这也是为什么我前面反复强调不要手贱随时格式化。提示如果你在复制集群配置到新节点时误复制了之前DataNode的数据目录千万要提前清空/data/hadoop/data里的内容否则新节点会带着旧ID去注册集群同样触发namespaceID不匹配的报错。8. 性能调优的一次真实经验参数怎么改才有意义最后分享一个我在完成基础搭建后做的性能验证实验目的是搞清楚网上说的调优参数到底有没有用。我在三台机器上都设置了dfs.replication2默认的block大小是128MB。按照理论写入一个大文件时数据块复制因子为2理论上能少写一块数据。但实际测试时我先把dfs.blocksize调到64MB然后上传一个1GB的文件发现写入速率并没有显著提升。原因其实不复杂——在小集群的千兆内网环境下网络带宽是主要瓶颈而且数据只有一个客户端在写队列里没有并发块大小的变化不会让物理IO变快只会影响存储文件块的数量和索引大小。所以我慢慢意识到所谓调优不是照抄几个参数就行必须结合自身集群的使用特征。如果是小文件特别多的业务比如日志文件几千个几KB到几MB反而应该把块调小减少内存碎片如果是大文件顺序读写保持默认128MB最省事。CPU和内存的分配同理。有段时间我让worker节点同时跑DataNode和NodeManager默认参数下NodeManager能用的内存挤占了DataNode的缓存导致HDFS读文件时频繁访问磁盘整个任务变慢。调法也很直白在yarn-site.xml里降低yarn.nodemanager.resource.memory-mb给DataNode留出更多页缓存空间。这说明在部署资源时要动态观察而不是照搬模板。在做这些调整时还有一个好习惯把每次修改的参数、修改理由、调整前后的数据记录下来。我在本地维护了一份配置变更表哪怕只是改一个副本数我都会记录上下文。集群出问题时这份记录是定位哪次改动引入回归的最重要线索。最后说说我个人的实测体会集群刚搭建完成时别急着堆参数、调性能先保持默认配置稳定运行两周观察磁盘、内存、网络三条曲线把日志熟悉起来再根据瓶颈做针对性调整。我现在回头看当年踩过的所有坑里真正伤筋动骨的都不是配置本身而是急于求成、跳过验证步骤带来的连锁反应。你按这套流程把基础打牢后面无论是上ZooKeeper做HA、接Spark还是接Flink都会顺畅得多。
返回列表