流式数据湖Paimon探秘之旅 (十五) 文件清理与维护

95 阅读3分钟

第15章:文件清理与维护

导言:垃圾回收的重要性

随着时间推移,Paimon表会积累大量的旧Snapshot、临时文件、孤儿文件。这些无用数据占用磁盘空间并影响元数据查询性能。本章讲解如何安全高效地清理


第一部分:Snapshot过期清理

1.1 Snapshot的生命周期

Snapshot 1 (时间: 1:00)
Snapshot 2 (时间: 1:10)
Snapshot 3 (时间: 1:20)
...
Snapshot 100 (时间: 1:59)

配置:snapshot-num-retain-min = 10

清理策略:
├─ 保留最新10个Snapshot
├─ 删除Snapshot 1-90
└─ 自动进行,无需手动干预

配置:
'snapshot-num-retain-min' = '10'    # 最少保留10个
'snapshot-num-retain-max' = '20'    # 最多保留20个
'snapshot-time-retain' = '7d'       # 保留7天内的Snapshot

1.2 Snapshot清理的实现

public class ExpireSnapshots {
    
    public void expire() {
        List<Long> allSnapshots = snapshotManager.listSnapshotIds();
        
        // 计算要删除的Snapshot ID
        long earliestToKeep = allSnapshots.size() - minRetain;
        
        for (long id : allSnapshots) {
            if (id < earliestToKeep) {
                // 删除Snapshot及其数据文件
                snapshotManager.deleteSnapshot(id);
            }
        }
    }
}

第二部分:孤儿文件清理

2.1 什么是孤儿文件

场景1:Compaction异常
├─ 新文件生成
├─ 旧文件应该被删除
└─ 但由于异常,旧文件仍存在
   → 孤儿文件(无Snapshot引用)

场景2:提交失败
├─ 临时文件生成
├─ 提交失败,应该清理
└─ 清理失败,临时文件遗留
   → 孤儿文件

识别方法:
├─ 扫描所有Snapshot
├─ 收集被引用的文件
└─ 磁盘上存在但未被引用 → 孤儿文件

2.2 孤儿文件清理

-- 运行清理任务
CALL clean_orphan_files('table_name');

-- 如果支持参数
CALL clean_orphan_files(
    table_name => 'orders',
    dry_run => true  -- 只报告,不删除
);

预期结果:
清理前:磁盘占用 500GB
清理后:磁盘占用 480GB
释放空间:20GB(孤儿文件)

第三部分:Manifest清理

3.1 Manifest过期

大量Snapshot提交后,会有很多旧Manifest文件:
manifest-v1-0
manifest-v2-0
manifest-v3-0
...
manifest-v100-0

配置自动清理:
'manifest-target-size' = '8MB'
'manifest-merge-min-count' = '30'

系统会:
├─ 定期合并小Manifest
├─ 删除被合并的旧版本
└─ 保持Manifest精简

第四部分:生产级维护计划

4.1 日常维护

# 每天执行(凌晨2点)
cron: 0 2 * * *

维护任务:
1. Snapshot过期清理
   ├─ 保留最近7天的Snapshot
   └─ 自动执行

2. Manifest合并
   ├─ 合并积累的小Manifest
   └─ 优化元数据查询性能

3. 统计信息更新
   ├─ 重新计算文件统计
   └─ 用于查询优化

4.2 周期性维护

# 每周执行(周日午夜)
cron: 0 0 * * 0

1. 全量Compaction(可选)
   ├─ 强制压缩所有Level
   └─ 优化文件组织

2. Tag清理
   ├─ 删除超过30天的自动Tag
   └─ 保留重要的手动Tag

3. 完整性检查
   ├─ 验证文件一致性
   └─ 报告异常

第五部分:最佳实践

5.1 安全删除数据

错误做法:
DELETE FROM table WHERE dt < '2024-01-01';
   → 生成DELETE标记,需要Compaction清理
   → 不是真正的磁盘释放

正确做法:
-- 方法1:使用分区过期
ALTER TABLE table SET (
    'partition.expiration.time' = '90d'
);
   → 自动删除90天前的分区
   → 磁盘立即释放

-- 方法2:手动删除分区
ALTER TABLE table DROP PARTITION dt='2023-12-01';
   → 立即删除该分区所有文件
   → 磁盘立即释放

5.2 监控磁盘使用

-- 查询磁盘占用
SELECT 
    SUM(file_size) / 1024 / 1024 / 1024 as size_gb
FROM paimon_files;

-- 分区级别的磁盘占用
SELECT 
    partition,
    SUM(file_size) / 1024 / 1024 as size_mb
FROM paimon_files
GROUP BY partition
ORDER BY size_mb DESC
LIMIT 20;

总结

清理的优先级

P0(立即清理):
└─ 孤儿文件(占用空间但无用)

P1(日常清理):
├─ 过期Snapshot(保留配置时间后删除)
└─ 旧Manifest(合并后删除)

P2(周期清理):
└─ 备份清理(保留的Tag和Branch)

下一章:第16章讲解Flink集成深度解析