HBase 性能问题很少只由一个参数造成。热点 Region、StoreFile 过多、compaction backlog、BlockCache 命中率下降、GC 停顿、HDFS locality 变差,都会表现成读写延迟上升。调优的第一步不是改配置,而是把症状映射到可观察对象。

本篇只抓一个核心问题:如何用 Metrics、hbtop、JMX 和服务端状态识别热点 Region、compaction backlog、缓存失配、GC 和磁盘瓶颈。

观察路径图

flowchart TD
  Slow[读写变慢] --> Client[Client retry/timeout]
  Slow --> RS[RegionServer metrics]
  RS --> Hot[Region #REQ/S/#WRITE/S]
  RS --> Cache[BlockCache hit/miss]
  RS --> Store[#SF / StoreFile size]
  RS --> Compaction[Compaction queue/progress]
  RS --> GC[JVM GC pauses]
  Store --> HDFS[Block locality / HDFS IO]
  Compaction --> HDFS

这条路径把“慢”拆成五类问题。请求是否集中到少数 Region;读是否频繁穿透 BlockCache;StoreFile 数是否太多;compaction 是否追不上 flush;JVM 或 HDFS 是否成为瓶颈。每一类都有可观察指标。

官方 Metrics 文档说明,HBase 使用 Hadoop Metrics API,默认带一组 metrics 配置,可通过 JMX、HTTP /jmx/metrics 或 Prometheus 相关方式接入监控。官方 hbtop 文档提供交互式视图,支持 Region、Namespace、Table、RegionServer、User、Client 等模式。

hbtop 读法

hbtop 是快速定位的入口,不是长期监控替代品。它每隔一段时间刷新,把 Region、表、namespace、RegionServer 等维度的请求和存储状态排出来。

1
hbase hbtop

Region 模式里常用字段包括:

字段 含义 常见判断
#REQ/S 每秒请求数 是否有热点 Region
#READ/S 每秒读请求 读热点
#WRITE/S 每秒写请求 写热点
#SF StoreFile 数 读放大和 compaction 压力
MEMSTORE MemStore 大小 flush 压力
LOCALITY Block locality 读是否跨节点
%COMP compaction 进度 后台合并是否长期占用

热点 Region 的信号通常是少数 Region 的 #REQ/S#WRITE/S 远高于同表其他 Region。原因常见于 row key 前缀单调递增、salt 桶数不足、时间桶粒度过粗、预分区缺失。处理方式回到第 03 篇的 row key 设计,而不是先调 RegionServer 线程数。

StoreFile 数过多会增加读放大。一个 Get 可能要在 MemStore 和多个 HFile 中合并可见版本;Bloom Filter 和 BlockCache 能降低代价,但不能把多个 StoreFile 的元数据、索引和 seek 成本消掉。

LOCALITY 降低通常意味着 Region 迁移或 HDFS block 放置和 RegionServer 不再同节点。HBase 仍能读,只是读路径可能跨网络。重启、balance、Region move 之后要观察 locality 逐步恢复。

Metrics 和 JMX

RegionServer 的 HTTP UI 暴露 /jmx/metrics 等监控端点。Metrics2 的常见接法是把 conf/hadoop-metrics2-hbase.properties 配成对应 sink,然后由 Prometheus、Ganglia 或其他系统采集。

1
curl http://regionserver-host:16030/jmx
1
curl http://regionserver-host:16030/metrics

这两条命令的端口和路径依部署而定,当前本地没有运行的 RegionServer,标记为 UNVERIFIED_RUNTIME。文章不提供固定 JSON 输出,因为不同版本、sink 和开关会改变字段集合。

Metrics 的正确用法是做关联判断:

症状 指标组合 初步方向
点查变慢 BlockCache miss 上升 + #SF cache 失配或读放大
写入变慢 MemStore 接近阈值 + flush queue 增长 flush 压力
后台 IO 高 compaction queue 高 + HDFS 写吞吐高 compaction backlog
局部超时 单 Region #REQ/S row key 热点
全局抖动 GC pause 上升 + handler backlog JVM 或内存压力

单个指标很容易误导。BlockCache hit 下降可能是 scan 把缓存污染了,也可能是工作集变大,还可能是 Region 刚迁移导致冷 cache。必须同时看访问模式、Region 分布和 StoreFile 状态。

Compaction backlog

Compaction 是 HBase LSM 路径的后台成本。写入先进入 WAL 和 MemStore,flush 生成 HFile;多个 HFile 再通过 minor 或 major compaction 合并。写入压力大于 compaction 能力时,StoreFile 数会增长,读放大会变高,最终可能触发写入限流。

诊断 compaction backlog 需要看三类信号。

第一,#SF 持续增长。单个 Store 的 StoreFile 数越多,读路径要检查的文件越多。Bloom Filter 可以避免一部分无关文件,但不能消除所有读放大。

第二,compaction queue 长期不下降。短时间队列上升是正常后台行为,长期积压说明磁盘、线程或策略跟不上。

第三,HDFS 和磁盘写压力升高。Compaction 读旧 HFile、写新 HFile,再删除旧文件;它会制造额外 I/O。把 compaction 线程简单调大,可能只是把磁盘打满。

处理顺序通常是:先判断热点是否导致单 Region StoreFile 暴涨,再判断 flush 太频繁是否来自 MemStore 配置或写入突刺,最后再调 compaction 相关线程和阈值。顺序反过来会把架构问题掩盖成参数问题。

Scan 和缓存污染

第 14 篇讲过 Scan#setCacheBlocks(false) 的边界。大范围一次性 scan 如果默认进入 BlockCache,会把热点点查需要的数据挤出去。症状是 scan 期间或之后点查延迟上升,BlockCache miss 增加。

这类问题不该先扩大 cache。更小的改动是按访问模式设置 scan 参数:一次性批处理 scan 关闭 block cache;交互式范围查询保留合理 caching;热点点查保留缓存。访问模式不同,缓存策略也要不同。

这也是 HBase 宽列模型的直接后果。列族是物理存储边界,BlockCache 和 HFile 都按列族组织。冷热数据混进同一列族,会让 scan 和点查互相污染。

最小实验

以下实验需要 HBase 2.6.6 集群,当前本地不可执行,标记为 UNVERIFIED_RUNTIME。实验先建立一张表,再用单调 row key 写入制造热点。

1
hbase shell

Shell 内创建 namespace 和表:

1
2
create_namespace 'lab'
create 'lab:hotspot', 'cf'

启动连续写入程序后打开 hbtop,观察请求是否集中到一个 key range。

1
hbase hbtop

观察 Region 模式下 #WRITE/S 是否集中在最后一个 key range。再把 row key 改为 salt 前缀,重新写入同等规模数据,比较 Region 维度分布是否更均匀。

制造 scan 缓存污染时,先记录点查 BlockCache 指标,再运行一次大范围 scan。Java 代码应显式区分两种 scan:

1
2
3
Scan offlineScan = new Scan().withStartRow(Bytes.toBytes("u#0000")).withStopRow(Bytes.toBytes("u#9999"));
offlineScan.setCacheBlocks(false);
offlineScan.setCaching(500);

这段 API 形状按 HBase 2.6 public API 核对,未在本地编译,标记为 UNVERIFIED_RUNTIME

失败恢复

性能调优失败常见于“改了参数但没有回看指标”。每次变更都应绑定一个观察窗口:变更前指标快照、变更项、变更后同一批指标。没有快照,就不能判断变更是否有效。

热点 Region 的恢复通常要改 row key 或做预分区。临时 move Region 只能改变承载节点,不能改变 key 分布。写入仍然集中到一个 Region 时,新节点也会继续热。

Compaction backlog 的恢复要防止把磁盘压垮。增加 compaction 线程前先看磁盘利用率、HDFS 写吞吐和 RegionServer GC。磁盘已满载时,更多线程只会制造更长队列。

BlockCache 失配的恢复要回到访问模式。把所有 scan 都设成大 caching,或把所有 scan 都关闭 cache,都会伤害另一类请求。按任务类型区分参数更稳。

工程迁移

HBase 症状 迁移到其他系统的同类问题 处理模式
热点 Region 分片数据库热点 shard 改 key 分布
StoreFile 过多 LSM SSTable 过多 控制后台 merge
BlockCache miss 应用缓存命中率下降 分离冷热访问
GC pause JVM 服务抖动 限制对象分配和堆压力
locality 降低 计算存储错位 重新放置或预热

模式提炼:先把慢请求映射到对象,再把对象映射到成本。Region 是负载对象,StoreFile 是读放大对象,MemStore 是写缓冲对象,BlockCache 是读缓存对象,compaction 是后台 I/O 对象。

常见误解

误解一:HBase 慢了就调大线程。线程只是执行资源,热点、读放大和磁盘瓶颈不会因为线程变多而消失。

误解二:BlockCache 越大越好。缓存如果被大 scan 污染,扩大缓存只能推迟问题。

误解三:Major compaction 是常规提速按钮。Major compaction 会产生大量 I/O,应作为受控维护操作,不应在业务高峰随意触发。

误解四:Region move 能解决 row key 热点。move 只能换机器,不能改变数据分布。

练习

  1. 给一张写热点表画出排查顺序:hbtop Region 模式、hbase:meta key range、row key 样本、预分区方案。
  2. 设计一个 scan 缓存污染实验,列出运行前后必须采集的 BlockCache 指标。
  3. 把 compaction backlog 和 GC pause 同时出现的场景拆成两个独立假设,分别写出验证指标。

系列导航

参考资料

证据等级:指标入口、hbtop 字段和诊断边界为 VERIFIED_SOURCE;本地未运行 HBase 集群,实验为 UNVERIFIED_RUNTIME