Skip to content

HBase Compaction:数据文件的整理艺术

MemStore 不断 Flush,产生越来越多的小 HFile。

Compaction 就是把这些小文件合并成大文件的过程。


Compaction 类型

┌─────────────────────────────────────────────────────────────┐
│                    Compaction 类型                            │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Minor Compaction                                    │   │
│  │  合并少量小 HFile,不删除过期数据                    │   │
│  │  触发频率:高                                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Major Compaction                                   │   │
│  │  合并所有 HFile,删除过期数据和删除标记              │   │
│  │  触发频率:低(建议手动触发)                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Minor Compaction

触发条件

java
// Minor Compaction 触发条件
public class MinorCompaction {
    // 1. HFile 数量超过阈值
    public static final int COMPACTION_MIN = 3;  // 至少 3 个

    // 2. HFile 大小满足条件
    // Ratio = smallestHFile / sumOfOtherHFiles
    // 当 Ratio > threshold 时触发
    public static final double COMPACTION_RATIO = 1.2;
}

合并策略

Minor Compaction 合并策略:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  合并前(多个小文件):                                       │
│  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐                │
│  │ 1MB │ │ 2MB │ │ 3MB │ │ 4MB │ │ 5MB │                │
│  └─────┘ └─────┘ └─────┘ └─────┘ └─────┘                │
│                                                             │
│  合并后(一个大文件):                                       │
│  ┌─────────────────┐                                        │
│  │      15MB      │                                        │
│  └─────────────────┘                                        │
│                                                             │
│  注意:不会删除过期数据(Major 会)                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Major Compaction

触发条件

java
// Major Compaction 触发条件
public class MajorCompaction {
    // 1. 所有 HFile 合并成一个
    // 2. 删除标记被处理
    // 3. 删除已过期数据
    // 4. 触发时间间隔
    public static final long COMPACTION_ENABLED_CRON = 7 * 24 * 60 * 60 * 1000L;  // 7天
}

Major Compaction 影响

Major Compaction 影响:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  正面影响:                                                  │
│  - 减少 HFile 数量,提高读取性能                             │
│  - 删除过期数据,释放磁盘空间                                │
│  - 删除被标记删除的数据                                      │
│                                                             │
│  负面影响:                                                  │
│  - 大量磁盘 I/O,影响读写性能                               │
│  - 网络压力(如果 HFile 跨节点)                             │
│  - 可能触发 OOM(内存压力大)                                │
│                                                             │
│  建议:业务低峰期手动触发 Major Compaction                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Compaction 执行流程

java
// Compaction 执行流程
public class CompactionProcess {
    // 1. 选择待合并的 HFile
    public List<HStoreFile> selectFilesToCompact() {
        // 1.1 检查 HFile 是否过期
        // 1.2 检查 HFile 是否达到合并条件
        // 1.3 选择合适的 HFile 集合
        // 1.4 创建 Compaction 请求
    }

    // 2. 执行合并
    public void performCompaction(List<HStoreFile> files) {
        // 2.1 创建临时 Writer
        StoreFileWriter writer = createWriter();

        // 2.2 合并写入
        for (HStoreFile file : files) {
            for (KeyValue kv : file.getScanner()) {
                writer.append(kv);
            }
        }

        // 2.3 关闭 Writer
        writer.close();

        // 2.4 替换旧文件
        replaceFiles(oldFiles, newFile);
    }
}

Compaction 配置

java
// Compaction 配置
public class CompactionConfig {
    // 表级配置
    TableDescriptor table = TableDescriptorBuilder
        .newBuilder(tableName)
        .setColumnFamilies(
            ColumnFamilyDescriptorBuilder
                .of("info")
                // 合并策略
                .setCompactionEnabled(true)
                // 最大 HFile 数(超过后强制合并)
                .setMaxFilesToCompact(10)
                // 最小 HFile 数(Major Compaction 阈值)
                .setMinFilesToCompact(3)
                // TTL(数据过期时间)
                .setTimeToLive(7 * 24 * 3600)  // 7 天
                .build()
        )
        .build();
}

Compaction 优化

1. 选择合适的触发时机

bash
# 手动触发 Major Compaction
hbase shell
> major_compact 't_user'

# 只压缩特定列族
> major_compact 't_user', 'info'

2. 调整合并策略

java
// 使用 DateTieredCompaction(适合时序数据)
ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder
    .of("info")
    .setCompactionDataType(DataBlockEncoding.DATE_TIERED_COMPACTION)
    .build();

// 或者使用 FIFO Compaction(极高性能,但不支持更新删除)
ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder
    .of("log")
    .setCompactionDataType(DataBlockEncoding.FIFO)
    .build();

3. 监控 Compaction 状态

java
// 监控 RegionServer 状态
Admin admin = connection.getAdmin();
ClusterStatus status = admin.getClusterStatus();

for (ServerName server : status.getServers()) {
    ServerMetrics metrics = status.getServerLoad(server);
    CompactionState state = metrics.getCompactionState();
    System.out.println(server + ": " + state);
}

面试追问方向

  • Minor 和 Major Compaction 有什么区别?
  • Compaction 对读写性能有什么影响?

下一节,我们来了解 HBase 的 Region 分裂机制。

基于 VitePress 构建