1. 项目概述与整体设计思路
1.1 单节点集群到底在解决什么问题
单节点 Hadoop 集群,说白了就是伪分布式环境。我第一次接触这个概念的时候也觉得别扭,明明只有一台机器,为什么叫集群?后来理解了,Hadoop 的伪分布式模式是把 NameNode、DataNode、ResourceManager、NodeManager 这些角色全部跑在同一台机器的不同进程里,每个进程各干各的活,彼此通过地址和端口通信。从架构上讲,它具备了一个完整 Hadoop 集群的所有组件,只是所有组件挤在一台机器上。
这个环境的价值在于学习成本和资源成本都极低。你不需要三台服务器,不需要机房,一台 8G 内存的笔记本就能跑起来。对于刚开始学大数据的人来说,伪分布式是理解 HDFS 读写流程、YARN 资源调度、MapReduce 执行机制的最好载体。很多公司在做技术预研、跑数据管道测试、给新手做入职培训时,也直接在一台服务器上搭伪分布式,效果和真实集群在逻辑上完全一致。
我见过不少人上来就买三台云服务器搭完全分布式,结果两天过去了,光配 SSH 免密和修网络问题就耗掉大半时间,真正接触 HDFS 和 MapReduce 的时间少得可怜。先搭好单节点、跑通 WordCount、理解数据是怎么存进去又是怎么算出来的,再去扩展多节点,才是合理的路径。
1.2 调试和测试场景里的真实价值
除了学习,单节点集群在开发调试场景里也很能打。我自己就有过这样的经历:写了一个需要跑在 YARN 上的 Spark 任务,本地 IDE 里跑和集群里跑行为差异很大,但申请测试集群要排队。这时候在一台开发机上搭一个伪分布式,直接把任务丢上去跑,日志随便看,配置随便改,调试效率高得多。
还有一个特别实用的场景是验证 Hadoop 生态组件的集成。比如说 Hive 和 HBase 的元数据要放到 HDFS 上,你在单节点环境里先验证一遍读写链路,确认没有问题,再往正式环境迁移,心理就有底了。文章后面我会提到和 ZooKeeper 整合的扩展思路,同样可以在这个单节点基础上先做验证。
我在这篇文章标题里写了“优化版”,和网上泛滥的纯照着官网文档抄的教程相比,优化点主要体现在几个地方:版本搭配上避开踩坑组合、配置文件里加上容易被忽略的参数、启动顺序和验证手段更完整,还总结了我在实际安装过程中遇到过的典型报错。接下来我会把每一个环节拆开讲,尽量不让你卡在半路。
2. 环境准备与前置检查
2.1 操作系统、JDK 和 Hadoop 版本怎么搭配
版本搭配是搭建 Hadoop 过程中最容易让人抓狂的问题。我在前面带新人的时候,经常看到他们把 JDK 装成最新的 JDK 17,然后 Hadoop 怎么都起不来,日志里一堆莫名其妙的IllegalAccessError。原因很简单,Hadoop 3.x 系列官方明确要求 Java 8 或 Java 11 运行环境,你用 JDK 17 去跑,某些反射和模块化访问的代码就会直接罢工。
我推荐使用 Ubuntu 20.04 或 22.04 的系统,JDK 选择 OpenJDK 1.8,也就是openjdk-8u或者java-1.8.0-openjdk。Hadoop 版本选择 3.3.6 或者 3.3.4,这两个版本在社区里反馈都比较稳定,部署方式也一致。如果你有特殊需求必须用 Hadoop 2.x,那记得去看对应的文档,2.x 和 3.x 的配置项有些差异,不要混着看。
下载 Hadoop 安装包的时候,我建议直接到 Apache 官方镜像站找hadoop-3.3.6.tar.gz,避免在某些第三方下载站拿到被篡改过的包。拿到安装包后先校验一下 SHA-512 校验和,Apache 官网每个下载链接旁边都提供了校验值,用sha512sum命令验证一下,确认包没有损坏再继续。
2.2 创建专用用户、配置 SSH 免密登录
很多教程直接让你用 root 用户安装 Hadoop,这是个大坑。Hadoop 框架内部很多脚本和进程对文件权限很敏感,用 root 启动会有各种意想不到的权限问题,而且一旦出了问题,排查起来非常痛苦。正确的做法是创建一个专门的 Hadoop 用户,比如hadoop。
sudo useradd -m hadoop -s /bin/bash sudo passwd hadoop创建完用户之后,切换到hadoop用户,生成 SSH 密钥对,配置免密登录。这里有个细节很多人会忽略:伪分布式环境下 NameNode 启动的时候会通过 SSH 登录到本机来启动 DataNode 进程,如果免密没配好,就会出现 NameNode 起来了、DataNode 起不来或者反复重启的情况。
su - hadoop ssh-keygen -t rsa -P '' cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ssh localhost执行ssh localhost时如果不需要输入密码,就说明免密配置成功了。这里的-P ''意思是私钥密码为空,如果你在这里设置了密码,后续 Hadoop 脚本在免密登录时依然会要求输入密码,一样会出问题。
2.3 主机名、hosts 映射和基础系统配置
安装 Hadoop 前,把主机名设置好。我习惯把节点命名为hadoop-node这种一眼能看懂的名字,不要用默认的ubuntu或者localhost,因为后续配置core-site.xml时要用主机名来指定 NameNode 地址,用localhost虽然能跑通,但无法模拟真实环境的访问方式。
sudo hostnamectl set-hostname hadoop-node然后编辑/etc/hosts,把主机名映射到本机 IP。这一步的作用是确保 Hadoop 进程通过主机名互相访问时能解析到正确的地址。如果你用的是云服务器,记得填内网 IP,而不是公网 IP。
127.0.0.1 localhost 192.168.1.100 hadoop-node还有一个容易踩的坑是防火墙。Ubuntu 默认没有开防火墙,但有些云镜像会预装ufw并且默认开启。Hadoop 需要用到8020(NameNode RPC)、9870(NameNode Web UI)、9864(DataNode Web UI)、8088(YARN Web UI)等端口,如果防火墙开着,你会在浏览器里怎么都访问不到 Web UI,但在服务器本机用curl却一切正常。排查这个问题的时候记得看一眼防火墙状态:
sudo ufw status如果状态是active,直接把用到的端口放行,或者学习环境下干脆关掉防火墙。我个人的建议是学习环境直接关掉,省得来回折腾。
3. 配置文件逐项拆解:为什么每个参数这样设
3.1 core-site.xml——集群入口地址的设定逻辑
Hadoop 的配置目录在解压后的etc/hadoop/下。核心配置文件有五个:core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml、workers(3.x 版本叫workers,2.x 版本叫slaves),还有一个hadoop-env.sh环境变量文件。
core-site.xml里最重要的参数是fs.defaultFS,它指定了整个集群的 NameNode 地址和端口。NameNode 是 HDFS 的“大脑”,所有客户端读写文件都要先访问它,所以这个地址是全局入口。
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop-node:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/home/hadoop/hadoop_data/tmp</value> </property> </configuration>这里要特别注意hadoop.tmp.dir这个参数。默认值是/tmp/hadoop-${user.name},而/tmp目录在系统重启后会被清空。一旦这个目录被清空,NameNode 的元数据也没了,启动时就会因为找不到镜像文件而报错。所以这一步必须提前改掉,把它指向一个持久化目录。我习惯放到 Hadoop 用户的 home 目录下,用hadoop_data统一管理元数据、数据块和临时文件。
3.2 hdfs-site.xml——副本数、数据目录和回收站
伪分布式模式下 DataNode 只有一台,HDFS 的默认副本数是 3,但你只有一台机器,副本数为 3 意味着同一份数据要在同一个磁盘上写三份,白白浪费存储空间。所以要把dfs.replication改成 1,这是单节点环境最重要的调整。
<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/hadoop/hadoop_data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/home/hadoop/hadoop_data/datanode</value> </property> <property> <name>dfs.namenode.secondary.http-address</name> <value>hadoop-node:9868</value> </property> <property> <name>dfs.permissions.enabled</name> <value>false</value> </property> </configuration>解释几个容易被忽略的参数。
dfs.namenode.name.dir和dfs.datanode.data.dir分别指定 NameNode 元数据存储路径和 DataNode 数据块存储目录。单独指定这两个路径的好处是管理和备份都方便,如果你要对数据盘扩容,直接改这里就好。生产环境里一般配置多个目录做冗余,但单节点学习环境就一个目录够了。
dfs.namenode.secondary.http-address是 SecondaryNameNode 的 Web 地址。很多人会问,伪分布式下有没有必要启动 SecondaryNameNode?我的建议是启动。它虽然不是完整的 NameNode 热备,但它会定期合并 NameNode 的 edits 日志,对学习理解 HDFS 元数据管理机制非常有帮助,而且在单节点环境下多跑一个进程也不会有什么负担。
dfs.permissions.enabled设置为false,意思是关闭 HDFS 的权限检查。这一步纯粹是为了学习方便,不然你每次上传文件、建目录都要注意 HDFS 上的用户权限,对刚接触 Hadoop 的人来说平白增加很多阻碍。生产环境必须开启权限检查,我这里只针对学习场景做优化。
3.3 yarn-site.xml 和 mapred-site.xml——资源调度与计算框架
YARN 是 Hadoop 的资源调度层,MapReduce 是计算框架。它们俩配合起来的关系可以这样理解:YARN 像是一个项目经理,负责分配服务器资源(内存、CPU)给各个任务,MapReduce 则是一批具体的工人,负责执行数据计算任务。在伪分布式环境下,YARN 的 ResourceManager 和 NodeManager 都跑在同一台机器上,需要配置成不启用代理的方式运行。
<!-- 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> <property> <name>yarn.nodemanager.resource.cpu-vcores</name> <value>2</value> </property> </configuration>yarn.nodemanager.aux-services这个参数很多人不理解它的作用。MapReduce 任务在 Shuffle 阶段(也就是 Map 输出传给 Reduce 的阶段)需要 NodeManager 辅助处理数据流转,这个辅助服务就是mapreduce_shuffle。不配置这个参数,你的 MapReduce 作业会全部卡在 Shuffle 阶段,看似在跑,实际上一直没有进展。
yarn.nodemanager.resource.memory-mb决定了 NodeManager 能使用的总内存,cpu-vcores是可用虚拟核数。这两个值的设定要看机器实际配置。比如 8G 内存的机器,我建议给 NodeManager 分配 4G,留一半给操作系统和其他进程。虚拟核数填 2 不是指你只有 2 个物理核,YARN 的虚拟核和物理核是逻辑换算的关系,4 核机器填 2 或者 4 都可以,不用太纠结。
<!-- mapred-site.xml --> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>mapreduce.framework.name设置为yarn,意思是你提交的 MapReduce 作业会交给 YARN 去调度执行,而不是在本地进程里跑。很多人在伪分布式环境里配完这个参数,提交作业后发现运行日志显示job_local,那是因为没设置这个参数或者设错了,导致任务在本地上跑而不是在 YARN 上跑。区分方法也很简单:在 YARN 的 Web UI 上能看到任务记录,就说明作业真正跑在了 YARN 上。
3.4 hadoop-env.sh 和环境变量里的隐藏优化
安装目录下的hadoop-env.sh文件里有几个环境变量需要手动确认。最重要的问题是 JDK 路径,有些机器上系统默认的java命令指向的可能是其他 JRE,Hadoop 脚本不一定会去识别JAVA_HOME,所以显式写死是最稳妥的做法。
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export HADOOP_HOME=/home/hadoop/hadoop-3.3.6 export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop同时把 Hadoop 的路径写到用户的环境变量文件里:
cat >> ~/.bashrc <<EOF export HADOOP_HOME=/home/hadoop/hadoop-3.3.6 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin EOF source ~/.bashrcHADOOP_CONF_DIR这个变量很多人不知道是干嘛的,它的作用是指定配置文件目录。如果你把配置文件放在自定义路径下,就必须配置这个变量,Hadoop 才能找到你的core-site.xml和hdfs-site.xml。
还有一个细节,3.x 版本的 Hadoop 默认在hadoop-env.sh里通过JAVA_HOME的自动检测逻辑来找 JDK,但这个自动检测在有些环境下覆盖不到,尤其是某些通过包管理器安装的 OpenJDK 路径很特殊。直接手动注释掉原来的 JAVA_HOME 配置,填入你自己的路径,实测最稳。
3.5 配置完成后自查清单
配置文件都改完之后,不要急着启动,先做一轮自查。我每次搭建环境都会过一遍这些检查点,基本能过滤掉九成以上的低级问题。
| 检查项 | 预期结果 | 检查方式 |
|---|---|---|
java -version | 显示 1.8 版本信息 | 命令行直接执行 |
hadoop version | 显示 Hadoop 3.3.6 | 命令行直接执行 |
ssh localhost | 无需密码直接登录 | 命令行直接执行 |
| 配置文件 XML 格式 | 无报错且参数完整 | xmllint或文本编辑器检查 |
hadoop_data目录 | 所属用户是 hadoop | ls -l /home/hadoop/ |
这里最容易被忽略的是配置文件 XML 格式是否正确。我见过有人手打配置时少写了一个闭合标签,结果 Hadoop 启动时直接忽略整个文件,用了默认配置,最后 NameNode 都起不来,报错信息还特别隐晦。用python3 -c "import xml.dom.minidom; xml.dom.minidom.parse('core-site.xml')"这种命令快速检查一下格式,能省很多事。
4. 启动流程与功能验证
4.1 格式化 NameNode 的正确时机和误区
配置完成后第一步是格式化 NameNode。格式化是什么?简单说就是在 NameNode 的数据目录下生成初始的元数据文件,类似给一块新硬盘做分区和格式化。执行命令:
hdfs namenode -format格式化成功后会输出successfully formatted的提示。但这里我要强调几个很容易踩的坑。
第一个坑是重复格式化。如果你已经启动过集群,往 HDFS 里写了文件,然后又执行了格式化命令,会直接清空所有元数据。更严重的是,NameNode 和 DataNode 之间靠一个clusterID来标识彼此,格式化会生成新的clusterID,而旧 DataNode 上的数据和新的clusterID对不上,启动时 DataNode 就会拒绝正常工作,报Incompatible clusterIDs错误。一旦遇到这种情况,仅删掉 DataNode 的数据目录重新格式化还不够,必须两边一起清空重来。
第二个坑是格式化时机的选择。在正式启动 HDFS 之前格式化,和启动之后再格式化,完全是两回事。最稳妥的操作顺序是:先确认所有配置文件都改好了,确认数据目录路径都指向了正确的文件夹,然后再执行格式化,最后启动。
第三个坑是没有确认数据目录是否为空就去格式化。格式化不会覆盖已有文件,如果name.dir目录里已经有旧的元数据文件,格式化过程会报错或者生成新的元数据混在一起,导致启动后行为诡异。所以格式化之前rm -rf /home/hadoop/hadoop_data清一遍,再重新创建空目录,是最保险的。
4.2 一键启动脚本与进程检查
启动 Hadoop 集群有两种方式,分开启动和脚本一键启动。推荐你用脚本启动,Hadoop 提供了现成的启动脚本:
start-dfs.sh start-yarn.shstart-dfs.sh会启动 NameNode、DataNode 和 SecondaryNameNode,start-yarn.sh会启动 ResourceManager 和 NodeManager。如果你想把两个合并成一条命令,也可以直接执行start-all.sh,但这个脚本在较新版本里官方已经不建议使用了,所以我还是建议分开执行,出问题时能更清晰地定位是哪一层出了问题。
启动完成后用jps命令查看 Java 进程状态。JPS 是 JDK 自带的工具,专门用来查看 Java 相关的进程。正确的结果应该是以下 5 个进程全部出现:
[hadoop@hadoop-node ~]$ jps 12345 NameNode 12346 DataNode 12347 SecondaryNameNode 12348 ResourceManager 12349 NodeManager如果这 5 个进程齐全,说明你的单节点集群核心组件都启动成功了。差一个都不行,比如没有 NameNode,说明 HDFS 没启动成功;没有 NodeManager,说明 YARN 有问题,需要回看对应的日志文件排查。
停止集群则用对应的stop-dfs.sh和stop-yarn.sh脚本。我建议每次实验做完之后养成 stop 的习惯,因为伪分布式环境占用的内存不小,不关的话机器会越来越卡,时间长了影响后续使用。
4.3 功能验证:Web UI 和文件上传下载
进程都起来了,还得验证功能是否真的可用。第一个要验证的是 Web UI。在浏览器里访问http://hadoop-node:9870,可以看到 NameNode 的管理页面,里面有 HDFS 的容量信息、节点列表、文件目录浏览功能。再访问http://hadoop-node:8088,是 YARN 的资源调度页面,可以看到任务运行记录、队列状态和节点资源使用情况。
接下来验证 HDFS 的基本读写能力:
hdfs dfs -mkdir -p /user/hadoop hdfs dfs -put /etc/hosts /user/hadoop/ hdfs dfs -ls /user/hadoop/hdfs dfs是 HDFS 的命令行客户端工具,-put把本地文件上传到 HDFS,-ls查看文件列表。能成功执行这些命令,说明你的 HDFS 读写链路是通的。
再来一个真正的计算任务验证,跑官方的 WordCount 示例。这个示例的作用是统计文本中每个单词出现的次数,是 Hadoop 世界的 Hello World。
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /user/hadoop/hosts /user/hadoop/output输出结果后查看统计文件:
hdfs dfs -cat /user/hadoop/output/part-r-00000执行这条命令后,能在 YARN 的 Web UI 看到这次任务的执行记录,包括用了多少内存、多少核、任务分了多少个 Map 和 Reduce。跑通这一步,你的单节点 Hadoop 集群就算完全可用了,之后可以在这个基础上安装 Hive、Spark、Flink 等工具。
5. 常见问题与排查技巧实录
5.1 问题速查表
我在多次搭建和帮助别人排查的过程中,整理了一张高频问题对照表。初学者照着这张表排查,大部分问题都能自己解决。
| 现象 | 直接原因 | 解决方法 |
|---|---|---|
jps没有 NameNode | 未格式化或格式化失败 | 清空数据目录,重新格式化,启动 |
DataNode 起不来,日志报Incompatible clusterIDs | 重复格式化导致 ID 不一致 | 删除 DataNode 数据目录和 NameNode 数据目录,统一重新格式化 |
| 访问 9870 端口不通 | 防火墙拦截或端口未监听 | 关防火墙,确认启动脚本执行成功 |
提交 MapReduce 任务卡住,日志停在INFO | Shuffle 依赖未配置 | 检查yarn-site.xml中 aux-services 配置 |
上传文件报Permission denied | HDFS 权限检查开启 | 学习环境下把dfs.permissions.enabled设为 false |
Hadoop 启动报JAVA_HOME is not set | 环境变量没配置或配置错误 | 检查hadoop-env.sh和.bashrc中的 JAVA_HOME |
| YARN 页面可见,但任务全部 FAILED | NodeManager 资源不足 | 调大yarn.nodemanager.resource.memory-mb,减少同时运行的任务量 |
5.2 格式化不成功和重复格式化的高级补救
格式化不成功的情况分两种。第一种是数据目录有残留文件导致的,解决方法如同前面说的,删掉hadoop_data目录重新建空目录再格式化。第二种是磁盘满了,格式化时会直接报没有空间。这种情况容易被人忽略,因为机器看起来还能用,但/home/hadoop/hadoop_data所在分区的空间已经被日志或者下载的安装包塞满了,用df -h查一下就能确认。
重复格式化导致 DataNode 无法启动的问题需要一点额外的技巧。有时候你不想把全部数据都清掉重来,比如里面已经存了一些测试数据想保留,那可以尝试手动统一clusterID。把两个数据目录里的VERSION文件都找出来,把 DataNode 的clusterID改成和 NameNode 的一样,然后重启 DataNode,有时能救回来。这个操作在 3.x 版本下可行,但只建议你在这个学习环境里折腾,生产环境千万别这么干,直接按流程恢复备份或者重建节点才是正路。
5.3 内存不足和进程反复重启的处理
单节点环境最常见的资源问题是内存不足。默认配置下,Hadoop 会给 NameNode、DataNode、ResourceManager、NodeManager 每个进程分配较大的堆内存。在只有 8G 内存的笔记本上,这些进程全部启动后,内存很容易吃紧,表现是某个进程启动之后过几秒就没了,或者整体运行特别卡顿。
解决方法是在hadoop-env.sh里显式调整各进程的堆内存参数。HADOOP_NAMENODE_OPTS和HADOOP_DATANODE_OPTS是设置 NameNode 和 DataNode 内存的地方,把-Xmx值调小即可:
export HADOOP_NAMENODE_OPTS="-Xmx1024m $HADOOP_NAMENODE_OPTS" export HADOOP_DATANODE_OPTS="-Xmx1024m $HADOOP_DATANODE_OPTS" export YARN_RESOURCEMANAGER_OPTS="-Xmx1024m $YARN_RESOURCEMANAGER_OPTS" export YARN_NODEMANAGER_OPTS="-Xmx1024m $YARN_NODEMANAGER_OPTS"内存分配的整体思路是:操作系统留 2G,NameNode 和 ResourceManager 各留 1G,DataNode 和 NodeManager 各留 1G,剩余空间给正在运行的 MapReduce 任务。4G 内存的小机器可以再调低一点,但不要让 NameNode 低于 512M,否则 NameNode 频繁 GC,集群会变得非常不稳定。
5.4 Web UI 访问不到和原生库警告排查
Web UI 访问不到,这个问题我遇到过一次最典型的情况是:所有进程都在,jps输出正常,服务器本机curl localhost:9870也有返回,但浏览器就是进不去。最后定位到是云服务器安全组没放行端口,不在 Ubuntu 防火墙层面,而在云平台的控制面板里。如果你也是用云服务器搭环境,记得同时检查安全组的入站规则。
还有一个常见现象是启动日志里出现Unable to load native-hadoop library的警告。这个是 Hadoop 在提示你没有编译好的本地库文件,通常是libsnappy或者libhadoop相关的原生库缺失。对这个警告,学习环境下不用管它,不影响功能。Hadoop 会自动回退到 Java 实现,只是压缩和解压性能差一些,等以后有需求了再编译安装对应的原生库即可。
5.5 从日志中定位问题的基本套路
排查 Hadoop 问题,日志是第一手信息。Hadoop 的日志目录在$HADOOP_HOME/logs/下,每个角色都有独立的日志文件,比如hadoop-hadoop-namenode-hadoop-node.log对应 NameNode,hadoop-hadoop-datanode-hadoop-node.log对应 DataNode。
MR任务相关的报错则要看 YARN 的日志目录/home/hadoop/hadoop_data/yarn/logs或者通过yarn logs -applicationId <app_id>命令查看。我一般排查问题的顺序是:先用jps确认哪些进程挂了,再去看对应组件的日志尾部,用tail -100拉出最后 100 行日志,重点看ERROR和WARN关键字。日志里八成以上的报错信息会直接告诉你怎么修复,比你去搜索要快得多。
6. 从单节点走向更完整的生态
6.1 善用快照和克隆,让环境可以随便折腾
单节点集群搭建好以后,最重要的一件事是做快照。如果你用的是虚拟机,就在装好 Hadoop 之后打一个快照;如果你用的是云服务器,就做镜像备份。有了快照,你再也不用担心把环境搞坏了。不管是改配置改乱了,还是实验把集群搞挂了,一个快照回滚就恢复如初。我在学习阶段经常两天一小搞、三天一大搞,全靠快照兜底。
如果你需要给同事或者同学分发同样的环境,还可以直接克隆虚拟机或者用镜像,对方启动后改一下 IP 和 hosts 就能用,比从头搭节省大量时间。这就是为什么我一直强调把 Hadoop 数据目录放到独立的路径下,克隆之后调整路径和权限非常方便,不会因为路径分散而漏配。
6.2 单节点上整合 ZooKeeper 和规划 HA
很多人搭完单节点后,下一步就想和高可用方向靠拢,比如文章开头热词里提到的 Hadoop 和 ZooKeeper 整合。在单节点环境里,ZooKeeper 要跑起来大概率也是单机模式,但没关系,单机 ZooKeeper 加上 Hadoop 的自动故障转移配置足以帮你理解整个 HA 机制:ZooKeeper 负责选主和状态存储,JournalNode 负责同步元数据日志,故障时自动切换 NameNode。整个过程中观察到的日志和状态变化,和真实环境下的多节点 HA 几乎一致,只是规模缩小了。
我建议的扩展路线是:先在这个单节点上装一个 ZooKeeper,理解它的节点竞选和数据模型;然后配置 HDFS 的高可用,虽然伪分布式下没法真正看到秒级切换的效果,但你能理解整个 HA 的组件构成;最后再把 YARN 的 ResourceManager 高可用也配上。这一套走下来,你对 Hadoop 的高可用机制的理解会比单纯背书深刻得多。
6.3 用 Docker 快速起 Hadoop 环境的另一种思路
如果你嫌弃手动安装麻烦,直接用 Docker 跑 Hadoop 镜像也是一种方式。社区里有现成的 Hadoop 镜像,拉下来就能起一个预配置好的单节点容器,几分钟就能进入使用环节。这种方式的好处是环境隔离和快速重建,缺点是隐藏了太多底层细节,你不太容易理解配置文件之间的关系和启动顺序,对学习原理不是特别友好。
我更推荐的做法是:手动搭建完这一遍之后,再用 Docker 跑一个镜像做对照。手动搭过的过程让你明白了组件之间怎么通信、配置在哪、日志在哪,Docker 镜像就成了一把验证你理解对不对的工具。手动搭一遍加容器跑一遍,知识会记得非常牢固。之后不管是在新机器上重新部署,还是用容器编排工具做多节点模拟,你都有足够的知识储备去应对。
我自己在经历过这些步骤之后最大的体会是:Hadoop 单节点集群不是终点,它是一个让你低成本触碰整个大数据技术栈的支点。很多人在这一步放弃,觉得配来配去没意思,但只要把环境跑通,后面无论是学 Hive 的 SQL 转 MapReduce、学 Spark 的任务提交流程,还是了解 Flink 的 Checkpoint 机制,你都有了一个可以随时折腾的试验田。数据管道的每一环都可以在这个单节点上模拟出来,这对建立对整个技术栈的整体认知帮助巨大。所以别嫌第一步繁琐,耐心把环境搭好,后面受益无穷。