一台内存只有4G的电脑,能不能顺利完成Hadoop安装部署?能。而且我更建议你先来做伪分布式搭建,而不是直接开三台虚拟机搞完全分布式。伪分布式就是把NameNode、DataNode、ResourceManager这些角色全部塞进同一台机器,用一套配置模拟出完整集群的工作流程。很多初次接触大数据的人,往往在配置阶段就开始懵:为什么要改这么多XML?为什么启动要SSH免密?为什么格式化一次就不能再格式化?这篇文章就把从零开始装Hadoop、配置伪分布式的那套完整流程,以及我实际踩过的坑和排查思路全部写清楚,适合刚入门、想在虚拟机或云服务器上先跑通HDFS和YARN的人。1. 环境准备与版本选型1.1 伪分布式到底在模拟什么在正式动手之前,先把一个概念理清楚:Hadoop有三种运行模式,很多人分不清伪分布式和单机模式的区别。单机模式(Standalone Mode)下,Hadoop不会启动独立的守护进程,MapReduce任务直接在同一个JVM里用本地文件系统跑,根本没有启动HDFS和YARN。这种模式适合做代码调试和冒烟测试,但它没有体现任何分布式语义,你在单机模式里跑WordCount,只是验证命令能通而已。伪分布式(Pseudo-Distributed Mode)则完全不同。虽然只有一台机器,但NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager这五个进程都会真实启动,数据会真正写入HDFS,MapReduce任务会通过YARN去申请容器、分配资源。它和真实集群的区别仅仅是所有角色挤在同一台机器上,但工作机制和真实集群一模一样。完全分布式就是把NameNode、ResourceManager放在一台机器,DataNode、NodeManager放在另外几台机器,各司其职。如果你一上来就搭三节点集群,网络配置、节点互信、资源隔离这些坑会堆在一起,出了问题根本分不清是配置错误还是环境问题。所以在单机环境先趟一遍完整的安装部署和任务提交流程,再上多节点会顺很多。1.2 Hadoop版本和JDK版本怎么选版本选错是很多人后面反复折腾的根源。我这里的建议是选择Apache Hadoop 3.3.x,不要碰2.x。3.x对NameNode内存占用做了优化,HDFS支持了纠删码,YARN的调度机制也更成熟;更重要的是,现在市面上主流教程和第三方工具都已经切到3.x,遇到问题搜索到的经验大多是适配3.x的。JDK方面,Hadoop 3.3.x官方支持Java 8和Java 11。我用OpenJDK 8的次数最多,整体兼容性最省心。有些开发者装了JDK 17,启动时直接报不支持--add-exports相关参数,倒不是说不能配,只是默认参数没适配,需要额外加JVM参数,对新手不友好。所以保守起见,请按OpenJDK 8或11来准备。操作系统推荐使用主流Linux发行版,Ubuntu、Debian、CentOS均可,下面命令以Ubuntu/Debian系为例,CentOS只是包管理器不同,解压、配置、启动部分完全一致。不建议用Windows直接装Hadoop,虽然可以通过一些补丁跑起来,但会额外消耗很多精力,完全不值得。1.3 基础环境检查清单在动手安装前,先确认三件事:内存至少2G,推荐4G。伪分布式要同时跑五个Java进程,1G内存很容易让ResourceManager因OOM退出。如果使用云服务器,需要放行后续会访问的Web端口。这一点经常被忽略,本地一切正常,但浏览器就是打不开管理界面,基本都是安全组问题。确认系统里有wget、tar、ssh等基础工具,没有就提前装上。准备好之后,开始安装JDK。2. 安装JDK、创建专用用户与SSH免密2.1 安装OpenJDK并设置JAVA_HOME我以Ubuntu为例,安装命令如下:sudo apt update sudo apt install -y openjdk-8-jdk-headless安装完之后验证一下:java -version如果输出里出现OpenJDK 8的版本号,说明成功。接下来设置JAVA_HOME。很多人不设置这个变量,后面启动Hadoop时报JAVA_HOME is not set,非常经典。先确认Java实际安装路径:readlink -f $(which java)我的机器上输出是/usr/lib/jvm/java-8-openjdk-amd64/bin/java,那么JAVA_HOME就是去掉末尾/bin/java后的路径。把它写进环境变量文件:sudo tee /etc/profile.d/java.sh <<'EOF' export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH EOF source /etc/profile.d/java.sh然后重新执行echo $JAVA_HOME确认路径已经生效。2.2 创建一个Hadoop专用用户很多云主机默认用自己的普通用户,甚至直接拿root操作。我建议单独建立一个hadoop用户,原因很简单:一是权限隔离,避免误删系统目录;二是Hadoop脚本在root下启动时会因为用户检查和权限问题增加额外障碍,虽然可以通过环境变量强制指定用户,但没必要给自己添麻烦。sudo useradd -m -s /bin/bash hadoop sudo passwd hadoop后续所有安装操作都在hadoop用户下执行。如果你被迫使用root,也要记得在后面的hadoop-env.sh里增加HDFS_NAMENODE_USER、HDFS_DATANODE_USER、YARN_RESOURCEMANAGER_USER等变量,否则sbin下的脚本会拒绝对root执行。2.3 SSH免密登录为什么绕不开伪分布式虽然只有一台机器,但start-dfs.sh脚本依然会通过SSH协议连接localhost来启动NodeManager等进程。如果每次连接都要求输入密码,脚本会卡在交互界面,让启动流程直接半途而废。所以免密登录是必须配置的一项。切换到hadoop用户并生成密钥:su - hadoop ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys然后测试:ssh localhost第一次会提示确认指纹,输入yes后如果直接进入shell而不需要密码,就说明免密生效。权限如果不对,SSH出于安全策略会忽略authorized_keys,所以那两步chmod不要省。3. 下载Hadoop并逐份拆解四个核心配置文件3.1 下载安装包与目录规划去Apache Hadoop官网或者任意一个镜像站,选择hadoop-3.3.x.tar.gz二进制包,不要下源码包,源码包还需要自己编译。解压到/opt/hadoop,并把数据目录规划好:sudo tar -xzf hadoop-3.3.6.tar.gz -C /opt sudo mv /opt/hadoop-3.3.6 /opt/hadoop sudo chown -R hadoop:hadoop /opt/hadoop mkdir -p /data/hadoop/namenode /data/hadoop/datanode /data/hadoop/tmp sudo chown -R hadoop:hadoop /data/hadoop之所以把数据目录建在独立的/data/hadoop下,而不是用默认路径,是因为默认的元数据目录在/tmp下面。/tmp在系统重启时可能被清理,一旦NameNode的元数据丢失,整个集群的状态就乱了。这个坑在我见过的初学者里出现频率非常高。3.2 配置hadoop-env.sh进入/opt/hadoop/etc/hadoop目录,首先修改hadoop-env.sh:vim hadoop-env.sh找到export JAVA_HOME=这一行,把刚才设置的路径填进去:export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64如果当前就是root用户,还建议在文件末尾追加这些内容,避免sbin脚本检查用户时报错:export HDFS_NAMENODE_USER=root export HDFS_DATANODE_USER=root export HDFS_SECONDARYNAMENODE_USER=root export YARN_RESOURCEMANAGER_USER=root export YARN_NODEMANAGER_USER=root如果你按上面的方案使用hadoop用户,也建议把上面的root改成hadoop,这样可以确保脚本在sudo场景下行为一致。3.3 core-site.xml:告诉客户端去哪里找NameNode这个文件配置Hadoop集群的全局属性。最重要的参数是fs.defaultFS,它决定了客户端访问HDFS时默认连接的NameNode地址。<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>这里的node1需要提前写在/etc/hosts里,例如:127.0.0.1 node1使用主机名而不是IP,是为了将来扩展到多节点集群时,不用回改配置文件里的地址。端口9000是常见的自定义选择,它只是NameNode RPC端口,配置成8020也可以,核心是不要被其他服务占用,并且所有配置保持一致。hadoop.tmp.dir是Hadoop临时目录的根,虽然我们在hdfs-site.xml里会单独指定NameNode和DataNode的数据目录,但把tmp目录也挪到非系统文件夹,能避免系统清理临时文件影响任务运行。3.4 hdfs-site.xml:副本数与数据目录这个文件是HDFS的核心配置。有三个参数必须理解透彻。第一个是dfs.replication,副本数。伪分布式只有一个DataNode,如果保留默认值3,NameNode会一直尝试把块复制成3份,但集群里根本没有那么多节点,于是Web UI里会长期显示Under-Replicated Blocks,控制台也会不断刷警告。所以必须改成1。第二个是dfs.namenode.name.dir,NameNode存放元数据(fsimage和edits log)的路径,必须是本地文件系统路径。第三个是dfs.datanode.data.dir,DataNode存放实际数据块的路径,同样必须是本地文件系统路径。<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///data/hadoop/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///data/hadoop/datanode</value> </property> </configuration>注意路径前面的file:///不能丢。Hadoop允许把数据目录配置成HDFS路径,但NameNode元数据必须写在本地磁盘,所以要用file这个scheme明确告诉它这是块本地路径。很多人的配置看着没问题却起不来,就是少写了一个/,写成了file://data/hadoop/namenode,语法就错了。3.5 mapred-site.xml:让MapReduce跑在YARN上默认etc/hadoop/mapred-site.xml这个文件是不存在的,只有一个模板mapred-site.xml.template。先复制:cp mapred-site.xml.template mapred-site.xml然后写入:<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>mapreduce.framework.name决定MapReduce任务跑在哪种资源调度框架上,最核心就是这个yarn。如果不配置,任务会退回本地模式,完全不会用YARN来申请容器;网上一些老教程会让你配mapreduce.jobtracker.address,那是Hadoop 1.x时期MapReduce独立运行时的配置,在3.x里完全不需要。3.6 yarn-site.xml:辅助服务与内存上限YARN有两个重要配置。第一个是yarn.nodemanager.aux-service,值固定是mapreduce_shuffle。MapReduce任务在shuffle阶段,需要从map任务所在节点拉取中间结果,这个操作由NodeManager上的辅助服务完成。不配置这一项,作业会一直卡在Running状态,日志里报错shuffle连接失败。第二个是内存相关配置。默认情况下,NodeManager觉得自己内存很大,会给每个容器分配很高配额。在只有2G或4G内存的机器上,这会让ResourceManager连启动容器的基本内存都不够,直接OOM退出。建议根据机器物理内存调整:<configuration> <property> <name>yarn.nodemanager.aux-service</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> </property> </configuration>如果机器有4G内存,这个配置可以再调高到3072或4096;如果只有2G,一定要把这两个值压到2048以下,否则启动即崩。4. 格式化、启动服务与验证4.1 格式化NameNode,只做一次在所有配置完成后,启动前的最后一步是格式化NameNode:hdfs namenode -format这条命令会生成NameNode的集群标识,也就是clusterID,以及最初的fsimage元数据镜像。执行后看到SHUTDOWN_MSG和类似successfully formatted的字样,才算成功。这里有一个非常非常重要的经验:格式化命令只在集群第一次启动前执行,之后不要再随便跑。格式化的本质是初始化元数据目录,而DataNode在启动时会读取自己的clusterID,并尝试和NameNode的clusterID对齐。如果你启动后发现有问题,改完配置再次格式化,三个数据目录里的clusterID就对不上了,DataNode进程活着,却始终无法注册到NameNode,这种问题排查起来非常绕。真想重置环境,正确做法是先把所有数据目录清掉,再重新格式化,不能只执行格式化命令。4.2 启动HDFS和YARN执行启动命令:start-dfs.sh start-yarn.sh也可以直接start-all.sh,但为了避免启动顺序混乱问题,我习惯分开执行。停止时顺序反过来:stop-yarn.sh stop-dfs.sh启动完成后,验证进程状态最直接的工具是jps:jps正常情况应该看到正好五个进程:12345 NameNode 12346 DataNode 12347 SecondaryNameNode 12348 ResourceManager 12349 NodeManager如果jps命令不存在,检查PATH里是否包含JDK的bin目录。五个进程各有职责:NameNode负责元数据,DataNode负责数据块,SecondaryNameNode并不是NameNode的热备,它只负责定期拉取NameNode的fsimage和edits log并合并,帮NameNode瘦身;ResourceManager负责资源调度,NodeManager负责执行容器。4.3 Web界面与命令行双重验证进程都起来之后,从浏览器访问两个页面:访问地址端口说明http://ip:98709870NameNode管理界面,查看HDFS状态http://ip:80888088ResourceManager管理界面,查看YARN资源在NameNode界面里点Datanodes菜单,能看到一个Live状态的节点;点Overview能看到文件系统的容量和使用率。在8088页面上,能看到Active Nodes数量为1,说明NodeManager已经正常注册。命令行验证可以执行:hdfs dfsadmin -report输出里会有一行Live datanodes (1),后面跟着DataNode的存储容量信息。这一步如果正常,说明HDFS文件系统已经完全可用了。4.4 跑通第一个MapReduce作业环境搭好不能只看着Web界面发呆,跑一个真实的MapReduce任务才算闭环。先用HDFS自带的Pi示例验证YARN调度:hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi 2 4它会通过蒙特卡洛方法估算圆周率,整个过程会在控制台输出map和reduce的进度。如果这个任务能正常结束,说明HDFS读写、YARN容器分配、MapReduce框架这条链路全部通畅。再来一个WordCount:echo "hello hadoop hdfs yarn mapreduce" > words.txt hdfs dfs -mkdir -p /wordcount/input hdfs dfs -put words.txt /wordcount/input/ hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /wordcount/input /wordcount/output hdfs dfs -cat /wordcount/output/part-r-00000输出目录如果已经存在,任务会直接报错,所以重复执行前要先把旧目录删除:hdfs dfs -rm -r /wordcount/output顺便提醒一句:不要拿中文文本去跑WordCount还期待分词效果,Hadoop默认的分词器按空格和标点切分,对中文没有语义识别能力。学习阶段用英文文本验证流程即可。5. 高频问题与排查实录5.1 DataNode进程在线,但Web UI里显示Dead这是我遇到最多的问题。具体表现是jps里有DataNode,但NameNode管理界面里数据节点状态为Dead,或者命令行hdfs dfsadmin -report显示0个Live节点。根本原因是多次格式化导致DataNode上的clusterID和NameNode不一致。DataNode启动后会用本地的数据目录和NameNode通信,发现两边集群标识不匹配,就拒绝注册。查看DataNode日志,能找到类似Incompatible clusterIDs或does not match的记录。日志路径在/opt/hadoop/logs/hadoop-hadoop-datanode-node1.log,打开后搜clusterID关键词就能确认。解决方法很直接,就是重建全部数据目录:stop-yarn.sh stop-dfs.sh rm -rf /data/hadoop/namenode /data/hadoop/datanode /data/hadoop/tmp hdfs namenode -format start-dfs.sh start-yarn.sh这里最容易被忽略的点是:只删NameNode目录不删DataNode目录,DataNode的旧clusterID还在,格式化后依然对不上。两个目录必须一起清空,然后再格式化。5.2 NameNode压根起不来,日志提示找不到目录如果NameNode没有出现在jps结果里,先去看logs/hadoop-hadoop-namenode-node1.log。最常见的错误是日志里报找不到/data/hadoop/namenode目录,或者没有权限写入。原因通常有两种:第一种是配置里的路径写错了,少了file:///前缀;第二种是目录创建的时候用的是root,hadoop用户没有访问权限。检查:ls -ld /data/hadoop/namenode如果owner不是hadoop,执行:chown -R hadoop:hadoop /data/hadoop然后重新格式化。5.3 ResourceManager和NodeManager起来后又消失先确认物理内存是不是已经被吃满:free -h伪分布式默认情况下,YARN的NodeManager会认为自己可以分配大量内存,如果机器只有1G或2G内存,Java进程起一个崩一个,尤其是ResourceManager很容易报OutOfMemoryError。把yarn-site.xml里的yarn.nodemanager.resource.memory-mb和yarn.scheduler.maximum-allocation-mb调低到合理值,重启YARN服务,一般能解决。一个通用的经验是:给系统预留至少512M内存给操作系统本身,剩下的内存再按比例分配给HDFS和YARN,不要在4G机器上配3G的容器上限硬撑。5.4 SSH免密已经配置,启动脚本还是要密码一般发生在复制的公钥写入authorized_keys之后,没有修正权限。SSH对.ssh目录和authorized_keys文件的权限非常敏感,如果.ssh不是700,authorized_keys不是600,SSH会直接忽略这个文件。排查步骤:ls -ld ~/.ssh ls -l ~/.ssh/authorized_keys然后修正:chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys再执行ssh localhost测试。5.5 网页打不开,但进程都在如果jps五个进程都在,命令行也能正常读写HDFS,但浏览器访问9870或8088超时,问题几乎都在网络层而不是Hadoop本身。先在服务器本机测端口监听:ss -tlnp | grep -E '9870|8088'确认端口有监听后,再检查防火墙。如果这台机器是云服务器,还要去云厂商的安全组控制台放行这两个端口。对应关系记一下:9870是NameNode界面,8088是YARN界面,不要把这两个端口搞混。5.6 常见配置错误速查整理一份我常给身边人看的速查表,方便对照:现象常见原因解决办法jps无NameNodeJAVA_HOME未设置或路径错修改hadoop-env.shjps有DataNode但状态DeadclusterID不一致清空数据目录后重新格式化任务一直Runningyarn-site.xml缺少aux-service补上mapreduce_shuffleSecondaryNameNode无法连接NameNode网络端口不通检查9000端口监听输出目录已存在重复执行MapReduce删除输出目录或换新路径启动脚本提示Permission deniedroot用户未设置脚本用户变量在hadoop-env.sh设置HDFS_NAMENODE_USER等6. 给新手的几句实在经验6.1 伪分布式阶段最该练什么很多人搭完伪分布式,跑通WordCount就算完成任务,然后开始背面试题。其实这个阶段你更应该做的是理解数据流:在NameNode的9870页面上观察块分布,在YARN的8088页面看Map和Reduce阶段的资源占用,用hdfs dfs -ls和hdfs dfs -mkdir感受HDFS的目录结构,而不是把它当成一个普通的文件系统来用。也可以做一个小实验:手动停掉DataNode进程,然后试着读取刚写入HDFS的文件,观察报错信息,再启动DataNode,观察NameNode如何感知节点重新上线。这个过程比读十篇架构分析都有价值。6.2 从伪分布式向完全分布式扩展伪分布式的价值在于练习之后可以很自然地过渡到完全分布式。把当前这台机器当作NameNode和ResourceManager,再准备两台机器当DataNode和NodeManager,然后做这几件事:在/etc/hosts里写上三台机器的IP和主机名;把配置文件里fs.defaultFS保持指向node1不变,副本数从1改成3;修改workers文件(Hadoop 3.x中替代了slaves)为另外两个DataNode主机名;在每台机器上配置好SSH免密,确保NameNode能免密登录到所有worker。有了伪分布式的基础,你会发现完全分布式只是把进程拆到不同机器上而已,剩下的问题基本都是网络和权限问题。我见过太多人一上来就搞多节点,遇到问题后在配置文件里反复横跳,最后连哪个节点上哪个进程没起来都分不清。先把单机伪分布式彻底玩明白,再谈扩展。最后分享一个排查问题的小习惯:无论遇到什么异常,第一件事永远是打开/opt/hadoop/logs/目录,找到对应的-xxx.log文件,看最后几十行错误信息。不要盲目重启、不要反复格式化。日志里写得很清楚,只是很多人没养成先看日志的习惯。
一台内存只有4G的电脑,能不能顺利完成Hadoop安装部署?能。而且我更建议你先来做伪分布式搭建,而不是直接开三台虚拟机搞完全分布式。伪分布式就是把NameNode、DataNode、ResourceManager这些角色全部塞进同一台机器,用一套配置模拟出完整集群的工作流程。很多初次接触大数据的人,往往在配置阶段就开始懵:为什么要改这么多XML?为什么启动要SSH免密?为什么格式化一次就不能再格式化?这篇文章就把从零开始装Hadoop、配置伪分布式的那套完整流程,以及我实际踩过的坑和排查思路全部写清楚,适合刚入门、想在虚拟机或云服务器上先跑通HDFS和YARN的人。1. 环境准备与版本选型1.1 伪分布式到底在模拟什么在正式动手之前,先把一个概念理清楚:Hadoop有三种运行模式,很多人分不清伪分布式和单机模式的区别。单机模式(Standalone Mode)下,Hadoop不会启动独立的守护进程,MapReduce任务直接在同一个JVM里用本地文件系统跑,根本没有启动HDFS和YARN。这种模式适合做代码调试和冒烟测试,但它没有体现任何分布式语义,你在单机模式里跑WordCount,只是验证命令能通而已。伪分布式(Pseudo-Distributed Mode)则完全不同。虽然只有一台机器,但NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager这五个进程都会真实启动,数据会真正写入HDFS,MapReduce任务会通过YARN去申请容器、分配资源。它和真实集群的区别仅仅是所有角色挤在同一台机器上,但工作机制和真实集群一模一样。完全分布式就是把NameNode、ResourceManager放在一台机器,DataNode、NodeManager放在另外几台机器,各司其职。如果你一上来就搭三节点集群,网络配置、节点互信、资源隔离这些坑会堆在一起,出了问题根本分不清是配置错误还是环境问题。所以在单机环境先趟一遍完整的安装部署和任务提交流程,再上多节点会顺很多。1.2 Hadoop版本和JDK版本怎么选版本选错是很多人后面反复折腾的根源。我这里的建议是选择Apache Hadoop 3.3.x,不要碰2.x。3.x对NameNode内存占用做了优化,HDFS支持了纠删码,YARN的调度机制也更成熟;更重要的是,现在市面上主流教程和第三方工具都已经切到3.x,遇到问题搜索到的经验大多是适配3.x的。JDK方面,Hadoop 3.3.x官方支持Java 8和Java 11。我用OpenJDK 8的次数最多,整体兼容性最省心。有些开发者装了JDK 17,启动时直接报不支持--add-exports相关参数,倒不是说不能配,只是默认参数没适配,需要额外加JVM参数,对新手不友好。所以保守起见,请按OpenJDK 8或11来准备。操作系统推荐使用主流Linux发行版,Ubuntu、Debian、CentOS均可,下面命令以Ubuntu/Debian系为例,CentOS只是包管理器不同,解压、配置、启动部分完全一致。不建议用Windows直接装Hadoop,虽然可以通过一些补丁跑起来,但会额外消耗很多精力,完全不值得。1.3 基础环境检查清单在动手安装前,先确认三件事:内存至少2G,推荐4G。伪分布式要同时跑五个Java进程,1G内存很容易让ResourceManager因OOM退出。如果使用云服务器,需要放行后续会访问的Web端口。这一点经常被忽略,本地一切正常,但浏览器就是打不开管理界面,基本都是安全组问题。确认系统里有wget、tar、ssh等基础工具,没有就提前装上。准备好之后,开始安装JDK。2. 安装JDK、创建专用用户与SSH免密2.1 安装OpenJDK并设置JAVA_HOME我以Ubuntu为例,安装命令如下:sudo apt update sudo apt install -y openjdk-8-jdk-headless安装完之后验证一下:java -version如果输出里出现OpenJDK 8的版本号,说明成功。接下来设置JAVA_HOME。很多人不设置这个变量,后面启动Hadoop时报JAVA_HOME is not set,非常经典。先确认Java实际安装路径:readlink -f $(which java)我的机器上输出是/usr/lib/jvm/java-8-openjdk-amd64/bin/java,那么JAVA_HOME就是去掉末尾/bin/java后的路径。把它写进环境变量文件:sudo tee /etc/profile.d/java.sh <<'EOF' export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH EOF source /etc/profile.d/java.sh然后重新执行echo $JAVA_HOME确认路径已经生效。2.2 创建一个Hadoop专用用户很多云主机默认用自己的普通用户,甚至直接拿root操作。我建议单独建立一个hadoop用户,原因很简单:一是权限隔离,避免误删系统目录;二是Hadoop脚本在root下启动时会因为用户检查和权限问题增加额外障碍,虽然可以通过环境变量强制指定用户,但没必要给自己添麻烦。sudo useradd -m -s /bin/bash hadoop sudo passwd hadoop后续所有安装操作都在hadoop用户下执行。如果你被迫使用root,也要记得在后面的hadoop-env.sh里增加HDFS_NAMENODE_USER、HDFS_DATANODE_USER、YARN_RESOURCEMANAGER_USER等变量,否则sbin下的脚本会拒绝对root执行。2.3 SSH免密登录为什么绕不开伪分布式虽然只有一台机器,但start-dfs.sh脚本依然会通过SSH协议连接localhost来启动NodeManager等进程。如果每次连接都要求输入密码,脚本会卡在交互界面,让启动流程直接半途而废。所以免密登录是必须配置的一项。切换到hadoop用户并生成密钥:su - hadoop ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys然后测试:ssh localhost第一次会提示确认指纹,输入yes后如果直接进入shell而不需要密码,就说明免密生效。权限如果不对,SSH出于安全策略会忽略authorized_keys,所以那两步chmod不要省。3. 下载Hadoop并逐份拆解四个核心配置文件3.1 下载安装包与目录规划去Apache Hadoop官网或者任意一个镜像站,选择hadoop-3.3.x.tar.gz二进制包,不要下源码包,源码包还需要自己编译。解压到/opt/hadoop,并把数据目录规划好:sudo tar -xzf hadoop-3.3.6.tar.gz -C /opt sudo mv /opt/hadoop-3.3.6 /opt/hadoop sudo chown -R hadoop:hadoop /opt/hadoop mkdir -p /data/hadoop/namenode /data/hadoop/datanode /data/hadoop/tmp sudo chown -R hadoop:hadoop /data/hadoop之所以把数据目录建在独立的/data/hadoop下,而不是用默认路径,是因为默认的元数据目录在/tmp下面。/tmp在系统重启时可能被清理,一旦NameNode的元数据丢失,整个集群的状态就乱了。这个坑在我见过的初学者里出现频率非常高。3.2 配置hadoop-env.sh进入/opt/hadoop/etc/hadoop目录,首先修改hadoop-env.sh:vim hadoop-env.sh找到export JAVA_HOME=这一行,把刚才设置的路径填进去:export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64如果当前就是root用户,还建议在文件末尾追加这些内容,避免sbin脚本检查用户时报错:export HDFS_NAMENODE_USER=root export HDFS_DATANODE_USER=root export HDFS_SECONDARYNAMENODE_USER=root export YARN_RESOURCEMANAGER_USER=root export YARN_NODEMANAGER_USER=root如果你按上面的方案使用hadoop用户,也建议把上面的root改成hadoop,这样可以确保脚本在sudo场景下行为一致。3.3 core-site.xml:告诉客户端去哪里找NameNode这个文件配置Hadoop集群的全局属性。最重要的参数是fs.defaultFS,它决定了客户端访问HDFS时默认连接的NameNode地址。<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>这里的node1需要提前写在/etc/hosts里,例如:127.0.0.1 node1使用主机名而不是IP,是为了将来扩展到多节点集群时,不用回改配置文件里的地址。端口9000是常见的自定义选择,它只是NameNode RPC端口,配置成8020也可以,核心是不要被其他服务占用,并且所有配置保持一致。hadoop.tmp.dir是Hadoop临时目录的根,虽然我们在hdfs-site.xml里会单独指定NameNode和DataNode的数据目录,但把tmp目录也挪到非系统文件夹,能避免系统清理临时文件影响任务运行。3.4 hdfs-site.xml:副本数与数据目录这个文件是HDFS的核心配置。有三个参数必须理解透彻。第一个是dfs.replication,副本数。伪分布式只有一个DataNode,如果保留默认值3,NameNode会一直尝试把块复制成3份,但集群里根本没有那么多节点,于是Web UI里会长期显示Under-Replicated Blocks,控制台也会不断刷警告。所以必须改成1。第二个是dfs.namenode.name.dir,NameNode存放元数据(fsimage和edits log)的路径,必须是本地文件系统路径。第三个是dfs.datanode.data.dir,DataNode存放实际数据块的路径,同样必须是本地文件系统路径。<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///data/hadoop/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///data/hadoop/datanode</value> </property> </configuration>注意路径前面的file:///不能丢。Hadoop允许把数据目录配置成HDFS路径,但NameNode元数据必须写在本地磁盘,所以要用file这个scheme明确告诉它这是块本地路径。很多人的配置看着没问题却起不来,就是少写了一个/,写成了file://data/hadoop/namenode,语法就错了。3.5 mapred-site.xml:让MapReduce跑在YARN上默认etc/hadoop/mapred-site.xml这个文件是不存在的,只有一个模板mapred-site.xml.template。先复制:cp mapred-site.xml.template mapred-site.xml然后写入:<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>mapreduce.framework.name决定MapReduce任务跑在哪种资源调度框架上,最核心就是这个yarn。如果不配置,任务会退回本地模式,完全不会用YARN来申请容器;网上一些老教程会让你配mapreduce.jobtracker.address,那是Hadoop 1.x时期MapReduce独立运行时的配置,在3.x里完全不需要。3.6 yarn-site.xml:辅助服务与内存上限YARN有两个重要配置。第一个是yarn.nodemanager.aux-service,值固定是mapreduce_shuffle。MapReduce任务在shuffle阶段,需要从map任务所在节点拉取中间结果,这个操作由NodeManager上的辅助服务完成。不配置这一项,作业会一直卡在Running状态,日志里报错shuffle连接失败。第二个是内存相关配置。默认情况下,NodeManager觉得自己内存很大,会给每个容器分配很高配额。在只有2G或4G内存的机器上,这会让ResourceManager连启动容器的基本内存都不够,直接OOM退出。建议根据机器物理内存调整:<configuration> <property> <name>yarn.nodemanager.aux-service</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> </property> </configuration>如果机器有4G内存,这个配置可以再调高到3072或4096;如果只有2G,一定要把这两个值压到2048以下,否则启动即崩。4. 格式化、启动服务与验证4.1 格式化NameNode,只做一次在所有配置完成后,启动前的最后一步是格式化NameNode:hdfs namenode -format这条命令会生成NameNode的集群标识,也就是clusterID,以及最初的fsimage元数据镜像。执行后看到SHUTDOWN_MSG和类似successfully formatted的字样,才算成功。这里有一个非常非常重要的经验:格式化命令只在集群第一次启动前执行,之后不要再随便跑。格式化的本质是初始化元数据目录,而DataNode在启动时会读取自己的clusterID,并尝试和NameNode的clusterID对齐。如果你启动后发现有问题,改完配置再次格式化,三个数据目录里的clusterID就对不上了,DataNode进程活着,却始终无法注册到NameNode,这种问题排查起来非常绕。真想重置环境,正确做法是先把所有数据目录清掉,再重新格式化,不能只执行格式化命令。4.2 启动HDFS和YARN执行启动命令:start-dfs.sh start-yarn.sh也可以直接start-all.sh,但为了避免启动顺序混乱问题,我习惯分开执行。停止时顺序反过来:stop-yarn.sh stop-dfs.sh启动完成后,验证进程状态最直接的工具是jps:jps正常情况应该看到正好五个进程:12345 NameNode 12346 DataNode 12347 SecondaryNameNode 12348 ResourceManager 12349 NodeManager如果jps命令不存在,检查PATH里是否包含JDK的bin目录。五个进程各有职责:NameNode负责元数据,DataNode负责数据块,SecondaryNameNode并不是NameNode的热备,它只负责定期拉取NameNode的fsimage和edits log并合并,帮NameNode瘦身;ResourceManager负责资源调度,NodeManager负责执行容器。4.3 Web界面与命令行双重验证进程都起来之后,从浏览器访问两个页面:访问地址端口说明http://ip:98709870NameNode管理界面,查看HDFS状态http://ip:80888088ResourceManager管理界面,查看YARN资源在NameNode界面里点Datanodes菜单,能看到一个Live状态的节点;点Overview能看到文件系统的容量和使用率。在8088页面上,能看到Active Nodes数量为1,说明NodeManager已经正常注册。命令行验证可以执行:hdfs dfsadmin -report输出里会有一行Live datanodes (1),后面跟着DataNode的存储容量信息。这一步如果正常,说明HDFS文件系统已经完全可用了。4.4 跑通第一个MapReduce作业环境搭好不能只看着Web界面发呆,跑一个真实的MapReduce任务才算闭环。先用HDFS自带的Pi示例验证YARN调度:hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi 2 4它会通过蒙特卡洛方法估算圆周率,整个过程会在控制台输出map和reduce的进度。如果这个任务能正常结束,说明HDFS读写、YARN容器分配、MapReduce框架这条链路全部通畅。再来一个WordCount:echo "hello hadoop hdfs yarn mapreduce" > words.txt hdfs dfs -mkdir -p /wordcount/input hdfs dfs -put words.txt /wordcount/input/ hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /wordcount/input /wordcount/output hdfs dfs -cat /wordcount/output/part-r-00000输出目录如果已经存在,任务会直接报错,所以重复执行前要先把旧目录删除:hdfs dfs -rm -r /wordcount/output顺便提醒一句:不要拿中文文本去跑WordCount还期待分词效果,Hadoop默认的分词器按空格和标点切分,对中文没有语义识别能力。学习阶段用英文文本验证流程即可。5. 高频问题与排查实录5.1 DataNode进程在线,但Web UI里显示Dead这是我遇到最多的问题。具体表现是jps里有DataNode,但NameNode管理界面里数据节点状态为Dead,或者命令行hdfs dfsadmin -report显示0个Live节点。根本原因是多次格式化导致DataNode上的clusterID和NameNode不一致。DataNode启动后会用本地的数据目录和NameNode通信,发现两边集群标识不匹配,就拒绝注册。查看DataNode日志,能找到类似Incompatible clusterIDs或does not match的记录。日志路径在/opt/hadoop/logs/hadoop-hadoop-datanode-node1.log,打开后搜clusterID关键词就能确认。解决方法很直接,就是重建全部数据目录:stop-yarn.sh stop-dfs.sh rm -rf /data/hadoop/namenode /data/hadoop/datanode /data/hadoop/tmp hdfs namenode -format start-dfs.sh start-yarn.sh这里最容易被忽略的点是:只删NameNode目录不删DataNode目录,DataNode的旧clusterID还在,格式化后依然对不上。两个目录必须一起清空,然后再格式化。5.2 NameNode压根起不来,日志提示找不到目录如果NameNode没有出现在jps结果里,先去看logs/hadoop-hadoop-namenode-node1.log。最常见的错误是日志里报找不到/data/hadoop/namenode目录,或者没有权限写入。原因通常有两种:第一种是配置里的路径写错了,少了file:///前缀;第二种是目录创建的时候用的是root,hadoop用户没有访问权限。检查:ls -ld /data/hadoop/namenode如果owner不是hadoop,执行:chown -R hadoop:hadoop /data/hadoop然后重新格式化。5.3 ResourceManager和NodeManager起来后又消失先确认物理内存是不是已经被吃满:free -h伪分布式默认情况下,YARN的NodeManager会认为自己可以分配大量内存,如果机器只有1G或2G内存,Java进程起一个崩一个,尤其是ResourceManager很容易报OutOfMemoryError。把yarn-site.xml里的yarn.nodemanager.resource.memory-mb和yarn.scheduler.maximum-allocation-mb调低到合理值,重启YARN服务,一般能解决。一个通用的经验是:给系统预留至少512M内存给操作系统本身,剩下的内存再按比例分配给HDFS和YARN,不要在4G机器上配3G的容器上限硬撑。5.4 SSH免密已经配置,启动脚本还是要密码一般发生在复制的公钥写入authorized_keys之后,没有修正权限。SSH对.ssh目录和authorized_keys文件的权限非常敏感,如果.ssh不是700,authorized_keys不是600,SSH会直接忽略这个文件。排查步骤:ls -ld ~/.ssh ls -l ~/.ssh/authorized_keys然后修正:chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys再执行ssh localhost测试。5.5 网页打不开,但进程都在如果jps五个进程都在,命令行也能正常读写HDFS,但浏览器访问9870或8088超时,问题几乎都在网络层而不是Hadoop本身。先在服务器本机测端口监听:ss -tlnp | grep -E '9870|8088'确认端口有监听后,再检查防火墙。如果这台机器是云服务器,还要去云厂商的安全组控制台放行这两个端口。对应关系记一下:9870是NameNode界面,8088是YARN界面,不要把这两个端口搞混。5.6 常见配置错误速查整理一份我常给身边人看的速查表,方便对照:现象常见原因解决办法jps无NameNodeJAVA_HOME未设置或路径错修改hadoop-env.shjps有DataNode但状态DeadclusterID不一致清空数据目录后重新格式化任务一直Runningyarn-site.xml缺少aux-service补上mapreduce_shuffleSecondaryNameNode无法连接NameNode网络端口不通检查9000端口监听输出目录已存在重复执行MapReduce删除输出目录或换新路径启动脚本提示Permission deniedroot用户未设置脚本用户变量在hadoop-env.sh设置HDFS_NAMENODE_USER等6. 给新手的几句实在经验6.1 伪分布式阶段最该练什么很多人搭完伪分布式,跑通WordCount就算完成任务,然后开始背面试题。其实这个阶段你更应该做的是理解数据流:在NameNode的9870页面上观察块分布,在YARN的8088页面看Map和Reduce阶段的资源占用,用hdfs dfs -ls和hdfs dfs -mkdir感受HDFS的目录结构,而不是把它当成一个普通的文件系统来用。也可以做一个小实验:手动停掉DataNode进程,然后试着读取刚写入HDFS的文件,观察报错信息,再启动DataNode,观察NameNode如何感知节点重新上线。这个过程比读十篇架构分析都有价值。6.2 从伪分布式向完全分布式扩展伪分布式的价值在于练习之后可以很自然地过渡到完全分布式。把当前这台机器当作NameNode和ResourceManager,再准备两台机器当DataNode和NodeManager,然后做这几件事:在/etc/hosts里写上三台机器的IP和主机名;把配置文件里fs.defaultFS保持指向node1不变,副本数从1改成3;修改workers文件(Hadoop 3.x中替代了slaves)为另外两个DataNode主机名;在每台机器上配置好SSH免密,确保NameNode能免密登录到所有worker。有了伪分布式的基础,你会发现完全分布式只是把进程拆到不同机器上而已,剩下的问题基本都是网络和权限问题。我见过太多人一上来就搞多节点,遇到问题后在配置文件里反复横跳,最后连哪个节点上哪个进程没起来都分不清。先把单机伪分布式彻底玩明白,再谈扩展。最后分享一个排查问题的小习惯:无论遇到什么异常,第一件事永远是打开/opt/hadoop/logs/目录,找到对应的-xxx.log文件,看最后几十行错误信息。不要盲目重启、不要反复格式化。日志里写得很清楚,只是很多人没养成先看日志的习惯。