1. 为什么值得在Windows上搭一套Hadoop伪分布式
我最早接触Hadoop是在一台只有Windows系统的旧笔记本上。那会儿手头没有多余的机器装Linux,虚拟机跑起来风扇跟起飞一样,只能硬着头皮在Windows上把Hadoop伪分布式折腾起来。前前后后重装过七八次,从2.x版本一路踩到3.x,配置文件改烂过、NameNode格式化过好几遍、DataNode启动三秒就自杀的情况遇到过不止一次。这篇就当作我的搭建复盘,把每一步“为什么要这么做”和“哪里最容易翻车”都写清楚,你照着走能少走不少弯路。
先把概念摆正。Hadoop伪分布式模式,指的是在同一台物理机上同时拉起NameNode、DataNode、ResourceManager、NodeManager这几个角色进程,数据真正写进HDFS而不是本地磁盘,只不过所有“节点”都挤在一台机器上。它和“本地模式”的核心区别在存储层:本地模式下跑MapReduce完全不碰HDFS,输入输出都是Windows本地路径,fs.defaultFS还是file:///;伪分布式下你put进去的文件会被切成真正的block,落到你指定的数据目录里,副本因子、心跳机制、Web UI、YARN调度这些完整链路都能实际走一遍。
对学习来说这个价值很大。真集群动辄三台起步,配置SSH免密、时间同步、hostname映射,光是环境对齐就能劝退一批人。伪分布式把这部分复杂度砍掉,让你先把HDFS的读写路径、YARN的作业提交流程、配置项之间的依赖关系搞清楚。等这些弄明白了再去搭真集群,你会发现多出来的无非是网络和同步的问题,核心心智模型是一样的。
这套东西适合谁?我的判断是三类人:一是刚接触大数据组件、想在本机把链路跑通的学生和转行者;二是需要临时验证某个MapReduce逻辑、不想每次连公司集群的后端开发;三是想把Hadoop当成教学演示环境的讲师。如果你只是想跑个Spark或者Flink,那其实没必要专门搭Hadoop,直接用本地模式或者Standalone就行。但只要你的学习目标里包含“理解HDFS怎么存数据”和“理解YARN怎么调度作业”,伪分布式就是绕不开的一环。
在Windows上做这件事,本质上是在跟平台的先天差异较劲。Hadoop的原生设计假设是类Unix环境:脚本是.sh、路径分隔符是/、权限模型是POSIX那一套、文件名大小写敏感。Windows这边脚本变成.cmd、路径是反斜杠、还有盘符概念。所以整个搭建过程有一大半精力花在“补平台差异”上,而不是Hadoop本身。想清楚这一点,后面遇到报错心态会好很多——不是你的操作有问题,是这两个世界本来就不完全兼容。
2. 环境准备:版本选型和几个前置依赖
2.1 JDK版本怎么定,别一上来就用最新的
这一步我吃过亏。第一次搭的时候图省事,装了当时最新的JDK,结果Hadoop启动脚本里一堆反射相关的警告,某些类加载直接失败。后来老老实实退回JDK 8才顺。
版本搭配这件事有明确的对应关系,我整理成下面这张表,你可以直接对照:
| Hadoop版本 | 推荐JDK | 说明 |
|---|---|---|
| 2.7.x | JDK 8 | 最稳,资料最多,但生态偏老 |
| 3.1.x - 3.2.x | JDK 8 | 兼容性最好,新手首选 |
| 3.3.x | JDK 8 / JDK 11 | JDK 11下部分脚本需要额外改,JDK 8更省心 |
| 3.4.x | JDK 8 / JDK 11 | 同上,伪分布式场景建议还是JDK 8 |
我个人的选择是Hadoop 3.3.x + JDK 8。理由很实在:3.3是3.x系列里比较成熟的一个版本,Web UI端口已经统一到9870,文档齐全;JDK 8对Windows的支持最完善,不会出现奇怪的模块化报错。
注意:安装JDK的路径里绝对不能有空格。默认的
C:\Program Files\Java\...就是一颗地雷,Hadoop的启动脚本在拼接路径时不会给你加引号,路径一带空格整个命令就断了。我一般直接装到D:\Java\jdk1.8.0_xxx这种干净路径下。
装完记得验证:
java -version输出的版本号里带1.8.0就对了。顺便把JAVA_HOME配好,指向JDK根目录而不是bin目录,这个细节很多人会搞错。
2.2 Hadoop安装包从哪来,解压到哪
官方下载站给的是tar.gz包,Windows下用解压工具解开就行,不需要额外编译。解压位置同样遵循“路径无空格、无中文”的原则。我习惯放在D:\hadoop\hadoop-3.3.6,这样后面配环境变量的时候不容易出错。
目录规划上我会额外建两个文件夹,一个放临时数据,一个放HDFS的实际存储:
D:\hadoop\ ├─ hadoop-3.3.6\ # 解压出来的主目录 ├─ data\ │ ├─ namenode\ # NameNode元数据 │ └─ datanode\ # DataNode数据块 └─ tmp\ # hadoop.tmp.dir为什么要单独把data和tmp拆出来?因为hadoop.tmp.dir默认指向系统临时目录,Windows的临时目录是会被清理的,某天重启完发现集群起不来、元数据全没了,那酸爽我体验过一次。显式指定到自己的目录下,格式化之后就别再动它。
2.3 winutils和hadoop.dll:Windows上绕不开的一块补丁
这是整个搭建过程中最容易被忽略、也最容易在后期爆雷的一环。Hadoop的某些功能依赖native库,官方发布的二进制包是给Linux编译的,Windows下缺两个关键文件:winutils.exe和hadoop.dll。
winutils.exe是一组Windows下的文件操作命令封装,Hadoop在启动时会去%HADOOP_HOME%\bin下面找它,找不到就抛那句经典的:
Failed to locate the winutils binary in the hadoop binary path这句话本身不一定导致启动失败,但后面涉及权限检查、目录创建的操作都会受影响。
hadoop.dll更要紧,缺了它,运行MapReduce作业时会报:
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0这个错一旦出现,作业是百分百跑不起来的。
解决办法是去社区维护的Windows构建仓库里,找到和你Hadoop版本号完全对应的winutils包,把winutils.exe、hadoop.dll等文件复制到%HADOOP_HOME%\bin下面。版本号必须严格对应,3.3.6的Hadoop配2.7的winutils,大概率还是报错。
hadoop.dll还有一步:复制一份到C:\Windows\System32,或者把它所在目录加进PATH。我倾向于直接拷到System32,简单粗暴,省得每次排查PATH。
提示:这一步我建议在装完Hadoop之后立刻做,不要等到跑作业的时候再补。很多教程把这段放到最后,结果前面一路顺畅,到最后一步突然卡住,排查起来反而更费时间。
2.4 环境变量:四个必须配的,一个建议配的
环境变量这块我把踩过的坑整理成一张表:
| 变量名 | 值示例 | 作用 | 常见问题 |
|---|---|---|---|
JAVA_HOME | D:\Java\jdk1.8.0_301 | 定位JDK | 指向bin目录导致找不到java |
HADOOP_HOME | D:\hadoop\hadoop-3.3.6 | 定位Hadoop | 路径含空格,脚本解析断裂 |
HADOOP_CONF_DIR | %HADOOP_HOME%\etc\hadoop | 指定配置目录 | 不配也能跑,但多版本共存时必配 |
PATH | 追加%HADOOP_HOME%\bin | 让hadoop命令全局可用 | 忘了追加,只能在bin目录下执行 |
HADOOP_USER_NAME | 你的Windows用户名 | 覆盖 HDFS 用户名 | 用户名含中文时建议显式设成英文 |
最后一条值得多说两句。Hadoop在Windows下会用当前登录用户名去访问HDFS,如果你的Windows账户名是中文,或者带空格,HDFS里会建出对应的中文目录,后续执行命令时可能出现路径解析异常。我一般直接把HADOOP_USER_NAME设成一个纯英文的值,比如hadoopuser,规避掉这个问题。
配完这些,开个新的命令行窗口(这点很重要,旧窗口读不到新环境变量),敲:
hadoop version能打印出版本号和编译信息,环境这块就算过了。
3. 四个XML加一个CMD:配置文件逐个拆解
3.1 core-site.xml:告诉Hadoop文件系统在哪
所有配置文件都在%HADOOP_HOME%\etc\hadoop下面。先说core-site.xml,这是核心入口配置,伪分布式下最关键的就两项:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>D:/hadoop/tmp</value> </property> </configuration>fs.defaultFS是全局默认文件系统。写hdfs://localhost:9000,Hadoop就知道所有没带协议的路径都要走HDFS,NameNode在本地9000端口。这里的localhost我建议始终写主机名而不是IP,因为后面DataNode注册节点标识时用的也是主机名,两边不一致会出现DataNode能起来但NameNode认不到的情况。
hadoop.tmp.dir是Hadoop所有临时文件的根目录,包括NameNode、DataNode在一些默认配置下的存储位置。默认值指向%TEMP%,容易被清理,一定要显式改到自己规划的目录。
注意:路径分隔符在XML里统一用正斜杠
/,别用反斜杠。虽然Windows能认,但Hadoop内部解析时偶尔会把它当转义符处理,写成D:\\hadoop\\tmp反而容易出问题。
3.2 hdfs-site.xml:副本因子和存储目录
hdfs-site.xml管的是HDFS自身的存储行为,伪分布式下有两组配置必改:
<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///D:/hadoop/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///D:/hadoop/data/datanode</value> </property> </configuration>dfs.replication必须设成1。这不是可选项。默认值是3,伪分布式只有一个DataNode,你上传一个文件,HDFS会认为它应该有3份副本,实际只有1份,于是永久处于“副本不足”状态。这个状态不会让读写失败,但每次hdfs fsck都会给你刷一屏警告,新手看到容易以为出事了。我见过有人为了消掉警告,硬凑了三个目录塞给dfs.datanode.data.dir,让一个DataNode模拟三个存储位置。能消警告,但完全没必要,教学环境下设成1最清爽。
另外两个目录的file:///前缀不能少,它表示本地文件系统协议。少了这个前缀,Hadoop会把D:/...当成HDFS内的相对路径,结果就是格式化的时候在你意料之外的地方建目录。
3.3 mapred-site.xml和yarn-site.xml:把计算框架接到YARN上
这两个文件决定了你后面能不能跑MapReduce作业。
mapred-site.xml:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>就这一项,意思是MapReduce作业交给YARN调度。不配这个,作业会走local runner,在本地起JVM跑完就结束,根本不会经过ResourceManager,那伪分布式的意义就丢了一大半。
yarn-site.xml稍微多一点:
<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name> <value>org.apache.hadoop.mapred.ShuffleHandler</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>4096</value> </property> </configuration>第一项是辅助服务,MapReduce的shuffle阶段依赖它,不配的话作业会卡在map完成之后迟迟不进入reduce。第二项是具体实现类,通常默认就有,但显式写出来更保险。
第三项resource.memory-mb是很多人忽略的。它的默认值比较大(8192MB),如果你的笔记本只有8G内存,YARN一启动就把可用内存算得很足,真正跑作业时系统直接卡死。按你实际物理内存的六成左右来设比较稳妥,8G内存的机器设4096,16G可以设8192。这个不是越小越好,设太小会导致作业申请不到容器,报“Container is running beyond physical memory limits”。我第一次设成2048,结果一个简单的WordCount都跑不起来,改回4096才正常。
3.4 hadoop-env.cmd:Windows上的JAVA_HOME要单独改
这个文件容易被跳过,但它特别重要。etc/hadoop目录下同时存在hadoop-env.sh和hadoop-env.cmd,Windows上真正生效的是后者。打开hadoop-env.cmd,找到这一行:
set JAVA_HOME=%JAVA_HOME%看起来没问题,但实际执行时这个变量经常读不到,特别是你的JAVA_HOME是在用户变量里配的、而命令行以管理员身份运行的时候。我的做法是直接写死:
set JAVA_HOME=D:\Java\jdk1.8.0_301写死的好处是稳定,坏处是以后换JDK要回来改。教学环境里我选稳定。
同一个文件里还有两处可以顺手调一下,一个是日志目录,默认在%HADOOP_HOME%\logs,可以保留;另一个是HADOOP_OPTS里的编码参数。Windows控制台默认是GBK,Hadoop输出中文日志时会乱码,加上:
set HADOOP_OPTS=%HADOOP_OPTS% -Dfile.encoding=UTF-8日志里的中文就正常了。这一点不影响功能,但排查问题的时候,看得懂日志比看不懂强太多。
4. 格式化、启动与双路验证
4.1 第一次格式化NameNode,这一步只能做一次
所有配置改完,接下来是格式化。打开命令行执行:
hdfs namenode -format成功的话会看到一大段日志,结尾附近有Storage directory ... has been successfully formatted。看到这句就对了。
这一步很容易被误解,必须讲清楚:格式化是在NameNode的存储目录里建立一套初始的元数据结构,包括clusterID、namespaceID、fsimage这些。它不会碰你的数据,但它会把dfs.namenode.name.dir下面的内容重建。所以:
- 第一次装,必须格式化
- 已经跑过一段时间、里面有数据,绝对不能重新格式化
- 如果非要重来,先把namenode目录和datanode目录都清空,再格式化
我见过有人在集群起不来的时候下意识又跑一遍format,结果元数据清了但DataNode目录里的clusterID还是旧的,两边对不上,DataNode启动后立刻退出。这个问题后面排查章节会细说。
还有一个坑:格式化的时候,控制台可能会打出一堆WARN,但真正决定成败的是最后那行有没有successfully formatted。别被中间的警告吓到,只要没有ERROR和异常堆栈,基本就是成功的。
4.2 启动脚本:sbin目录下的.cmd文件
Windows下的启动脚本在%HADOOP_HOME%\sbin,一共四个:start-dfs.cmd、start-yarn.cmd、stop-dfs.cmd、stop-yarn.cmd。
执行start-dfs.cmd,会弹出新的命令行窗口,分别对应NameNode、DataNode、SecondaryNameNode三个进程。这里有个Windows特有的现象:关掉那个黑窗口,进程就直接被杀掉,不像Linux下后台daemon那样脱离终端。所以启动之后别手贱去点关闭,最小化放着就行。
start-yarn.cmd同理,会弹出ResourceManager和NodeManager两个窗口。
验证进程有没有真的起来,最直接的办法是开一个新窗口敲:
jps正常情况下应该能看到:
| 进程名 | 对应角色 |
|---|---|
NameNode | HDFS 元数据管理 |
DataNode | HDFS 数据块存储 |
SecondaryNameNode | 元数据检查点 |
ResourceManager | YARN 资源调度 |
NodeManager | YARN 单节点管理 |
Jps | 查询工具自身 |
五个都齐了才算完整。少一个就要去看对应的日志,日志在%HADOOP_HOME%\logs下面,文件名格式是hadoop-用户名-角色名-主机名.log,按时间排序找最新的那个看。
4.3 Web UI和命令行双路验证
进程起来了不代表服务可用,还得验证端口。Hadoop 3.x的默认端口和2.x不一样,这点网上很多老教程还在用9870之前的数字,容易误导:
| 服务 | Hadoop 2.x | Hadoop 3.x |
|---|---|---|
| NameNode UI | 50070 | 9870 |
| DataNode UI | 50075 | 9864 |
| SecondaryNameNode | 50090 | 9868 |
| ResourceManager | 8088 | 8088 |
浏览器打开http://localhost:9870,能看到HDFS的概览页面,重点看两个地方:一是Overview里的Live Nodes是不是1,二是Utilities里的Browse the file system能不能点进去。Live Nodes是0的话,说明NameNode起来了但DataNode没注册上,这时候去DataNode的日志里找Registration相关的行。
http://localhost:8088是YARN的界面,能看到集群资源总量、运行中的作业列表。刚启动的时候作业列表是空的,这正常。
命令行这边验证一下HDFS能不能写:
hdfs dfs -mkdir -p /test hdfs dfs -ls / hdfs dfs -put D:\somefile.txt /test hdfs dfs -cat /test/somefile.txt四条命令依次走通,说明HDFS的读写链路是通的。如果-put那一步报Permission denied,多半是HADOOP_USER_NAME没设或者设成了不认识的值,退回去检查环境变量。
5. 跑通第一个MapReduce:WordCount实操
5.1 准备输入数据
Hadoop自带了一个示例jar包,在%HADOOP_HOME%\share\hadoop\mapreduce\下面,名字类似hadoop-mapreduce-examples-3.3.6.jar。里面的wordcount是最适合做首次验证的,逻辑简单、输出直观。
先在本地准备一个文本文件,随便写几行英文,比如:
hadoop windows pseudo distributed hadoop hdfs yarn windows hdfs block保存为D:\input\words.txt。注意不要用中文内容做首次测试,中文分词和编码问题会混进来,增加排查难度。等英文跑通了再试中文也不迟。
然后传到HDFS:
hdfs dfs -mkdir -p /wordcount/input hdfs dfs -put D:\input\words.txt /wordcount/input hdfs dfs -ls /wordcount/input最后一条命令能看到文件列表,就说明上传成功。
提示:输出目录必须不存在。WordCount会在作业开始时检查输出路径,如果
/wordcount/output已经存在,作业会直接失败并报Output directory ... already exists。这是Hadoop的保护机制,防止覆盖已有结果。每次重跑之前记得先hdfs dfs -rm -r /wordcount/output。
5.2 提交作业并观察执行过程
提交命令:
hadoop jar %HADOOP_HOME%\share\hadoop\mapreduce\hadoop-mapreduce-examples-3.3.6.jar wordcount /wordcount/input /wordcount/output回车之后,控制台会刷出一大段日志。新手看到这么多输出容易慌,实际上只需要盯几个关键节点:
先是Running job: job_xxxxxxxxxxxx_0001,这行出现说明作业已经成功提交到ResourceManager,拿到了jobId。如果卡在这一步不动,说明YARN那边有问题,去ResourceManager的日志里找。
然后是map 0% reduce 0%开始的进度条。伪分布式下这个进度刷新会比较慢,因为容器启动本身要花时间,十几秒没变化是正常的。不要在这时候反复Ctrl+C,我看过不少人在这一步以为卡死了,连按几次中断,结果留下一个僵尸作业占着资源。
进度到map 100% reduce 100%之后,会打印统计信息,包含输入记录数、输出记录数、启动的map和reduce任务数量。最后一行是Job job_xxx completed successfully,看到这句就是成了。
5.3 读结果、看日志、理解产物结构
结果在HDFS上,用命令读出来:
hdfs dfs -ls /wordcount/output hdfs dfs -cat /wordcount/output/part-r-00000输出目录里通常有三个东西:
| 文件名 | 内容 |
|---|---|
_SUCCESS | 空文件,标记作业成功 |
part-r-00000 | 实际的reduce输出结果 |
_SUCCESS.crc | 校验文件 |
part-r-00000里的格式是“单词 + 制表符 + 出现次数”,按单词字典序排。这个排序不是巧合,MapReduce的shuffle阶段会对key排序,reduce拿到的输入本来就是有序的。
如果你想看作业执行的细节,去YARN的8088界面,点进那个已完成的作业,能看到每个map/reduce任务的容器分配、执行时长、数据读写量。这部分信息特别有价值,它让你直观看到“一个作业到底消耗了多少资源”。我第一次看的时候才发现,跑三行文本的WordCount也启动了完整的容器,虚拟内存申请了1G多,这才理解为什么YARN的资源参数不能设得太小。
作业结束后,/wordcount/input和/wordcount/output都还在HDFS里,要清理可以手动删。整个流程走通一遍,Hadoop伪分布式的核心链路——提交、调度、执行、落盘——就都跑过了。
6. 常见问题与排查实录
6.1 启动阶段:进程起了又挂,或者压根没起来
症状一:敲hdfs namenode -format报ERROR: JAVA_HOME is incorrectly set。
这是最经典的一个。原因通常是JAVA_HOME里带空格(比如指向C:\Program Files\Java\...),或者hadoop-env.cmd里的写法和实际路径对不上。排查办法很简单,在报错的那个命令行窗口里执行echo %JAVA_HOME%,把输出打印出来逐字对比。如果是空格问题,重装JDK到无空格路径,别想着用引号绕,Hadoop脚本的拼接逻辑处理不了。
症状二:DataNode启动后几秒钟就消失,jps里看不到。
先去logs目录找最新的DataNode日志,搜clusterID。如果看到类似Incompatible clusterIDs in ... namenode clusterID = xxx; datanode clusterID = yyy,那就是ID不一致。这个问题的根源几乎总是:格式化之前没清datanode目录,或者格式化过多次导致两边错位。
修复流程是固定的:停掉所有进程 → 删掉namenode和datanode两个目录下的全部内容 → 重新hdfs namenode -format→ 重新启动。这里提醒一句,删之前确认里面没有你要保留的数据,格式化是不可逆的。
症状三:jps里能看到NameNode,但Web UI打不开。
先确认端口号,3.x是9870不是50070,这个错犯得太多了。端口对了还打不开,检查防火墙,Windows Defender有时候会拦截Java进程的监听端口。临时关掉防火墙试一次,能访问就说明是拦截问题,再把java.exe加进白名单。
症状四:start-dfs.cmd一闪而过,什么窗口都没留下。
这种情况一般是环境变量没生效。注意是当前命令行窗口的环境变量,你改完系统变量之后,已经开着的窗口是读不到的。关掉重开一个,再试。如果还是不行,直接在命令行里临时set HADOOP_HOME=D:\hadoop\hadoop-3.3.6,然后从sbin目录下用相对路径执行,能跑起来就说明是环境变量的问题。
6.2 运行阶段:作业提交了,但跑不动
症状一:报Failed to locate the winutils binary。
上面提过,bin目录下缺winutils.exe。这个错误有时候只是警告,作业能继续跑,但如果后面跟着UnsatisfiedLinkError,那就必须补hadoop.dll了。补的时候版本号要对齐,这个前面详细说过。
症状二:作业卡在map 0% reduce 0%长时间不动。
先看ResourceManager的8088界面,作业状态是ACCEPTED还是RUNNING。如果是ACCEPTED一直不动,说明没有可用资源,回头检查yarn.nodemanager.resource.memory-mb这个值,设得太小会导致容器申请不到。如果是RUNNING但map进度不涨,去看NodeManager日志,通常是容器启动失败,日志里会有具体的异常。
症状三:报Container is running beyond physical memory limits。
资源超限。两个方向调整:一是把yarn.nodemanager.resource.memory-mb调大,给容器更多空间;二是检查有没有别的进程在吃内存。伪分布式下一台机器要同时跑五六个Java进程,8G内存的机器本身就比较紧张,建议关掉浏览器和其他占内存的应用再跑作业。
症状四:作业跑完了,但part-r-00000是空的。
先看输入路径对不对,hdfs dfs -ls /wordcount/input确认文件在。再看文件是不是真的有内容,hdfs dfs -cat一下。还有一种可能是输出目录之前就存在,Hadoop读了旧的结果,这种情况删掉输出目录重跑就行。
6.3 一张速查表,遇到问题先对照
| 报错关键词 | 大概率原因 | 处理方向 |
|---|---|---|
JAVA_HOME is incorrectly set | 路径含空格或未生效 | 重装JDK到无空格路径,检查hadoop-env.cmd |
Failed to locate the winutils binary | 缺winutils.exe | 按版本号对齐放入bin目录 |
UnsatisfiedLinkError ... access0 | 缺hadoop.dll | 复制到bin和System32 |
Incompatible clusterIDs | 格式化后未清数据目录 | 清空namenode和datanode目录重新格式化 |
Output directory already exists | 输出路径冲突 | 删除旧输出目录 |
Permission denied | 用户名解析异常 | 设置HADOOP_USER_NAME为英文 |
Container ... beyond memory limits | YARN资源设置过小 | 调整resource.memory-mb |
| Web UI打不开 | 端口记错或被拦截 | 确认9870,检查防火墙 |
| 日志中文乱码 | 控制台编码不是UTF-8 | 加-Dfile.encoding=UTF-8 |
7. 几次重装之后我总结的几条经验
搭这套环境最耗时间的从来不是配置本身,而是排查那些不报错但行为不对的现象。比如dfs.replication设成3,集群能跑、能读能写,只是每次fsck都刷警告;比如hadoop.tmp.dir没改,运行一切正常,直到某次系统清理临时文件之后元数据没了。这类问题不像报错那样显眼,但埋得更深。
我的习惯是:每改完一组配置,就重启验证一次,别攒着一起测。一次性改十几个配置再启动,出了问题根本定位不到是哪一项导致的。伪分布式的启动成本不高,一次几十秒,分批验证反而更快。
还有一条关于格式化的。我现在会把这个动作当成一个“不可逆操作”来对待,执行前先在脑子里过一遍:namenode和datanode目录是不是空的?里面有没有我还没导出来的数据?确认了再敲回车。养成这个习惯之后,就没再出现过因为误格式化重来一遍的情况。
最后提一个实际用起来很顺手的做法:把启动和停止写成一个批处理文件放在桌面上,内容就是依次调用sbin下的那几个cmd,双击执行。省得每次都要开命令行、切目录、敲命令。文件里记得加一句ping 127.0.0.1 -n 5 > nul做个延时,因为start-dfs.cmd刚执行完的时候NameNode还没完全就绪,紧接着执行start-yarn.cmd偶尔会撞到一起,加个几秒缓冲就稳了。这种小工具看着不起眼,天天用的话能省下不少重复动作。