1. 为什么我要在本地从零搭一套 Hadoop + HBase 集群
大数据这块,很多人第一次接触 HBase 都是在公司现成的集群上敲命令,create、put、scan玩得挺溜,但一旦集群出问题、要扩容、要调参,立马抓瞎。我自己早期也是这样,直到有一次测试环境要重建,运维甩给我一句“你自己搭一套吧”,才发现从零把 Hadoop 和 HBase 串起来这件事,坑远比想象中多。
这套组合到底解决什么问题?简单说,Hadoop 提供分布式存储(HDFS)和资源调度(YARN),HBase 建立在 HDFS 之上,提供海量数据的随机实时读写能力。你可以把 HDFS 理解成一个超大号的“网盘”,适合一次写入、多次读取的大文件;而 HBase 则是在这个网盘上盖了一栋“带索引的图书馆”,让你能按行键快速定位到某一条记录。两者配合,才能撑起亿级行、TB 级数据的实时查询场景。
这篇文章适合谁看?如果你是刚入行的大数据开发、运维,或者学生党想在虚拟机上练手,又或者你是个后端工程师,想搞明白 HBase 底层到底依赖了什么,那这篇内容就是给你写的。我会按“规划 → 环境准备 → Hadoop 搭建 → HBase 搭建 → 联调验证 → 排错”的完整链路走一遍,把每一步为什么这么做、参数怎么算、坑在哪,都掰开揉碎讲清楚。整套流程我在 3 台虚拟机上反复搭过不下十次,下面这些经验都是踩出来的。
需要提前说明的是,本文以完全分布式模式为目标,也就是真正意义上的多节点集群,而不是单机伪分布式。伪分布式只能让你跑通流程,但学不到节点间通信、SSH 免密、时间同步这些真实集群才会遇到的问题。既然要学,就一步到位。
2. 搭建前的整体规划与方案选型
2.1 集群规模与角色分配怎么定
搭集群第一步不是装软件,而是画图纸。很多人上来就tar -zxvf,结果装到一半发现节点角色冲突,只能推倒重来。我建议先在纸上把节点和角色列清楚。
以最经典的最小生产级规模为例,3 台机器就能跑起来。为什么是 3 台?因为 HDFS 默认副本数是 3,3 台刚好能保证每个块都有 3 份,同时 NameNode 的高可用(HA)也需要奇数台 JournalNode 来做仲裁,3 台是最经济的选择。
| 节点主机名 | IP 示例 | 承担角色 |
|---|---|---|
| node1 | 192.168.1.101 | NameNode、ResourceManager、HMaster、ZooKeeper |
| node2 | 192.168.1.102 | DataNode、NodeManager、HRegionServer、ZooKeeper |
| node3 | 192.168.1.103 | DataNode、NodeManager、HRegionServer、ZooKeeper |
这里有个关键决策点:ZooKeeper 要不要独立部署?生产环境强烈建议独立,因为 ZK 对磁盘 IO 和网络延迟敏感,和 HBase 混部容易互相影响。但学习和测试环境,3 台机器混部是完全可以接受的,本文就采用混部方案,把 ZK 和 HBase 放一起。
另一个决策是NameNode 要不要做 HA。做 HA 需要额外部署 JournalNode 和 ZKFC,配置复杂度翻倍。我的建议是:第一次搭建先做非 HA 版本,把 HDFS、YARN、HBase 跑通,理解清楚各组件关系后,再升级到 HA。一上来就搞 HA,出问题你根本不知道是哪一层挂了。
2.2 版本选型:为什么我推荐这套组合
版本兼容性是大数据搭建里最容易翻车的地方。Hadoop、HBase、ZooKeeper、JDK 四者之间有严格的依赖关系,选错一个版本,可能卡在启动阶段几天都出不来。
我实测下来比较稳的一套组合是:
- JDK 8(Hadoop 3.x 和 HBase 2.x 对 JDK 8 支持最成熟,JDK 11 虽然部分支持但坑多)
- Hadoop 3.3.x
- HBase 2.4.x
- ZooKeeper 3.6.x
为什么不用最新的 Hadoop 3.4 或 HBase 2.5?因为新版本在社区里踩坑的人少,遇到问题搜不到答案。选版本的核心原则是:选发布一年以上、社区讨论充分的稳定版,而不是追新。HBase 2.4 和 Hadoop 3.3 的搭配经过大量验证,兼容性问题最少。
提示:HBase 2.x 必须搭配 Hadoop 3.x,HBase 1.x 才配 Hadoop 2.x。这个对应关系搞错,HBase 启动时会直接报
NoClassDefFoundError或者 HDFS 客户端版本不匹配的错。
2.3 硬件与系统层面的前置准备
虚拟机配置上,我建议每台至少4 核 CPU、8GB 内存、50GB 磁盘。HBase 是个吃内存的家伙,RegionServer 默认堆内存就要 1GB 起步,加上 Hadoop 的各个守护进程,8GB 是底线。如果宿主机内存不够,把 3 台压到 2 台也行,但副本数要相应调整。
操作系统我用的是 CentOS 7 或 Ubuntu 20.04 这类主流发行版。系统层面必须提前做三件事,这三件事没做好,后面 90% 的通信问题都源于此:
- 主机名与 hosts 映射:每台机器设置唯一 hostname,并在所有节点的
/etc/hosts里写全三台的 IP 和主机名映射。别依赖 DNS,内网环境 hosts 最可靠。 - SSH 免密登录:NameNode 需要能免密 SSH 到所有 DataNode 去启动进程。配置方式是生成密钥对后,把公钥追加到所有节点(包括自己)的
authorized_keys。 - 时间同步:集群节点时间差超过默认阈值,HBase 会拒绝启动 RegionServer。用
ntpdate或chronyd对齐时间,这是硬性要求。
# 生成密钥并分发(在 node1 上执行) ssh-keygen -t rsa -N "" for host in node1 node2 node3; do ssh-copy-id $host done这三步做完,先互相ssh node2测试一下,能免密登录再往下走。我见过太多人跳过验证,结果 Hadoop 启动脚本卡在Starting datanodes半天不动,最后发现是 SSH 没通。
3. Hadoop 集群搭建的核心细节与实操
3.1 配置文件逐个拆解:每个参数为什么这么写
Hadoop 的配置集中在$HADOOP_HOME/etc/hadoop/目录下,核心是 5 个文件。我不建议直接抄网上的配置,因为每个参数背后都有逻辑,理解了才能改对。
core-site.xml是全局配置,最关键的是fs.defaultFS,它告诉所有组件“HDFS 的入口在哪”。非 HA 模式下就写hdfs://node1:8020。8020 是 NameNode 的 RPC 端口,客户端读写文件都走这个口。
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>hadoop.tmp.dir这个参数特别容易被忽略。默认它指向/tmp,而/tmp在很多系统上重启会被清空,导致 NameNode 元数据丢失、集群起不来。一定要改到一个持久化目录,这是我踩过的血泪坑。
hdfs-site.xml管 HDFS 的行为。dfs.replication设成 3,和节点数对应。dfs.namenode.name.dir和dfs.datanode.data.dir分别指定元数据和数据块的存放路径,建议放在独立磁盘上,避免和系统盘抢 IO。
yarn-site.xml里yarn.resourcemanager.hostname指向 node1,yarn.nodemanager.aux-services必须设为mapreduce_shuffle,否则跑 MapReduce 任务会报 shuffle 错误。
mapred-site.xml指定mapreduce.framework.name为yarn,让计算框架走 YARN 调度。
workers 文件(老版本叫 slaves)列出所有 DataNode 主机名,一行一个。这个文件决定了启动脚本会去哪些机器拉起 DataNode 和 NodeManager。
3.2 环境变量与目录规划的门道
环境变量配置在/etc/profile.d/hadoop.sh里,比直接改/etc/profile更清晰,也方便管理。
export HADOOP_HOME=/opt/hadoop export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbinHADOOP_CONF_DIR这个变量很多人不设,结果 HBase 启动时找不到 Hadoop 的配置,报Cannot find configuration。HBase 依赖 Hadoop 的配置来连接 HDFS,这个变量必须导出。
目录规划上,我习惯把所有数据放在/data下,按组件分子目录:/data/hadoop/tmp、/data/hadoop/name、/data/hadoop/data、/data/hbase、/data/zookeeper。这样备份和清理时一目了然,不会误删。
3.3 格式化与启动:顺序错了全盘重来
Hadoop 首次启动前必须格式化 NameNode,命令是hdfs namenode -format。这个命令一辈子只能执行一次(除非你要清空集群重来)。格式化会生成集群 ID,DataNode 靠这个 ID 和 NameNode 握手。如果你格式化了两次,DataNode 的 ID 和 NameNode 对不上,就会报Incompatible clusterIDs错误。
启动顺序也有讲究:
# 在 node1 上执行 start-dfs.sh # 启动 HDFS start-yarn.sh # 启动 YARN启动后立刻用jps检查每台机器的进程。node1 上应该有 NameNode、ResourceManager、SecondaryNameNode;node2 和 node3 上应该有 DataNode、NodeManager。少任何一个进程,都要去看对应的日志,日志在$HADOOP_HOME/logs/下,按组件名区分。
验证 HDFS 是否正常,最直接的方法是建目录、传文件:
hdfs dfs -mkdir -p /test hdfs dfs -put /etc/hosts /test/ hdfs dfs -ls /test/能列出来就说明 HDFS 通了。如果报Connection refused,八成是 NameNode 没起来或者防火墙挡了 8020 端口。
注意:CentOS 7 默认开着 firewalld,测试环境图省事可以直接
systemctl stop firewalld && systemctl disable firewalld。生产环境则要精确放行各组件端口,别一关了之。
4. HBase 集群搭建的关键环节
4.1 HBase 与 HDFS 的依赖关系理清
HBase 的架构里,HMaster 负责管理元数据和 Region 分配,HRegionServer 负责实际的数据读写,而所有数据最终都落在 HDFS 上。所以 HBase 搭建的前提是 HDFS 必须健康运行。这也是为什么我把 Hadoop 放在前面讲透。
HBase 自己还依赖 ZooKeeper 来做分布式协调:HMaster 选举、RegionServer 心跳、元数据位置信息都存在 ZK 里。所以完整的依赖链是HBase → ZooKeeper + HDFS。三者缺一不可。
理解这一点,你就能明白为什么 HBase 启动失败时,排查顺序应该是:先看 ZK 通不通,再看 HDFS 通不通,最后才看 HBase 自身配置。
4.2 hbase-site.xml 核心参数详解
HBase 的配置在$HBASE_HOME/conf/hbase-site.xml。几个必改参数:
<configuration> <property> <name>hbase.rootdir</name> <value>hdfs://node1:8020/hbase</value> </property> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>node1,node2,node3</value> </property> <property> <name>hbase.zookeeper.property.dataDir</name> <value>/data/zookeeper</value> </property> </configuration>hbase.rootdir指向 HDFS 上的存储路径,HBase 的所有表数据、WAL 日志都放这里。hbase.cluster.distributed设为 true 才是分布式模式,设 false 就是单机模式,这个开关千万别搞错。
hbase.zookeeper.quorum列出 ZK 集群的所有节点。如果你用 HBase 自带的 ZK(也就是让 HBase 自己拉起 ZK),那这个参数就够了;如果 ZK 是独立部署的,还要设hbase.zookeeper.property.clientPort和确保 ZK 已经先启动。
regionservers文件列出所有 HRegionServer 的主机名,和 Hadoop 的 workers 文件类似。这里写 node2、node3。
4.3 启动 HBase 与进程验证
启动 HBase 用start-hbase.sh,它会在 node1 拉起 HMaster,然后 SSH 到 regionservers 列表里的机器拉起 HRegionServer。启动后jps检查:node1 有 HMaster,node2 和 node3 有 HRegionServer。
如果 HMaster 起不来,最常见的原因是ZK 没起来或者连不上。去看$HBASE_HOME/logs/hbase-*-master-*.log,如果看到Connection refused到 ZK 端口,就是 ZK 的问题。如果看到hbase.rootdir相关的 HDFS 异常,就是 HDFS 没通。
HBase 启动后,用hbase shell进去敲status,能看到集群有 2 个 RegionServer 就说明成功了。再create 'test', 'cf'建张表,list能看到表,put和get能读写数据,整个链路就完全打通了。
5. 常见问题排查与避坑经验实录
5.1 启动阶段高频故障速查
搭建过程中遇到的问题,八成集中在下面这张表里。我把它们整理出来,方便你对照排查。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| DataNode 启动后立刻消失 | clusterID 不匹配 | 检查是否重复格式化 NameNode |
| HMaster 启动即退出 | ZK 连不上或 rootdir 异常 | 看 master 日志,确认 ZK 和 HDFS 状态 |
| RegionServer 拒绝启动 | 节点时间不同步 | 用 date 对比各节点时间,配置时间同步 |
| HBase shell 卡住无响应 | HDFS 处于安全模式 | hdfs dfsadmin -safemode leave |
| 客户端连不上 HBase | hosts 映射缺失 | 检查客户端机器的 /etc/hosts |
5.2 几个只有踩过才知道的细节
第一个坑:HBase 的 WAL 日志目录。默认 WAL 放在hbase.rootdir下的/WALs,如果 HDFS 写入慢,RegionServer 会频繁报Slow sync警告。测试环境可以调大hbase.regionserver.hlog.blocksize,但生产环境更该关注的是磁盘性能。
第二个坑:ZooKeeper 的 myid 文件。如果用独立 ZK,每个节点的dataDir下必须有一个myid文件,内容是 1 到 255 之间的唯一数字,对应zoo.cfg里server.N的 N。这个文件写错或漏写,ZK 集群根本组不起来,而且报错信息很隐晦。
第三个坑:内存分配。HBase 的hbase-env.sh里HBASE_HEAPSIZE默认可能只有 1GB,跑起来后频繁 Full GC。测试环境调到 2GB 到 4GB 会稳很多。同时HBASE_MASTER_OPTS和HBASE_REGIONSERVER_OPTS可以分别设置,别只改一个。
第四个坑:hostname 解析。有些系统hostname返回的是短名,但配置里写的是全限定名,导致 RPC 绑定失败。统一用短名,并在 hosts 里做好映射,能避免大量诡异问题。
5.3 集群健康状态的日常检查清单
集群搭起来只是开始,日常要养成检查习惯。我一般会看这几个指标:
hdfs dfsadmin -report:看 DataNode 数量、容量、是否有节点掉线yarn node -list:看 NodeManager 是否全部在线- HBase shell 里
status 'detailed':看 RegionServer 的请求数、Region 分布是否均衡 - ZK 的
echo stat | nc node1 2181:看 ZK 是否正常响应
这套检查跑一遍,集群有没有暗病基本就清楚了。我个人的体会是,搭建阶段花时间把每个组件单独验证透,比后面出问题再回头补要省太多事。很多人图快,Hadoop 没验证就直接上 HBase,结果 HBase 报错时根本分不清是 HBase 的问题还是 HDFS 的问题,排查成本翻倍。
最后分享一个实用技巧:把整个搭建过程写成脚本,包括环境变量、配置文件分发、启动命令。下次重建集群时,改几个 IP 就能一键跑完,既省时间又避免手抖写错参数。这套脚本我现在还留着,每次换环境都能直接复用。