
1. 写在动手之前这套单节点集群到底在解决什么问题如果你正在学 Hadoop或者刚进了一家要用大数据技术的公司大概率会遇到一个尴尬节点学习资料一上来就讲分布式集群三台五台起步但手里只有一台电脑虚拟机开两台都卡。更现实的情况是很多 Hadoop 的基础机制——HDFS 的存储原理、MapReduce 的计算流程、YARN 的资源调度——根本不需要一堆机器就能跑通。这篇文章要聊的就是 Hadoop 单节点集群搭建也就是常说的伪分布式模式。所谓“伪”是说它只用一台机器、一套 Java 进程把 NameNode、DataNode、ResourceManager、NodeManager 全部跑在同一台机器上模拟出完整集群的效果。你别看它“伪”学习价值一点不掺水HDFS 的文件上传下载、副本机制、MapReduce 的作业调度、Web UI 监控这些核心功能在单节点模式下和真实集群几乎没有区别。这个方案适合谁来用我觉得至少有三类人第一是刚入门大数据、想在本地快速搭一套能跑通全流程的环境第二是准备 Hadoop 面试需要在简历上写“熟悉 Hadoop 生态独立搭建过集群环境”的求职者第三是做一些课程设计、毕业设计需要用 Hadoop 跑数据分析和统计的在校学生。单节点集群足够应付这些场景等真上了生产环境无非是把配置里的主机名换成 ip把副本数调回三再补齐多台机器的 SSH 互通思路完全一致。我接下来会把整个搭建过程——从环境准备、JDK 安装、配置文件逐项拆解到格式化、启动、跑通第一个 MapReduce 任务再到我踩过的坑——全部摊开讲清楚。这篇是“优化版”除了基础搭建还会把内存参数、异常排查、后续扩展这几个常规教程很少细讲的地方一并补上争取让看完的人不只是敲一遍命令而是真正理解每一条配置是干什么用的。2. 环境与版本选型先把地基打对后面才不返工2.1 操作系统、JDK、Hadoop 的版本搭配逻辑很多教程直接甩给你“Ubuntu 16.04 JDK1.8 Hadoop 2.7.2”就开始装也不解释为什么。等你装完发现版本不兼容或者跑了几年老版本连文档都找不到才意识到版本选型的重要性。我先说结论再解释原因组件推荐版本备选方案操作系统Ubuntu 20.04 / 22.04 LTSCentOS 7.9或其他 Linux 发行版JDKOpenJDK 1.88u372Oracle JDK 8HadoopApache Hadoop 3.3.63.2.4、3.1.4为什么主打 JDK 8 Hadoop 3.x这俩版本的组合是过去五年生产环境验证最充分的搭配。Hadoop 3.x 相比 2.x 有几个硬性升级支持了 NameNode 联邦、引入了基于 erasure coding 的存储优化、MapReduce 的内存模型也做了重构但整体 API 和配置文件 90% 兼容学习成本不会突然拔高。有朋友可能会问JDK 能不能用 11 或 17Hadoop 3.3.x 官方文档确实声称支持 JDK 8 和 11但我实测下来JDK 11 在部分发行版上会遇到 Java 模块化导致的反射访问警告虽然不影响核心功能但排查问题的时候会多一层干扰。作为学习环境稳定压倒一切JDK 8 是最省心的选择。还有一个容易忽略的点安装 Hadoop 时不要用 root 用户。强烈建议单独建一个 hadoop 用户。原因有两层一是 Hadoop 的 DataNode 进程默认会拒绝以 root 身份启动避免权限过高引发安全问题二是统一用户后后面配置 SSH 免密、操作 HDFS 目录权限都会省很多事。这一步很多教程嫌麻烦直接跳过实际上是后面一系列 permission denied 问题的根源。2.2 JDK 安装与环境变量配置别让 PATH 坑你一整天JDK 安装没什么花活但环境变量配置值得多说两句。sudo apt update sudo apt install -y openjdk-8-jdk安装完成后先确认安装路径readlink -f $(which java)我这边得到的路径是/usr/lib/jvm/java-8-openjdk-amd64记下来待会儿要用。接着编辑用户环境变量文件vim ~/.bashrc在文件末尾追加这一段export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export PATH$JAVA_HOME/bin:$PATH export HADOOP_HOME/opt/hadoop export PATH$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop我把HADOOP_HOME和环境变量一起写了因为这一步早晚要做提前配置好省得改两遍。这里有一个很多人容易犯的错只改了/etc/profile忘了改用户级环境变量或者改完不执行source ~/.bashrc导致终端里java -version能出来、hadoop version却找不到命令。执行source ~/.bashrc java -version看到 openjdk version 1.8.0_xxx 就说明 JDK 部分终于稳了。2.3 SSH 免密登录单节点也要认真配为什么单节点还需要 SSH 免密因为 Hadoop 的守护进程之间需要通过 SSH 进行通信比如启动脚本会用ssh登录到每个节点去拉起进程。即使是本机也会走一遍 localhost 的 SSH 通道。如果你跳过这步后面start-dfs.sh执行时会反复要求输入密码极其烦躁。配置流程三步走ssh-keygen -t rsa -P -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys-P 的意思是私钥不设置密码这样 SSH 连接时不需要交互。生成完成后验证一下ssh localhost第一次连接会提示确认指纹输入 yes如果能直接进到 shell 而不是让你输密码就说明免密配置成功。顺手把~/.ssh/config配一下更省心Host localhost HostName 127.0.0.1 User hadoop StrictHostKeyChecking noStrictHostKeyChecking no是为了避免后面 Hadoop 脚本首次连接时卡在指纹确认上。安全上这点瑕疵对于学习环境无伤大雅生产环境建议保持默认 yes。2.4 Hadoop 安装包准备下载、解压、目录规划Hadoop 的下载源国内有很多镜像Apache 官方、清华镜像、阿里镜像都行。我一般用清华镜像源速度快且稳定wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz解压到/opt下并设置软链这样后续切换版本不用改路径sudo tar -zxvf hadoop-3.3.6.tar.gz -C /opt cd /opt sudo ln -s hadoop-3.3.6 hadoop sudo chown -R hadoop:hadoop /opt/hadoopchown那一步不可省略。我之前有一次没改属主结果 Hadoop 启动时日志目录写不进去报了一堆权限错误排查了半天才发现是自己的疏忽。目录规划上我建议严格遵循默认的$HADOOP_HOME结构不要自己乱改目录名因为 Hadoop 内部很多脚本和配置都是相对路径引用改乱了后面维护很痛苦。到这里地基部分完成。接下来进入重头戏——四个核心配置文件的逐项拆解。3. Hadoop 核心配置文件逐个拆解每一行参数都要心里有数Hadoop 的配置集中在$HADOOP_HOME/etc/hadoop目录下。单节点集群模式下需要改动的文件正好四个core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml。另外还有两个辅助文件hadoop-env.sh和workers。我一个个说。3.1 core-site.xml集群的全局大脑core-site.xml里最核心的配置是fs.defaultFS它决定了 HDFS 的访问入口也就是 NameNode 的地址和端口。默认文件系统的写法是file:///表示本地文件系统我们要改成hdfs://协议。configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop/tmp/value /property /configurationhadoop.tmp.dir是我特意要拎出来说的一个参数。Hadoop 的 NameNode、DataNode 等进程会把元数据、数据块索引、日志等存放在这个目录下。默认值指向/tmp/hadoop-${user}而系统/tmp目录在部分 Linux 发行版下会被定期清理一旦清理导致元数据丢失NameNode 格式化后的信息就全没了整个集群等于废掉重来。我见过不止一个新手因为这个问题被迫重新格式化。这里改成/opt/hadoop/tmp并记得手动创建目录mkdir -p /opt/hadoop/tmp如果你计划后续升级到高可用集群还可以顺手把ha.zookeeper.quorum等参数预留出来但单节点阶段不需要配写了反而画蛇添足。3.2 hdfs-site.xml数据怎么存、存几份、NameNode 在哪这个文件的每个参数都直接决定了 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 value1/value /property property namedfs.namenode.http-address/name valuelocalhost:9870/value /property /configuration先讲dfs.replication副本数。生产环境默认是 3因为数据需要跨节点冗余存储。但我们只有一个节点如果硬设成 3DataNode 上报可用副本数不足NameNode 会进入安全模式显示There are 0 datanode(s) running and 1 node(s) are excluded实际上就是集群因为副本数不满足阈值拒绝服务。单节点必须设为 1这一点新手最容易踩坑。dfs.namenode.name.dir和dfs.datanode.data.dir分别指定 NameNode 元数据和 DataNode 实际数据块的存储位置。这里的file:///协议是指本地磁盘路径注意不要写错。我单独指到/opt/hadoop/tmp下是为了配合前面hadoop.tmp.dir统一管理。端口方面dfs.namenode.http-address是 NameNode 的 Web UI 端口。注意 Hadoop 3.x 默认是 9870不是 2.x 时代的 50070。经常有照着老教程配置的人发现网页打开 50070 一片空白就是这个原因。既然是单节点hostname 写localhost完全没问题生产环境则要改成具体主机名。3.3 mapred-site.xml 和 yarn-site.xml计算框架的运转规则在 Hadoop 3.x 中mapred-site.xml不再是默认存在需要从模板复制一份cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xml它的核心配置是指定 MapReduce 作业提交给哪个资源调度框架configuration property namemapreduce.framework.name/name valueyarn/value /property /configuration这个配置的意思是让 MapReduce 作业跑在 YARN 之上。YARN 是 Hadoop 2.x 之后引入的资源管理器它把计算资源抽象成容器Container由 ResourceManager 统一分配。如果把mapreduce.framework.name设为local作业就会以本地模式在单 JVM 内运行速度很快但无法体验 YARN 的调度过程。学习阶段一定要用yarn这样才能在 ResourceManager 的 Web UI 上观察到作业状态。yarn-site.xml配置如下configuration property nameyarn.resourcemanager.hostname/name valuelocalhost/value /property property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/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_MAPRED_HOME/value /property /configurationyarn.resourcemanager.hostname指定 ResourceManager 所在节点单节点写 localhost。yarn.nodemanager.aux-services这个参数新手往往看不明白是干什么的。它的作用是启用 NodeManager 的辅助服务MapReduce 的 Shuffle 阶段需要这个服务来传输 map 输出数据给 reduce 任务。如果不配这一项作业会在 Shuffle 阶段报错Shuffle errored典型症状就是 map 跑完 100% 后 reduce 一直不动最终整个作业失败。我之前第一次搭集群时没配这项折磨了一个下午。yarn.nodemanager.env-whitelist是我特意加的。Hadoop 3.x 中 NodeManager 为了安全性默认不把客户端的环境变量透传给容器如果JAVA_HOME、HADOOP_HOME这些没有加入白名单运行 MapReduce 时容器内部找不到 Java 环境和 Hadoop 依赖库会报一串ClassNotFoundException。这个参数在 Hadoop 2.x 时代还叫yarn.nodemanager.admin-env老教程经常互相抄错你如果发现网上有写法不一致以 3.x 为准。3.4 hadoop-env.sh 与 workers 文件容易被忽略的收尾配置hadoop-env.sh中必须确认一件事JAVA_HOME是否有值。Hadoop 在某些环境下无法自动探测 JDK 路径手动指定最保险echo export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 $HADOOP_HOME/etc/hadoop/hadoop-env.shworkers文件Hadoop 3.x 之前叫slaves用于声明哪些节点作为 DataNode 和 NodeManager。单节点模式下内容只有一行localhost配置完成后检查一下整个配置目录的所有 XML 是否语法正确。XML 解析错误会在启动阶段直接报错但报错信息往往不直观提前用xmllint检查能省不少时间for f in $HADOOP_HOME/etc/hadoop/*.xml; do xmllint --noout $f; done如果没有输出说明 XML 全部可解析。这一步做好心理准备后面启动基本都是一遍过。4. 初始化、启动与首跑验证让整个集群活起来4.1 格式化 NameNode一次性的关键操作配置文件全部就绪之后第一步不是启动而是格式化 NameNode。格式化的作用是在dfs.namenode.name.dir指定的目录下初始化元数据存储结构。执行命令hdfs namenode -format执行过程中会打印大量日志看到类似Storage directory /opt/hadoop/tmp/dfs/name has been successfully formatted就说明成功了。最后会问Re-format filesystem in Storage Directory ... ? (Y or N)输入 Y。这里有个重要的操作纪律格式化操作通常只做一次。如果集群运行一段时间后你再次执行格式化会因为 NameNode 的 clusterID 与 DataNode 的 clusterID 不一致导致 DataNode 无法注册报错Incompatible clusterIDs。强制重格式化的前提是确认数据无所谓、整个环境需要推到重来。如果你只是配置改错了不需要重新格式化。4.2 启动 HDFS 与 YARN 的完整过程启动命令是 Hadoop 自带的脚本分别负责 HDFS 和 YARNstart-dfs.sh start-yarn.shstart-dfs.sh会依次拉起 NameNode、DataNode、SecondaryNameNode。单节点会有三个进程。start-yarn.sh拉起 ResourceManager 和 NodeManager。启动完成后用jps命令检查进程状态jps一个健康的状态应该看到以下五个进程进程名角色对应模块NameNodeHDFS 元数据管理HDFSDataNode数据块存储HDFSSecondaryNameNode元数据检查点合并HDFSResourceManagerYARN 资源调度YARNNodeManager单节点任务执行YARN如果少了其中任何一个先用tail -f $HADOOP_HOME/logs/*.log看对应日志多半能在日志里定位到问题。日志文件非常多我习惯先ls -t $HADOOP_HOME/logs/ | head找到最新文件再 tail。4.3 Web UI 检查和 HDFS 基础读写验证进程都起来了不代表集群真的可用必须做功能验证。先从 Web UI 看起NameNode UI:http://localhost:9870ResourceManager UI:http://localhost:8088在 NameNode UI 上重点看 Datanodes 那一栏正常应该显示1 live或1 Live Nodes。如果显示 0 个 live 节点说明 DataNode 没注册上要去 logs 目录翻hadoop-hadoop-datanode-*.log找原因。然后做 HDFS 的目录操作和文件读写测试hdfs dfs -mkdir -p /user/hadoop hdfs dfs -put $HADOOP_HOME/etc/hadoop/core-site.xml /user/hadoop/ hdfs dfs -cat /user/hadoop/core-site.xml | head -5能上传、能读取说明 HDFS 的数据链路通了。顺便看一眼副本状态hdfs dfs -stat %r /user/hadoop/core-site.xml输出 1 表示副本数符合单节点配置。接下来验证 HDFS 的 Web UI 上文件块信息。这些操作虽然简单但每做一个都在验证不同层的功能是否正常别嫌繁琐一步到位能帮你省去后面排查的舍近求远。4.4 跑一个 MapReduce 样例验证计算链路HDFS 通了最后还要验证 YARN 上的计算链路。Hadoop 自带的pi计算任务是个很好的验证工具hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi 4 1000这个命令会用蒙特卡洛方法估算圆周率4是 map 数1000是每次采样的次数。作业提交后去 ResourceManager UI 的Active Applications应该能看到 RUNNING 状态的作业点击进去能看到详细的 Task 进度。执行过程中会打印类似这样的信息Job Running... (state: RUNNING) Job Finished in xxx ms Estimated value of Pi is 3.14250000000000000000看到 Pi 的估算值出来就说明 MapReduce 的完整链路——提交、拆分、调度、执行、归约——全部通畅。到这个节点一个可用的单节点集群就已经搭建完成了。但离“优化版”标题还差一块就是接下来的参数调优和避坑经验。5. 参数调优与后续扩展学完基础再往深处走一步5.1 内存怎么分配从默认值到合理调整Hadoop 的默认内存参数往往是“够运行但不好用”。单节点学习环境下最常见的问题是作业跑的数据量稍微一大NodeManager 分配给容器的内存不够用表现为任务卡死或直接被 kill。核心调整参数集中在yarn-site.xmlproperty nameyarn.nodemanager.resource.memory-mb/name value8192/value /property property nameyarn.scheduler.maximum-allocation-mb/name value4096/value /property property nameyarn.scheduler.minimum-allocation-mb/name value512/value /property这三个参数分别控制 NodeManager 总可用内存、单个容器最大内存、单个容器最小内存。简单打个比方NodeManager 像一个装了 8G 内存条的主机每个容器像上面跑的独立进程最大分配到 4G最小不低于 512M。mapred-site.xml中还需要对应调整 Map/Reduce 任务的内存property namemapreduce.map.memory.mb/name value1024/value /property property namemapreduce.reduce.memory.mb/name value2048/value /property注意这里的逻辑关系mapreduce.map.memory.mb不能超过yarn.scheduler.maximum-allocation-mb否则容器申请会被拒绝。一个常见配置会让 map 任务 1G、reduce 任务 2G在 8G 机器的单节点集群上能跑得很舒服。如果你的机器内存只有 4G把resource.memory-mb调到 4096maximum-allocation-mb调到 2048照比例缩小即可。提示修改这些参数后必须重启 YARN 相关进程才能生效不用重新格式化 NameNode。5.2 副本数、回收站、临时目录等实用参数补充除开内存还有几个参数在实际使用中非常重要。回收站配置。HDFS 默认删文件是真正的物理删除没有回收站兜底手滑删了只能干瞪眼。在core-site.xml里加这段property namefs.trash.interval/name value1440/value /property单位是分钟1440 即 1 天删除的文件在/user/hadoop/.Trash下保留 1 天期间可以通过hdfs dfs -mv命令找回。这个配置成本极低但价值极大建议不管学习还是后续扩展集群都第一时间配好。NameNode 元数据目录备份。我之前在hdfs-site.xml里配过一个 name dir其实可以配多个路径用英文逗号分隔property namedfs.namenode.name.dir/name valuefile:///opt/hadoop/tmp/dfs/name,file:///opt/hadoop/namenode-backup/value /propertyNameNode 会把元数据镜像同时写到两个目录相当于做了一层冗余。单节点学习环境里考虑的是磁盘故障风险多一重保险多一份安心。5.3 从单节点到分布式未来扩展的衔接点单节点集群的价值不仅仅是学习它还是迈向分布式的一个重要跳板。我聊几个你以后大概率用得到的扩展方向。第一是加节点。从单节点变成真正的多节点集群核心工作不外乎四件事新机器装好 JDK 和 Hadoop、配置好 SSH 互通、修改主节点的workers文件加入新节点、复制整套配置到所有节点并修改 hostname 相关的参数。没有额外的学习成本单节点模式下养成的配置习惯全部能复用。第二是引入高可用HA。在 Hadoop 2.x 之后生产环境的标配是双 NameNode ZooKeeper 做自动故障切换。这个架构里的journalnode用于共享 edit logzkfc用于监控 NameNode 健康状态并触发切换。你把单节点上的目录结构和命名习惯理顺了后面加 HA 时只是多配几个组件不会推翻重学。第三是接入 Hive、Spark 等上层组件。Hive 依赖 HDFS 存储表数据Spark 可以跑在 YARN 之上。单节点一样能装 Hive 跑几条 SQL能起 Spark Shell 做几个 RDD 操作对于学习整个大数据生态完全够用。我见过有人在单节点上把 Flink SQL、Hudi 都跑通了链路并不比集群差多少。5.4 与 ZooKeeper 整合的思路好多热词里面提到“hadoop和zookeeper整合实战”我再补充说一下这个方向。ZooKeeper 自身是一个独立的分布式协调服务不依赖 Hadoop 也能跑。Hadoop 中使用 ZooKeeper 主要是两个场景一是 NameNode 高可用HA模式下用于选主和状态共享二是有些任务比如 HBase会用它来协调 RegionServer 的分配和元数据管理。单节点环境如果想提前感受 ZooKeeper 整合可以直接下载 tarball 解压跑起来配置一个zoo.cfg文件然后改core-site.xml中 HA 相关参数。虽然单个 ZK 节点起不了真正的选主作用但理解它的整体工作模式是够用的。这里提醒一句ZooKeeper 有自己的端口配置默认 2181注意不要跟 Hadoop 的端口打架。学的时候把 ZooKeeper 独立跑理解它的节点模型和数据树再来谈整合思路会清晰很多。6. 常见问题与排查技巧实录我踩过的那些坑6.1 启动失败进程起不全先从日志切入最常见的一个场景是执行start-dfs.sh后NameNode 起来了DataNode 却反复退出。这种情况 90% 的根源在于 clusterID 不一致——你格式化 NameNode 之前DataNode 的数据目录已经存在旧的 clusterID。怎么判断看 DataNode 日志里有没有Incompatible clusterIDs关键字。解决方案有两种取决于数据是否重要保留数据导向找到dfs.datanode.data.dir目录下的VERSION文件把其中clusterID改成 NameNode 那边VERSION文件里的值重启 DataNode。清空重来导向删掉dfs.datanode.data.dir和dfs.namenode.name.dir两个目录重新格式化 NameNode。我实际遇到时的处理方式是既然是学习环境、数据可放弃直接清空重来最干净但想保留测试数据就要用第一种方案步骤也不复杂。6.2 端口占用9870 和 8088 打不开的原因Web UI 打不开先说三个高频原因。第一是服务本身没起来。用jps先确认进程在不在。第二是端口被防火墙拦截。Ubuntu 默认 ufw 未启用一般没有这个问题但如果你执行过ufw enable需要放行sudo ufw allow 9870 sudo ufw allow 8088第三是端口被别的进程占用。有时候你改了配置但没重启端口被旧进程持有新进程绑定失败。排查命令netstat -tlnp | grep -E 9870|8088|9000如果看到端口被某个非 Java 进程占用多半是配置文件里的端口写错了或者本机运行了什么其他应用。6.3 格式化报错权限、目录不存在、重复格式化格式化 NameNode 时最常见的报错就是Permission denied因为/opt/hadoop/tmp目录的属主不是当前用户。解决方法就是前面提过的sudo chown -R hadoop:hadoop /opt/hadoop还有一种情况是报NameNode is already formatted说明目录下已经有格式化的元数据。如果你是第一次执行检查一下是否之前用 root 或者别的用户执行过格式化导致目录属主变了。6.4 作业运行异常容器被杀、Shuffle 失败跑 MapReduce 样例时如果作业刚开始没多久所有任务都显示 KILLED去 ResourceManager UI 里看日志通常会看到Container killed by the ApplicationMaster和memory关键字。这是内存超卖问题NodeManager 可分配内存低于容器请求内存的 1.5 倍左右触发保护机制杀容器。解法就是回到 5.1 节说的把yarn.nodemanager.resource.memory-mb调大或者把单个容器的内存调小。我这里遇到的一次典型情况是mapreduce.map.memory.mb和mapreduce.reduce.memory.mb加起来超过了 NodeManager 总内存按比例缩一圈就恢复正常了。如果是 Shuffle 阶段的Shuffle error先检查yarn.nodemanager.aux-services是不是mapreduce_shuffle。还有一个小概率原因yarn.nodemanager.env-whitelist没配好导致容器里找不到 Hadoop 类库。这个报错信息往往很长开头就是ClassNotFoundException: org.apache.hadoop.mapreduce...看到这个字样直接往环境变量白名单方向排查就好。6.5 免密登录失效重启后要重新配吗SSH 免密配置一次生效正常情况下不需要重新配置。但如果哪一天突然发现ssh localhost又要输入密码了大概率是~/.ssh目录或authorized_keys文件的权限被人为改过。SSH 对权限非常敏感chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys另外一个低频场景是更换了机器或重装了系统密钥对丢了那就需要重新生成一遍。这种情况好判断直接看~/.ssh/id_rsa是否存在即可。6.6 安全模式下卡住为什么文件只能读不能写节点启动后偶尔会发现 HDFS 处于安全模式Safe mode表现是不能创建目录、不能上传文件但读取正常。原因通常是dfs.replication配置值与实际可用 DataNode 数量不匹配NameNode 等待至少一个副本上报完成才离开安全模式。单节点下如果副本数没改成 1必然卡安全模式。如果你确认配的是 1但启动后 HDFS 仍然安全模式超过 30 秒可以试着手动退出hdfs dfsadmin -safemode leave如果退出后立刻又回到安全模式说明 NameNode 认为可用 DataNode 数不足去 DataNode 日志排查比在这里硬等更有效。最后说点我的体会搭一套 Hadoop 单节点集群顺利的话四十分钟能跑通全流程但真正有价值的是你理解每一步在干什么。记得我最初学 Hadoop 时觉得配置文件就是抄一遍哪天报错了就百度换一个参数试试结果问题越解越多。后来一个前辈跟我说了一句话我记到现在“你配的每一行参数都在决定一个进程的行为。”从那之后我再也没跳过配置文件说明每写一行就问自己这个值是干什么的改大了会怎样、改小了会怎样。这套单节点集群搭建完成后别急着删了重来建议故意制造几个故障比如把副本数改回 3 再启动、把回收站关掉删一个文件再想办法修好。这个过程对理解 Hadoop 的机制作用很大。另外一个小建议养成写完配置就备份的习惯比如说给hdfs-site.xml加个.bak文件。我实际排查问题时经常改来改去最后忘了哪份是原版、改过哪里有备份就随时能对比 diff一分钟定位变化点。这个习惯我直到今天都在用比什么高级技巧都实在。