手头正好有台测试集群要重新搭,就顺手把 HBase 2.3.7 的安装过程完整梳理了一遍。HBase 这个版本在 2.x 分支里属于比较稳的,很多线上集群跑的就是它,不过装 HBase 从来不只是“解压一个 tar 包”那么简单。前置的 JDK、Hadoop、ZooKeeper 版本只要有一处没搭配好,后面就能冒出一堆莫名其妙的坑。这篇文章就直接按我实际部署的路径来写,从环境规划到配置拆解,从启动验证到排错记录,给准备装 2.3.7 的同学一份可以照着做的清单。
1. 安装前的组件版本匹配与环境规划
1.1 版本组合怎么选才能少踩坑
很多新手一上来就问“HBase 怎么装”,但真正动手时才发现,HBase 依赖的东西比想象中多。它不是一个能独立跑起来的数据库,底层存储依赖 HDFS、分布式协调依赖 ZooKeeper、运行环境依赖 JDK。所以第一步不是下载 HBase,而是先把版本组合想清楚。
我这次用的是 JDK 8 + Hadoop 3.1.4 + ZooKeeper 3.5.7 + HBase 2.3.7。这几个版本是经过验证的常见组合。先说 JDK,HBase 2.3.x 官方要求 JDK 8,用它自己的话说是“Java 8 is required”。有人会想直接用 JDK 11 或者更高版本,但 2.3.x 系列对 JDK 11 的支持并不好,有些 JVM 参数和类库行为在更高版本上会出问题。2.4 之后才逐步支持 JDK 11。所以装 2.3.7 就老老实实用 JDK 8,别给自己找麻烦。
再看 Hadoop。HBase 2.3.7 官方编译基于 Hadoop 2.10,但实际使用中与 Hadoop 3.1.x、3.2.x 兼容性都不错。我推荐 Hadoop 3.1.4 或 3.2.2 这种相对成熟的 3.x 版本。Hadoop 3.3.x 也能跑,但如果你不是对 3.3 的新特性有硬需求,建议保守一点。原因很简单,HBase 官方文档里列出的支持矩阵中,3.3 并不是当时重点验证的版本,生产环境没必要当小白鼠。
ZooKeeper 方面,HBase 2.3.7 自带了一个 3.5.x 的 ZK,这个自带版本适合单机或伪分布式场景测试用,真上集群我还是建议单独部署一套 ZooKeeper。版本选 3.4.14 或 3.5.x 都行,注意别用太老的 3.4.5 那种,和 2.3.x 配合时可能遇到兼容问题。
最后是节点规划。如果只是学习测试,单节点把 Hadoop、ZK、HBase 全部部署在一台机器上就够了,也就是伪分布式模式。如果是想体验真正的分布式能力,最少准备三台机器,一台作为 HMaster + NameNode,另外两台作为 RegionServer + DataNode,ZooKeeper 三个节点都部署。我用的是三节点方案,下文也是按三节点分布式来写的。
1.2 三节点集群的基础环境准备清单
机器准备好之后,有一堆基础环境要处理。这些步骤看起来琐碎,但每一条都是隐蔽的坑,跳过任何一个后面排查起来都费劲。
第一件是主机名和 /etc/hosts。三台机器的主机名我分别设置为 hbase-1、hbase-2、hbase-3,然后在每台机器的 /etc/hosts 里都写上三行的映射关系。这一步非常关键,HBase 集群节点之间是通过主机名互相通信的,如果主机名解析不了,RegionServer 注册不上、HMaster 找不到数据节点都是常见的报错。
第二件是 SSH 免密登录。HBase 的启动脚本 start-hbase.sh 会通过 SSH 去各节点启动 RegionServer,所以从 hbase-1 到三台机器都要配置免密。做法就是把 hbase-1 的公钥加到每台机器的 authorized_keys 里,包括它自己。建议用专门的运行账号,比如统一创建 hbase 用户,而不是直接用 root。生产环境用 root 跑 HBase 不是不行,但出了问题不好追责,权限也不好控制,所以规范一点,单独建用户。
第三件是关闭防火墙和 SELinux。这个其实不用我多说,集群内部通信需要大量端口,如果防火墙没关,经常出现“连不上 ZK”“RegionServer 之间无法同步”这类问题。我在部署前会确认三台机器的防火墙状态,直接停掉或者放行必要端口。SELinux 同样建议先关掉,它的拦截日志又隐蔽,出了问题非常难排查。
第四件是时间同步。ZooKeeper 对节点间时间偏差很敏感,偏差过大会导致 session 频繁过期,HMaster 和 RegionServer 之间也是靠心跳维持状态的,时间不一致会出现各种诡异问题。我用 NTP 同步,三台机器指向同一台时间源,保证时间误差在秒级以内。
第五件是文件描述符限制。RegionServer 在高并发下会打开大量文件,默认的 1024 很容易被打满,然后报 “Too many open files” 崩溃。在 /etc/security/limits.conf 里把 hbase 用户的 nofile 调大到 65536 或更高。这个参数在压力测试时特别重要,部署后就顺手调好,别等线上出问题再改。
提示:上面这几项环境准备工作,有一个不成文的优先级——先改 hosts,再配免密,再同步时间。因为免密登录依赖主机名解析,时间同步的配置过程也需要用主机名访问各节点。
2. 核心配置文件逐项拆解
2.1 hbase-env.sh 里的三处必改项
HBase 解压之后,conf 目录下有两个最重要的文件:hbase-env.sh 和 hbase-site.xml。很多人喜欢直接照抄网上的配置,但不懂每一项什么意思,出了问题只能瞎猜。我先把 hbase-env.sh 里的关键项拆开讲。
第一处是 JAVA_HOME。这个文件默认有一行# export JAVA_HOME=/usr/java/jdk1.8.0/,需要把注释去掉,改成实际 JDK 安装路径。如果机器上配好了全局 JAVA_HOME,理论上这行不设也行,但 HBase 的启动脚本对 JAVA_HOME 的判断有时会走偏,所以我每次都会显式写上,避免它去 /usr/bin/java 里找一个不合适的版本。
第二处是 HBASE_MANAGES_ZK。这一项决定是否让 HBase 自己管理 ZooKeeper。设为 true,HBase 启动时会在集群各节点自动拉起一个 ZK 进程,适合单机测试;设为 false,HBase 只连接外部已有的 ZooKeeper 集群。三节点部署时我建议设为 false,因为独立 ZK 集群更稳定,也方便单独维护和排查。每次分享这个经验时都会有人问:用 HBase 自带的 ZK 不好吗?不是不好,是生产上你总得单独运维 ZK,与其后面再拆,不如一开始就分开部署。
第三处是 HBASE_HEAPSIZE。它控制 HBase 进程的 JVM 堆大小,默认是 1G,对测试环境够用,对线上环境偏小。我一般根据机器内存来设,测试机 8G 内存就设 2G,16G 内存可以设 4G。这里有个细节,这个参数影响的是 HMaster 和 RegionServer 的默认堆大小,但它们可以分别用 HBASE_MASTER_OPTS 和 HBASE_REGIONSERVER_OPTS 里的 -Xmx 单独覆盖。如果想精细控制,就显式指定。注意别把堆设得接近机器总内存,要给操作系统和其他进程留余地。
除了这三处,还有一个 HBASE_PID_DIR 值得关注,它存放 HBase 的 pid 文件。默认在 /tmp 下,但如果 /tmp 被系统清理,会导致一些管理脚本找不到进程。我会专门建一个 /data/hbase/pids 目录作为 pid 目录,避免这类诡异问题。
2.2 hbase-site.xml 关键参数与选值逻辑
hbase-site.xml 是整个部署的核心,里面每一项配置都直接影响集群行为。我按重要程度逐一说明。
首先是 hbase.rootdir。这一项指定 HBase 数据在 HDFS 上的存储根目录,我写的是hdfs://hbase-1:8020/hbase。这里的 8020 是 NameNode RPC 端口,要和你的 Hadoop 配置一致,有些 Hadoop 环境用的是 9000,写错了 HBase 连不上 HDFS 会直接起不来。还有一点要注意,这个路径指的是 HDFS 上的路径,不是本地磁盘路径。如果配成了file:///data/hbase,那 HBase 就是在单机本地模式运行,数据不会落到 HDFS 上,也就谈不上分布式存储了。
其次是 hbase.cluster.distributed。这个参数是分布式开关,false 表示单机模式,true 表示分布式模式。三节点集群里当然要设 true。我见过有人把这个漏掉了,结果 HBase 启动时以为自己在单机模式,各种行为都不对,日志也看不出来明显报错,非常误导人。
然后是 hbase.zookeeper.quorum。它指定 ZooKeeper 集群的节点列表,多个节点用逗号分隔。我写的是hbase-1,hbase-2,hbase-3。这里有个细节:官方建议写三到五个节点,而不要写两个,因为 ZK 集群通常是奇数节点才能正常选举,两个节点反而容易出问题。HBase 官方的说法是 quorum 的节点建议配置为 3 个或 5 个,写两个会有点尴尬。我的三个节点都部署了 ZK,所以这里也写全三个。
还有 hbase.zookeeper.property.clientPort,默认 2181。如果你的 ZK 客户端端口改过,这里就要对应改。三台机器要保持一致,否则 HBase 连到不同节点时端口不一致,会随机出现连接失败。
最后再提两个参数,不必须改,但建议理解。一个是 hbase.master.info.port,默认 16010,是 HMaster Web UI 的端口,浏览器访问http://hbase-1:16010可以看到集群状态。另一个是 hbase.regionserver.handler.count,默认 30,表示 RegionServer 同时处理 RPC 请求的线程数,如果业务读写并发高,可以适当调到 50 甚至 100,但别盲目调大,线程数多了线程切换开销也会增加。
2.3 regionservers 文件与角色分配
conf 目录下还有一个 regionservers 文件,没有后缀,每行写一个主机名,作用是告诉 HMaster 集群中有哪些 RegionServer。在三节点方案里,我会把 hbase-2 和 hbase-3 写进去,因为这两个节点是真正的 RegionServer。hbase-1 作为 HMaster,本身不承担 RegionServer 角色,所以不写进去。当然如果你想在 Master 节点也跑 RegionServer,也可以写进去,但一般不建议,Master 节点要做的事情已经不少了。
这里顺便说下角色分配逻辑。三节点部署比较标准的方案是:hbase-1 跑 HMaster,hbase-2 和 hbase-3 跑 RegionServer。同时三个节点都跑 DataNode 和 ZooKeeper。这样既保证了 Master 的独立性,又最大化利用了资源。如果你有多台机器,可以再拆细一点,把 ZK 也独立出去,但三台机器按这个方案来是最高效的。
写完 regionservers 文件后,记得检查有没有多余的空格、空行或 Windows 的换行符。这些小问题平时不注意,分发到各节点后会导致 HBase 读取主机名时带上奇怪字符,然后报 UnknownHost。我习惯用cat -A regionservers看原始字符,确认每行结尾干净。
3. 完整部署实操过程记录
3.1 获取安装包与基础目录检查
先从官方下载页获取 HBase 2.3.7 的二进制发布包,文件名类似hbase-2.3.7-bin.tar.gz。下载后先校验一下 MD5,防止下载过程文件损坏。损坏的包在解压时可能不报错,但启动时会出各种找不到类的问题。
解压到一个固定目录,比如/opt/hbase/hbase-2.3.7。我喜欢在 /opt/hbase 下建一个软链,ln -s hbase-2.3.7 hbase,这样以后升级版本时只需要替换软链,不用改各种配置路径。HBase 的目录结构里,conf 放配置,lib 放依赖 jar,logs 放运行日志。启动失败时第一时间要去 logs 目录看日志,这一点后面排错还会反复用到。
解压完成后,先把 conf 目录里的 hbase-env.sh 和 hbase-site.xml 备份一份,避免改乱了没有原始参考。我习惯在 conf 目录下创建一个conf.backup文件夹,把原始文件复制进去。这不是必须的,但能让你在反复调试配置时心里有底。
3.2 配置文件编写与同步分发
在主节点 hbase-1 上编辑好所有配置后,要同步到其他节点。我用的就是 scp 命令,把整个 conf 目录分发到 hbase-2 和 hbase-3。之所以强调“整个 conf 目录”,是因为如果只分发个别文件,容易漏掉。另外,每个节点的 hbase-env.sh 中 JAVA_HOME 路径理论上应该一致,因为三台机器环境是一样的。
同步完之后,建议在每台节点上做一次快速检查。检查项包括:hbase-site.xml 里的 quorum 和 rootdir 是否一致、regionservers 文件内容是否正确、hbase-env.sh 里 JAVA_HOME 是否存在。我通常是直接 cat 一遍关键配置确认,虽然繁琐,但比后面启动失败再回头查要快得多。
分发还有一个容易被忽略的点:conf 目录文件的属主。因为前面建了 hbase 用户,配置文件应该 chown 给 hbase 用户,否则启动脚本可能因为权限问题无法读取或写入 pid 文件。我碰到过一次所有配置都正确但 HMaster 起不来的情况,最后发现就是 conf 目录属主不对。
提示:配置文件同步完成之后,不要急着启动 HBase。先单独启动 Hadoop 和 ZooKeeper,确认这两个依赖服务状态正常,再启动 HBase。依赖服务都没起来就启动 HBase,只会看到一堆连接拒绝的报错,而且日志很杂,容易掩盖真正的问题。
3.3 HBase 集群启动与功能验证
启动顺序是固定的:先启动 HDFS,再启动 ZooKeeper,最后启动 HBase。
HDFS 启动命令在 Hadoop 的 sbin 目录下执行start-dfs.sh,启动后用hdfs dfsadmin -report检查 DataNode 是否都上线。确认 HDFS 状态正常后,用zkServer.sh start在三台机器上分别启动 ZooKeeper,或者通过自己的 ZK 集群管理脚本统一操作。ZK 启动后用zkServer.sh status检查 mode,正常情况下三节点里会有一个 leader、两个 follower。这个状态确认好了再往下走。
最后在 HBase 主节点执行start-hbase.sh。这个脚本会启动本机的 HMaster,并通过 SSH 到 regionservers 文件里写的每个节点启动 RegionServer。启动后运行jps查看 Java 进程,HMaster 节点应看到 HMaster 进程,RegionServer 节点应看到 HRegionServer 进程,三个节点还各有 QuorumPeerMain 进程表示 ZooKeeper 在跑。
进程都在了,还需要做两层验证。第一层是 Web UI,浏览器访问http://hbase-1:16010,应该能看到 HBase 管理页面,里面显示 RegionServer 列表以及每个 RegionServer 的负载情况。第二层是 HBase Shell,命令行输入hbase shell进入交互界面,然后执行status命令,正常情况下应该显示类似1 active master, 2 backup masters外加2 RegionServer的信息。然后我再跑一轮真实读写测试:
create 'test_table', 'cf' put 'test_table', 'row1', 'cf:name', 'hello_hbase' scan 'test_table'如果 create 能成功、put 之后 scan 能看到数据,说明 HBase 集群的基本读写链路是通的。这一步非常关键,有些集群虽然进程都在,但 HDFS 连接有问题,读写时才会暴露出来。
4. 常见启动故障排查与实用经验
4.1 高频报错对照速查表
安装 HBase 的过程中,有几个报错我几乎每次都会遇到,或者是看到身边同事反复踩。我整理成了一张速查表,方便对照排查。
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| HMaster 启动后马上退出,日志末尾没有明显异常 | hbase.rootdir 写成了本地路径,或 hbase.cluster.distributed 未设为 true | 检查 hbase-site.xml 中 rootdir 是否是 hdfs:// 开头,确认 distributed 为 true |
| RegionServer 一直起不来,日志提示 ConnectionLoss | ZooKeeper 未启动,或 quorum 节点列表写错 | 先确认三台 zkServer.sh status 正常,再检查 hbase-site.xml 的 quorum |
| UnknownHostException: hbase-2 | /etc/hosts 没配置完整 | 三台机器的 hosts 都补全所有节点映射 |
| Can't get master address from ZooKeeper | HMaster 还在启动中,或者已经挂掉 | 先等几秒再执行 status,若 HMaster 进程不在则查 HMaster 日志 |
| Too many open files | ulimit 文件描述符限制太小 | 调大 limits.conf 中 nofile 并重新登录会话 |
| ZooKeeper session expired | 节点间时间不同步,或 ZK 负载过高 | 用 NTP 同步时间,检查 ZK 日志有没有频繁 GC |
这张表不是让你遇到问题才看,而是建议在启动 HBase 之前就逐项对照一遍,提前排除大半风险。
4.2 排查过程中的定位思路
很多人遇到 HBase 启动失败,第一反应是去搜索引擎复制日志,但排查问题最有效的方式其实是顺着日志一层层往上找。HBase 启动后,日志文件在 logs 目录下,HMaster 的日志类似hbase-hbase-master-hbase-1.log,RegionServer 的日志类似hbase-hbase-regionserver-hbase-2.log。启动失败时,先看对应节点的日志文件,不要只看控制台输出。
我的排查顺序是:先看 HMaster 日志,因为 HMaster 是集群的入口,它起不来或者起来后挂了,后面所有问题都无从谈起。HMaster 日志中最常见的是连接 ZooKeeper 或 HDFS 失败,这类错误通常指向环境配置而不是 HBase 本身。然后看 RegionServer 日志,它会尝试向 HMaster 注册,如果注册不上会反复重试,日志中出现 ConnectionLoss 或 SessionExpired,就要回头排查 ZK 和网络。
另一个容易被忽略的思路是“看日志的时间戳”。如果 HMaster 日志显示启动后几秒就退出,多半是初始化阶段就失败,比如配置错误或依赖服务没起来。如果运行了很久才挂,再考虑资源限制、GC 或外部因素。时间戳能帮你快速缩小排查范围,比漫无目的地看日志有效得多。
还有一个经验:遇到 HMaster 起不来,先检查 hbase-site.xml 是否被其他节点分发覆盖掉了。分布式的坑往往不是配置本身写错,而是某个节点上的配置文件是旧版本,导致这个节点行为不一致。所以每改一次配置,我都要在每台节点上确认一遍。
4.3 部署完成后的三项稳定性检查
集群能正常启动、能读写数据,这只能算部署成功了一半。完整验证还要做三项稳定性检查,这三项分别对应数据持久化、故障恢复和性能水位。
第一项是 HBase 数据持久化检查。通过 HBase Shell 写入数据后,重启整个 HBase 集群,再 scan 之前创建的表,确认数据还在。数据存在 HDFS 上,理论上重启不会丢,但只有实测过你才能确信自己的架构是通的。这个测试特别适合在刚部署完那几天做,早发现问题早解决。
第二项是故障恢复检查。手动 kill 掉一台 RegionServer 的进程,观察 HMaster 是否能感知并把这个 RegionServer 上服务的 region 重新分配到其他节点。正常情况下,HMaster 会在几百秒内完成 region 迁移,Web UI 上能看到 region 数量重新均衡。如果 HMaster 迟迟没有反应,说明心跳参数或 ZK session 超时设置可能有需要调整的地方。
第三项是负载检查。通过 HMaster 的 Web UI 看每个 RegionServer 的 region 数量和请求数是否大致均衡。如果某台机器上的 region 特别多,就需要考虑预分区策略,不然写入热点问题会在真实业务里被放大。
个人使用中的几点补充建议
这里分享几个我在部署 HBase 2.3.7 过程中的个人体会。第一个是独立 ZooKeeper 集群真的很有必要,虽然 HBase 自带 ZK 很方便,但自带的 ZK 和 HBase 进程共用一套日志体系,出问题时不方便定位,而且 HBase 重启时 ZK 也会跟着重启,集群的协调状态就全丢了。第二个是配置同步之后不要急着启动,先跑一遍快速检查命令,确认每个节点上的配置是最新的,这一步能节省后面大量的排错时间。第三个是日志目录要单独挂在数据盘上,不要放在系统盘,否则日志量大的时候容易撑满磁盘,HBase 会直接拒绝服务。第四个是启动后记得观察至少五分钟,确认 HMaster 和 RegionServer 不会在启动后几分钟内悄悄退出,这种“延迟死亡”现象比启动直接失败更难发现,也更危险。希望这份部署记录能帮你少走一些弯路,如果后面遇到什么奇怪的安装问题,不妨按文章里的排查顺序走一遍,大概率能定位到问题所在。