HBase 的存储模型是其高性能和可扩展性的核心。与传统的行式数据库不同,HBase 采用面向列族的存储,并具有多层次的分布式存储架构。下面详细解析其存储模型。
HBase 存储模型从逻辑到物理的层次结构:
Table (逻辑表)
↓
Regions (表的水平分区,按行键范围划分)
↓
RegionServer (物理服务器,托管多个Region)
↓
Store (每个Region中对应一个列族)
↓
MemStore (内存写缓冲区)
↓
HFile (磁盘上的实际数据文件,存储在HDFS上)核心机制:
Region分割过程:
初始状态:
Table → 单个空Region (范围: 无界)
随着数据增长:
Table → [Region1 (-∞, "mid_key")] [Region2 ("mid_key", +∞)]
继续增长:
Table → [Region1] [Region2] [Region3] ...Region特性:
一个Region的内部存储结构:
Region (负责一段连续的行键范围)
├── Store 1 (对应列族CF1)
│ ├── MemStore (写缓存,内存)
│ └── HFiles (实际数据文件,HDFS)
├── Store 2 (对应列族CF2)
│ ├── MemStore
│ └── HFiles
└── WAL (Write-Ahead Log,预写日志)重大特点:
Client写入请求
↓
1. 写入WAL (Write-Ahead Log) ← 保证持久性
↓
2. 写入MemStore (内存缓冲区) ← 快速响应
↓
3. MemStore达到阈值时触发Flush
↓
4. 内存数据写入新的HFile (HDFS)写路径关键点:
MemStore的作用:
MemStore刷写条件:
刷写过程:
MemStore (内存中的有序数据)
↓ 刷写
新的HFile (磁盘上的有序文件)
↓
旧MemStore清空,新的写入继续HFile是HBase实际存储数据的文件格式,存储在HDFS上。
HFile 3.0结构:
Data Blocks (多个数据块)
↓
Leaf Index Block (叶索引块)
↓
Intermediate Index Blocks (中间索引块,可选)
↓
Root Index Block (根索引块)
↓
Meta Blocks (元数据块,可选)
↓
Trailer (文件尾信息)
↓
Bloom Filter (布隆过滤器,可选)
↓
Data Block Index (数据块索引)数据块结构:
KeyValue1 → KeyValue2 → ... → KeyValueNKeyValue格式:
[Key Length] [Value Length] [Row Key] [Column Family]
[Column Qualifier] [Timestamp] [Key Type] [Value]示例:{rowkey: "user001", cf: "info", cq: "name", ts: 1641024000, value: "Alice"}
在磁盘存储为:
0x00 0x00 0x00 0x06 0x00 0x00 0x00 0x05 // KeyLen=6, ValueLen=5
0x75 0x73 0x65 0x72 0x30 0x30 0x31 // "user001"
0x69 0x6E 0x66 0x6F // "info"
0x6E 0x61 0x6D 0x65 // "name"
0x61 0xCC 0x5B 0x00 // Timestamp
0x04 // KeyType=Put
0x41 0x6C 0x69 0x63 0x65 // "Alice"Client读取请求
↓
1. 定位RegionServer (通过.META.表)
↓
2. 访问BlockCache (内存缓存)
↓
3. 检查MemStore (内存中的未刷写数据)
↓
4. 如果需要,扫描HFiles
│ ↓
│ 4.1 使用Bloom Filter快速判断是否存在
│ ↓
│ 4.2 通过索引定位数据块
│ ↓
│ 4.3 从HDFS读取数据块
↓
5. 合并MemStore和HFile中的结果
↓
6. 返回客户端读优化技术:
随着写入,会产生大量小HFile,Compaction是合并优化过程。
Minor Compaction (小合并):
Major Compaction (大合并):
Compaction过程:
多个小HFile (可能包含重复、过期数据)
↓ Compaction
单个大HFile (已排序、去重、清理)/hbase
├── data
│ ├── default # namespace
│ │ ├── user_table # 表
│ │ │ ├── 0123456789abc # Region
│ │ │ │ ├── .regioninfo
│ │ │ │ ├── .tmp
│ │ │ │ ├── info # 列族Store目录
│ │ │ │ │ ├── 9876543210.hfile # HFile
│ │ │ │ │ ├── 8765432109.hfile
│ │ │ │ │ └── .regioninfo
│ │ │ │ ├── contact # 另一个列族Store
│ │ │ │ │ ├── 7654321098.hfile
│ │ │ │ │ └── .regioninfo
│ │ │ │ └── recovered.edits
│ │ │ └── abcdef012345 # 另一个Region
│ │ └── order_table
│ ├── hbase:meta # 元数据表
│ └── hbase:namespace
├── WALs # 预写日志目录
│ ├── server1,16020,1234567890
│ └── server2,16020,1234567891
└── oldWALs # 旧的WAL文件两级元数据表结构:
元数据查找流程:
Client → ZooKeeper → hbase:meta表位置 → 查找目标Region位置 → 访问RegionServer// 不良设计:顺序递增,导致热点
rowkey = System.currentTimeMillis();
// 优化设计1:加盐/哈希前缀
rowkey = MD5(userId).substring(0, 4) + "_" + userId + "_" + timestamp;
// 优化设计2:时间反转
rowkey = Long.MAX_VALUE - timestamp + "_" + userId;
// 优化设计3:组合键
rowkey = regionCode + "_" + userId + "_" + reversedTimestamp;<!-- hbase-site.xml 配置示例 -->
<property>
<name>hbase.hregion.max.filesize</name>
<value>10737418240</value> <!-- Region最大10GB -->
</property>
<property>
<name>hbase.hstore.blockingStoreFiles</name>
<value>10</value> <!-- Store中最大HFile数 -->
</property>
<property>
<name>hbase.hstore.compactionThreshold</name>
<value>3</value> <!-- 触发Compaction的最小文件数 -->
</property>-- 建表时指定压缩
CREATE 'user_table',
{NAME => 'info', COMPRESSION => 'SNAPPY', BLOOMFILTER => 'ROW'},
{NAME => 'contact', COMPRESSION => 'GZ', DATA_BLOCK_ENCODING => 'FAST_DIFF'}Client → RegionServer → WAL → MemStore → Flush → HFile (HDFS)Client → RegionServer → BlockCache → MemStore → HFile → Client多个小HFile → Minor Compaction → 较大HFile → Major Compaction → 优化后HFileRegionServer故障
↓
ZooKeeper检测
↓
HMaster重新分配Region
↓
新区RegionServer重放WAL
↓
恢复MemStore状态HBase 存储依赖 HDFS:
HBase (计算层)
↓
RegionServer (内存处理、缓存、服务)
↓
HDFS (存储层)
├── 数据持久化 (HFile)
├── 高可用 (多副本)
├── 扩展性 (分布式存储)
└── WAL存储HBase在HDFS上的存储:
HBase 存储模型的核心特点:
这种存储设计使得HBase能够: