Skip to content

HBase HFile:数据是如何存储的

HBase 的数据最终存储在 HFile 中。

理解 HFile 的结构,是理解 HBase 高性能读写的关键。


HFile 是什么?

HFile 是 HBase 的存储格式,基于 Hadoop 的 Sequence File,特点是有序、压缩、可切分

┌─────────────────────────────────────────────────────────────┐
│                         HFile v3                                │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │              Block Index (可变大小)                     │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │  Block Index Entry 1: key, offset, size     │  │  │
│  │  │  Block Index Entry 2: key, offset, size     │  │  │
│  │  │  Block Index Entry N: key, offset, size     │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │                    Meta Index Block                     │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │                    Data Blocks                          │  │
│  │  ┌───────────┐ ┌───────────┐ ┌───────────┐        │  │
│  │  │ Block 1   │ │ Block 2   │ │ Block N   │        │  │
│  │  │ 64KB      │ │ 64KB      │ │ 64KB      │        │  │
│  │  └───────────┘ └───────────┘ └───────────┘        │  │
│  │                                                         │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │  KeyValue1 | KeyValue2 | KeyValue3 | ...  │  │  │
│  │  │  按 RowKey 排序,同一行可能跨 Block           │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │                    Meta Block                            │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │              File Info (可变大小)                       │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │  TotalBytes, NumEntries, LastKey, ...       │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │                    Trailer (固定大小)                     │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │  Magic, Version, IndexOffset, ...            │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

KeyValue 结构

HFile 中存储的基本单元是 KeyValue:

┌─────────────────────────────────────────────────────────────┐
│                         KeyValue 结构                          │
│                                                             │
│  ┌───────────┬───────────┬───────────┬───────────┬─────────┐│
│  │ Key Length │ Value Length │ Timestamp │ Type    │ Key   │ Value │
│  │ (4B)       │ (4B)        │ (8B)    │ (1B)   │ ...   │ ...  │
│  └───────────┴───────────┴───────────┴───────────┴─────────┘│
│                                                             │
│  Key = RowKey Length + RowKey + CF Length + CF + CQ + Timestamp │
└─────────────────────────────────────────────────────────────┘

Key 的组成

  1. RowKey Length(4 字节)
  2. RowKey(N 字节)
  3. Column Family Length(1 字节)
  4. Column Family(N 字节)
  5. Column Qualifier(N 字节)
  6. Timestamp(8 字节)
  7. Key Type(1 字节):Put / Delete / ...

Block 结构

Data Block

数据块是 HFile 存储数据的基本单元:

java
// HFile Block 配置
public class HFileConfig {
    // 块大小(默认 64KB)
    // 增大块:适合顺序读
    // 减小块:适合随机读
    public static final int BLOCK_SIZE = 64 * 1024;  // 64KB
}

Block Index

Block Index 存储每个 Block 的起始 Key 和位置:

Block Index 查找过程:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  1. 加载 Block Index 到内存                                  │
│  2. 二分查找:定位目标 Key 所在的 Block Index Entry          │
│  3. 读取对应 Block 的数据                                    │
│                                                             │
│  查找复杂度:O(log N) + O(1)                                 │
│  N = Block 数量                                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Bloom Filter

Bloom Filter 用于快速判断某个 Key 是否存在:

┌─────────────────────────────────────────────────────────────┐
│                    Bloom Filter 工作原理                      │
│                                                             │
│  Key1 ──┐                                                    │
│  Key2 ──┼──→ Hash Functions ──→ Bit Array ──→ 存在?      │
│  Key3 ──┘     (多个哈希)          (位数组)                   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  0 1 1 0 1 0 0 1 0 1 1 0 0 1 0 0 ...          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  特点:                                                     │
│  - 存在不一定准确(可能有假阳性)                            │
│  - 不存在一定准确(没有假阴性)                              │
│  - 空间效率高(每个 Key 只占几位)                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

在 HFile 中的应用

java
// 创建带 Bloom Filter 的 Column Family
ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder
    .of("info")
    .setBloomFilterType(BloomType.ROW)  // ROW: 按 RowKey 过滤
    // ROWCOL: 按 RowKey + Column 过滤
    .build();

压缩

HFile 支持多种压缩算法:

压缩算法压缩率CPU 开销适用场景
NONE
SNAPPY平衡之选
LZO通用
GZ冷数据
ZSTD推荐使用
java
// 配置压缩
ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder
    .of("info")
    .setCompressionType(Compression.Algorithm.SNAPPY)
    .build();

读取流程

HFile 读取流程:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  1. 加载 Trailer,获取 Index Block 位置                       │
│                                                             │
│  2. 加载 Index Block,建立 Block Index                       │
│                                                             │
│  3. 二分查找 Index Block,定位目标 Key 在哪个 Data Block     │
│                                                             │
│  4. 读取目标 Data Block                                      │
│                                                             │
│  5. 在 Data Block 内顺序查找目标 Key                         │
│                                                             │
│  6. 如果开启 Bloom Filter,步骤 3 可以跳过不存在的 Key        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

面试追问方向

  • HFile 的数据是按什么顺序存储的?
  • Bloom Filter 有什么优缺点?

下一节,我们来了解 HBase 的写入流程。

基于 VitePress 构建