HBase列族数据库
00:00
HBase架构原理、Region管理、RowKey设计、读写流程与性能优化。
1. HBase架构设计
HBase 是基于 HDFS 的分布式列族数据库,提供海量数据的随机读写能力。
1.1 核心概念
| 概念 | 说明 | 类比RDBMS |
|---|---|---|
| RowKey | 行唯一标识 | 主键 |
| Column Family | 列族,列的分组 | 列组 |
| Column Qualifier | 列族内的列 | 列名 |
| Cell | RowKey+CF+CQ+Timestamp → Value | 单元格 |
| Region | 表的水平分片 | 分区 |
| Store | Region中一个列族的存储 | — |
| HFile | Store的实际数据文件 | 数据文件 |
| MemStore | 内存写入缓冲 | — |
数据模型:
RowKey CF1 CF2
┌─────────┬─────────┐ ┌─────────┐
row1 │ col1:t2 │ col2:t1 │ │ col1:t1 │
│ "val3" │ "val1" │ │ "val2" │
└─────────┴─────────┘ └─────────┘
row2 ┌─────────┐
│ col1:t1 │
│ "val4" │
└─────────┘
1.2 系统架构
┌──────────────────────────────────────────────────┐
│ Client │
└──────────────┬──────────────────┬────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ HMaster │ │ ZooKeeper │
│ 表/Region管理 │ │ Master选举 │
│ 负载均衡 │ │ Region定位 │
│ 元数据维护 │ │ 集群状态 │
└──────────────────────┘ └──────────────────────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│Region ││Region ││Region │
│Server1 ││Server2 ││Server3 │
│┌──────┐││┌──────┐││┌──────┐│
││Region││││Region││││Region││
││ A,B ││││ C,D ││││ E,F ││
│└──────┘││└──────┘││└──────┘│
└────────┘└────────┘└────────┘
1.3 Region管理
Region 是 HBase 分布式和负载均衡的最小单元:
- 每个表初始为一个 Region,随数据增长自动分裂
- Region 分裂阈值:
hbase.hregion.max.filesize(默认10GB) - 分裂过程:先下线再分裂再上线
Region 定位流程:
Client → ZooKeeper → hbase:meta表 → RegionServer → Region
2. RowKey设计
RowKey 设计是 HBase 性能的决定性因素,直接影响数据分布和查询效率。
2.1 设计原则
| 原则 | 说明 | 原因 |
|---|---|---|
| 唯一性 | RowKey全局唯一 | 主键约束 |
| 长度适中 | 10~100字节 | 过长影响存储和索引效率 |
| 散列分布 | 避免热点 | 均匀分布到所有Region |
| 有序性 | 支持范围扫描 | HBase按RowKey字典序存储 |
2.2 热点问题与解决方案
问题:顺序写入导致所有请求集中在一个Region
RowKey: user1 → Region A ← 所有写入
RowKey: user2 → Region A ← 所有写入
RowKey: user3 → Region A ← 所有写入
解决方案:
- 加盐(Salting):在RowKey前添加随机前缀
原始: user1, user2, user3
加盐: a-user1, b-user2, c-user3 → 分散到不同Region
- 哈希(Hashing):对RowKey取哈希
- 反转(Reversing):反转RowKey字符串
原始: 20240101-user1 → 集中写入
反转: 1resu-10104202 → 分散写入
2.3 常见设计模式
| 模式 | RowKey格式 | 适用场景 |
|---|---|---|
| 时间序列 | userId_reverse + Long.MAX_VALUE - timestamp | 按用户查最新数据 |
| 查询优先 | 查询维度 + 时间戳 | 按维度范围查询 |
| 散列前缀 | hash(prefix) % N + 原始Key | 写入均衡 |
| 复合RowKey | regionId + '#' + userId + '#' + timestamp | 多维度查询 |
3. 读写流程
3.1 写入流程
Client → WAL → MemStore → HFile
│ │ │
│ │ └── Flush(内存→磁盘)
│ └── 写入内存(有序)
└── 预写日志(故障恢复)
详细步骤:
- 客户端定位目标 RegionServer
- 写入 WAL(Write-Ahead Log):确保数据不丢失
- 写入 MemStore:内存中的有序数据结构
- 返回客户端写入成功
- MemStore 达到阈值(128MB)时 Flush 为 HFile
- HFile 增多时触发 Minor Compaction(合并小文件)
- 定期触发 Major Compaction(合并所有HFile,清理删除标记)
3.2 读取流程
Client → BlockCache → MemStore → HFile
│ │ │
│ │ └── Bloom Filter快速判断
│ └── 读内存
└── 读缓存(LRU)
读取优化:
- BlockCache:LRU缓存,缓存热点数据块(默认64KB)
- Bloom Filter:快速判断RowKey/Column是否在HFile中
- TimeRange:利用时间戳过滤HFile
3.3 LSM-Tree模型
HBase 基于 LSM-Tree(Log-Structured Merge-Tree):
写入: MemStore(C0) → Flush → HFile(C1) → Compaction → HFile(C2)
内存 磁盘Level1 磁盘Level2
- 写入性能:(只写内存)
- 读取性能:(需合并多层数据)
- 空间放大:通过Compaction回收
4. HBase性能优化
4.1 关键配置
| 参数 | 默认值 | 说明 |
|---|---|---|
hbase.hregion.max.filesize | 10GB | Region最大大小 |
hbase.regionserver.global.memstore.size | 0.4 | MemStore占堆内存比例 |
hfile.block.cache.size | 0.4 | BlockCache占堆内存比例 |
hbase.hstore.compactionThreshold | 3 | 触发Minor Compaction的文件数 |
hbase.hregion.memstore.flush.size | 128MB | MemStore Flush阈值 |
4.2 优化策略
- 预分区:建表时指定Region分裂点,避免初始热点
- Bloom Filter:ROW或ROWCOL级别,减少无效磁盘读取
- 列族数量:不超过3个,每个列族独立Store和Flush
- Compaction策略:FIFO / Exploring / Stripe / Date Tiered
- Region大小:根据读写模式调整,过大导致Compaction压力大
- GC优化:使用G1GC,减少GC停顿