7.2 扩缩容与备份恢复:落点的迁移与兜底 本节摘要:扩容加机器很快,真正的成本在数据本地性的重建;缩容的关键是 draining 式优雅下线,先把 Region 搬走再停进程。备份体系由三层组成:快照做秒级零成本的一致性视图,Export 做异构介质的离线副本,Replication 做跨集群的持续容灾。本节给出每一步的操作序列与底层机制。 扩容:机器好加,本地性难养 集群磁盘水位到了七成五、或者写入吞吐顶到网卡一半,就该扩容了。操作本身不复杂,四步: 新机器装同版本 JDK 与 HBase,配置文件从现有节点原样拷贝(ZooKeeper 仲裁地址、rootdir 等关键项必须一字不差); 把主机名加进 RegionServer 名单文件,确认 SSH 免密可达;
本节摘要:扩容加机器很快,真正的成本在数据本地性的重建;缩容的关键是 draining 式优雅下线,先把 Region 搬走再停进程。备份体系由三层组成:快照做秒级零成本的一致性视图,Export 做异构介质的离线副本,Replication 做跨集群的持续容灾。本节给出每一步的操作序列与底层机制。
集群磁盘水位到了七成五、或者写入吞吐顶到网卡一半,就该扩容了。操作本身不复杂,四步:
但"机器上线"不等于"性能到手",这里有个容易被忽略的账:数据本地性。回顾 3.1 节,Region 迁到新 RegionServer 后,它的 HFile 副本还在老机器的磁盘上,新宿主每次读都要走网络。HDFS 的副本放置要等下一次 Compaction 重写文件时,才会按新的写入方重新分布——也就是说,新扩的机器要经历一轮 Major Compaction 才能获得真正的本地读。这期间集群的读延迟不降反升,是扩容后一两天内的正常现象,别急着回滚。
均衡器(Balancer)决定 Region 流向谁。它周期性运行,目标是让各机器的 Region 数趋于平均:
hbase:095:0> balancer true hbase:096:0> balance_switch true true
返回 true 表示本轮均衡已发起。要注意均衡器默认只看 Region 数量,不看请求负载——如果某台机器上恰好是几个热点 Region,数量均衡了负载还是斜的。这种情况下手动迁移更直接:
hbase:097:0> move '7f8e....region.en:code', 'vm4,16020,1724088'
第一条参数是 Region 的编码名(Web UI 或 list_region 可查),第二个是目标 RegionServer。紧急热点处理时,把烫手 Region 手动挪到空机器,比任何自动策略都快。
缩容的操作风险远高于扩容——直接 kill 进程虽然也能触发自动恢复,但等于人为制造一次宕机:WAL 切分、Region 重分配、客户端重试风暴,全套流程都要走一遍。正确姿势是 draining(排水式)下线,让 Region 先搬空再停机:
# 1. 准备下线的机器进入排水状态(放到 draining 节点集合) $ bin/graceful_stop.sh --config /etc/hbase vm3 disable regions on vm3 ... gracefully moving regions off vm3 ... Moved 152 regions in 214s stopping regionserver on vm3 ...
这个脚本做三件事:把 vm3 加入 ZooKeeper 的 draining 节点(Master 从此不给它分配新 Region)、逐个把它名下的 Region 迁到其他机器、全部迁完后停掉进程。两百余个 Region 约三四分钟,期间业务无感。之后再把它从 RegionServer 名单文件移除,缩容完成。
顺序千万不能反。先停进程再迁 Region,就是上面说的"人为宕机";生产上这类事故的典型形态是:值班同学想重启一台机器,直接 kill,结果该机器上有个大 Region 正在 Compaction,恢复花了四十分钟。

快照(Snapshot)是 HBase 备份的看家本领,原理见图 7.2-1 下半部分:它只是对表当前 HFile 的一份元数据指针清单,不复制任何数据块,所以创建在秒级完成、额外空间接近零。这个特性让"改 Schema 前先拍一张"变成零成本动作。
hbase:100:0> snapshot 'orders', 'orders_20240821' hbase:101:0> list_snapshots SNAPSHOT TABLE + CREATION TIME orders_20240821 orders (2024-08-21 02:00:11 +0800) 1 row(s) # 恢复 = 回到快照时刻(表需先禁用) hbase:102:0> disable 'orders' hbase:103:0> restore_snapshot 'orders_20240821' hbase:104:0> enable 'orders' # 更安全的用法:克隆出新表先验证 hbase:105:0> clone_snapshot 'orders_20240821', 'orders_verify'
恢复与克隆的差别要分清:restore 是把原表拉回快照时刻,快照之后的新写入全部丢失;clone 生成一张新表,原表不动。生产上我永远先 clone 验证数据,确认无误再决定要不要 restore——回滚动作本身也要留后路。
快照有两个隐性成本。其一,被快照引用的文件在 Compaction 时只能归档不能删除,长期不清理的快照会让归档目录悄悄膨胀,保留策略要明确(比如保留最近七天每天一张、每月一张长期档)。其二,快照是集群内副本——HDFS 坏三块盘它救不了你,所以必须有第二层。
Export 把快照数据导出到另一个存储介质(另一套 HDFS、对象存储、磁带库),构成真正的异地副本:
# 先拍快照再导出 保证一致性视图 $ hbase snapshot create -n orders_export -t orders $ hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot \ -snapshot orders_export -copy-to hdfs://backup-cluster/hbase_backup \ -mappers 16
导出过程走的是 HDFS 层面的数据块拷贝(所以参数叫 mappers 而不是扫描并发),对 RegionServer 几乎零压力,只占用网络与 DataNode 磁盘。恢复时在目标集群 Import,或者直接把导出的 HFile 用 bulkload 挂载成新表。
Replication 是第三层,跨集群持续同步(6.3 节讲过机制:主集群 WAL 异步推送到备集群回放)。它解决的是快照与导出都解决不了的问题:分钟级的 RPO。三层体系各有边界:
| 手段 | 空间成本 | 恢复速度 RTO | 数据丢失窗口 RPO | 防什么 |
|---|---|---|---|---|
| 快照 | 近零 | 秒到分钟 | 回到快照点 | 误删、坏变更、逻辑错误 |
| Export 异地 | 一份全量 | 小时级 | 上次导出时刻 | 机房级灾难、HDFS 损坏 |
| Replication | 一套备集群 | 分钟级切换 | 秒到分钟 | 主集群整体故障 |
注意防的对象里,逻辑错误只有快照能防——删表、错批量更新这类事故,Replication 会忠实地把错误复制到备集群,一点不少。这也是"快照是第一层"的原因:它防的恰恰是最常见的灾难(人)。
⚠️ 常见坑:drop 表前忘了它会连带删掉关联快照的恢复能力评估——快照本身不随表删除,但 restore 需要表名匹配。养成固定节奏:每天低峰自动快照、每周一次恢复演练(clone 出来跑行数对账)。没演练过的备份只是心理安慰。
有了观测与变更能力,剩下的问题是:出了事怎么最快收敛?下一节把常见故障整理成一张决策树。