Apache Paimon PMC 正式发布具有里程碑意义的 1.0 稳定版本(版本号 1.0.1)。这次核心版本历经近5个月的精心打磨,汇集了来自全球开源社区的 70 余位开发者智慧,累计完成 520 余项代码提交,充分展现了社区驱动的技术演进力量。我们谨向所有参与贡献的开发者致以诚挚谢意!
值得关注的是,Paimon 1.0 已成功通过阿里巴巴集团和字节跳动等头部企业的严苛生产验证。在双十一全球购物节万亿级流量洪峰的实战检验中,Paimon 展现出卓越的扩展性和稳定性。这一里程碑不仅标志着流式湖仓技术正式迈入成熟发展新阶段,更实证了 Paimon 湖存储架构具备支撑超百 PB 级数据存储的工业级能力。
01 版本综述
在 Paimon 1.0 中,并没有引入大量的内核修改,稳固和优化内核设计是长期的重点,引入 Catalog 相关的一些生态、加强了快照提交、提升了 Lookup 性能、优化主键表的存储。
- 我们引入了很多激动人心的生态集成,Catalog 生态支持了 Format Tables 来兼容 Hive 表的使用,Catalog 也支持了 View,并且我们引入了 Object Table 来管理非结构化数据。
- Iceberg 兼容在 1.0 中正式进入生产可用,对接 AWS 相关生态,以及 DuckDB 读取 Iceberg 表的能力。
- 快照事务相关的能力我们进行大幅优化,以应对超大表或超宽表的提交。
- 我们核心加强了 Orphan File Clean,使得它可以被分布式的执行,它是我们日常表管控运维的一个核心部分。
- 本地 Lookup (它是 Lookup Changelog-producer、主键表 Deletion Vectors 模式、Flink Lookup Join 的基础依赖) 的算法由 Hash 改变为 Sort,大幅提升本地磁盘的压缩率。
- Count(*) SQL 加速,执行不再需要读取数据文件,直接返回,非主键表和主键 DV 表将获得此加速效果。
- 引入了主键表 Thin 模式,主键相关字段不会再被重复保存,为了兼容性,目前还没有默认开启。
- 文件索引中的 Bitmap 得到了大幅增强,这来源于索引可以被下推到 Parquet 文件的 Page 粒度,它将大幅加强查询性能。
02 生态相关
Catalog 生态
上图是目前 Paimon 1.0 的 Catalog 相关生态,在 1.0 前,只有 Paimon Primary Key Table 和 Append Table,在 1.0 中扩展了大量的生态:
- View:当 metastore (比如 Hive) 可以支持视图时,即支持视图。如果没有元存储,则只能使用临时视图,该视图仅存在于当前会话中。持久化的视图当前将保存原始 SQL。如果需要跨引擎使用 View,可以编写跨引擎 SQL 语句。
- Format Table:当 metastore (比如 Hive) 可以支持格式表时,则支持格式表。元存储中的 Hive 表将映射到 Paimon 的格式表,供计算引擎(Spark、Hive、Flink)读写。此类型主要用于兼容 Hive 表的使用。
- Object Table:对象表为指定对象存储目录中的非结构化数据对象提供元数据索引。对象表允许用户分析对象存储中的非结构化数据。
- Materialized Table:物化表旨在简化批处理和流数据管道,提供一致的开发体验,比如 Flink 物化表。现在只有Flink SQL集成到物化表。
接下来的 Paimon 版本将:
- 给 FileSystemCatalog 带来 View、Format Table 的支持
- 考虑给 View 带来方言的支持
- 将 Materialized Table 给出跨引擎的物化视图定义,让 Spark 与 StarRocks 等引擎能协同操作
- 引入跨引擎的 Function 定义
Iceberg 兼容
Paimon支持生成与 Iceberg 兼容的元数据,以便 Iceberg Readers 可以直接使用 Paimon 表。Iceberg 兼容在这个版本中变得生产可用!
通过 Iceberg 兼容,可以解锁 Iceberg 的大量生态,包括各种 Serverless 计算产品。Paimon 1.0 核心解决了:
- 复杂类型的支持。
- 验证了 Athena 以及 Glue Catalog 的集成。
- 验证了 DuckDB 读取 Iceberg 的能力。
Paimon 主键表将数据文件组织为 LSM 树,因此在查询之前必须合并数据文件,或者结合 Deletion Vectors。但是,Iceberg Reader 无法合并数据文件,因此只能查询 LSM 树最高级别上的数据文件。最高级别的数据文件是通过 Full Compaction 生成的。
值得高兴的是 Iceberg 最新的研发中也支持了 Deletion Vectors,以后 Paimon 主键表 Deletion Vectors 也可以无损的产出 Iceberg 的快照,Iceberg 发布新版本后,会进一步集成。
03 快照事务
在阿里集团淘天的业务中,最大的表的单个分区甚至超过了100TB,这给 Manifest 带来了很多挑战,所以在 Paimon 1.0 中,大幅提升了快照提交的性能,以及多作业写入时的表现。
此版本引入了 Manifest Merging 内存优化,避免在内存中保留全量 DataFileMeta,此阶段不会再有内存问题导致 OOM 的不稳定。
多作业同时提交是 Paimon 的核心能力之一,比如一个写数据的作业,一个负责 Compaction 的作业,但是在之前的版本中,如果数据量太大,文件太多,很容易导致提交失败,而且可能反复失败最终导致作业 failover,此版本大幅优化了多作业同时写入时的反复冲突问题,避免长时间冲突导致作业 failover。
此版本引入了统计信息 Dense 模式,避免无效的大量空间占用,这使得超 1000 列的超级宽表能被很好的支持,元数据存储量降低 100 倍,在配置 'metadata.stats-mode' = 'none' 的情况下。
统计信息 Dense 模式也带来了兼容性问题,但是它只影响 'metadata.stats-mode' = 'none' 的情况,如果你想保持对旧版本 Reader 的兼容性,你可以配置 'metadata.stats-dense-store' = 'false',一般不推荐,因为在非dense模式下,这么配置也不会节省多少元数据存储空间。
在删除文件时,也支持了不保存统计信息,可以配置 'manifest.delete-file-drop-stats' = 'true',它默认值是 false,因为同样会引起旧版本 Reader 的兼容性,如果你已经升级了所有 Readers,建议打开此参数,它将进一步提升 Compaction 的稳定性。
04 管控运维
Paimon 的写入作业在 failover 时可能会产生一些未提交的临时文件,这些临时文件在文件系统中浪费了存储空间,所以 Paimon 提供了 Orphan 文件清理的工具。
但是此工具在之前的版本中是单机执行的,在超级大表的清理中有比较大的性能问题,所以此版本中引入了分布式的执行,包括 Flink 和 Spark 计算引擎均支持此能力。
05 读写性能
本地 Lookup
本地 Lookup 是 Paimon 点查 LSM 结构的基础能力,它是如下能力的基础结构:
- lookup changelog-producer:点查历史文件生成 changlog。
- 主键表 deletion vectors 模式:点查历史文件生成 deletion vectors。
- Flink Lookup Join:当 Join 条件是维表的主键时,会使用本地 Lookup 的方式。
之前的版本使用 HashFile 来解决 Lookup 问题,它有两个缺点:
- 生成 HashFile 写入时,磁盘会拷贝多次。
- HashFile 的压缩率太差了,就算使用 ZSTD 也支持2-3倍。
在 Paimon 1.0 中,我们切换到了新的 Sort Based 文件:
这是一个类似 LevelDB SST 文件的格式,它有着更好的压缩率,更低的磁盘 IO 放大。我们测试了一些数据,在很多场景中,压缩率比 Hash 文件提升3-5倍。
Count(*) 优化
Paimon 在 Manifest 文件中已经保存了数据文件的统计信息,对于 Count(*) 的 SQL,本来可以返回 Manifest 里面的数据,但是之前的版本仍然去读取每个文件,消耗很大。
在 Paimon 1.0 中,我们结合 Flink 和 Spark 优化了此 SQL,比如以下 SQL:
-- 查询 Append 表,可以被加速SELECT COUNT(*) FROM APPEND_T; -- 查询 Append 表,指定分区,可以被加速SELECT COUNT(*) FROM APPEND_T WHERE dt = '20250101'; -- 查询 DV 模式的主键表,可以被加速SELECT COUNT(*) FROM PRIMARY_KEY_T_DV;
主键表 Thin 模式
之前的 Paimon 保存如下结构到主键表的数据文件中:
- Key columns
- _VALUE_KIND
- _SEQUENCE_NUMBER
- Value columns
实际上你会发现,在 Value columns 里面已经包含了所有的 Key columns,它们重复保存了相同的数据。
所以在新版本中,提供了 'data-file.thin-mode' 来使得不再保存重复的 Key columns,这可以节省不少存储,以及提供读写性能。
注意,此功能会导致引起旧版本 Reader 的兼容性,所以它默认不被启用,请保证先升级你的读取端。
文件索引
之前版本的 Bitmap 索引对点查有一些作用,但是作用并不大,此版本:
- 将 Bitmap 下推到 Parquet Reader 中,且作用到 Page 粒度,这可以显著提升 Bitmap 的过滤效果,大幅提升性能。
- 并且支持了 Bit-Slice Index Bitmap,BSI 文件索引是一种数值范围索引,用于加速范围查询。
- 此外,Deletion Vectors 模式的主键表也支持了文件级索引。
新的 Bitmap 索引也在社区讨论中,它将大幅提升索引列基数很高时的性能情况。
Catalog 优化
为了避免元数据造成的瓶颈,Catalog 也迎来了部分优化:
- HiveCatalog:大幅优化了无用的 getTable 次数,大幅加速了 listTables 的性能
- CachingCatalog:引入了分区的缓存,添加了 Snapshot 文件的缓存,添加了缓存的统计信息
Parquet 读取器
我们参考 Spark SQL 的 Parquet 读取器来完整重构了 Paimon 的 Parquet 读取器,这使得我们在读取 Parquet 文件时,提升了复杂类型的读取性能,并减少了复杂类型的 Bugs。
06 其它功能
Nested Schema 的提升,支持 Nested Projection Pushdown 以及 Nested Schema Evolution,至此,Paimon 真正意义上的支持嵌套类型,以及支持了完整的 Schema Evolution。
另外有趣的是 binlog 系统表,通过 binlog 表查询 binlog,之前的更新和之后的更新将打包在一行中,这可以让流读像 Mysql binlog 一样,你可以处理在一起的 -U 和 +U 消息。
07 Flink 集成
除了与 Flink 社区一起推进 Materialized Table,Paimon 1.0 也有很多流处理和批处理相关的提升。
流处理部分:
- CDC:Kafka Sync 支持了复杂类型;并支持了 Aliyun Json 类型
- Local 合并 (配置 'local-merge-buffer-size') 现在会使用 Hash 算法来完成了,这非常有利于部分聚合表的效率。
- Lookup Join 支持了黑名单机制,避免关键时刻 refresh 影响稳定性。
- Append 表自动 Compaction 的内存优化,超大表也可以自动 Compaction 小文件了。
- 当开启 Changelog-producer 为 Lookup,如果 Flink 的检查点间隔很短(例如,30秒),并且桶的数量很大,则每个快照可能会产生大量的小变更日志文件。为了将小的变更日志文件压缩为大的变更日志引入了配置 'changelog.precommit-compact'。
批处理部分:
- 支持了 Flink 批处理中的预测执行
- 支持了 Flink 对接 Paimon 的统计信息
- 支持了 使用 Flink SQL 来生成 Paimon 的统计信息
08 Spark 集成
Spark4 已经发布了 preview2 了,其中有比较重要的一个能力是 Variant,包括 Variant Shredding,这可以大幅提升半结构化数据的处理。Paimon 社区会在后续对接 Variant 以及 Variant Shredding 能力。
另外 Spark SQL 支持了使用动态参数来配置表,比如:
-- set scan.snapshot-id=1 for the table default.T in any catalogs SET spark.paimon.*.default.T.scan.snapshot-id=1; SELECT * FROM default.T;
09 后续规划
在后续计划中,我们重点投入 RESTCatalog 的建设,并且推动 REST Server 的发展,在未来,我们希望通过 REST 元数据服务极大的提升整个湖仓的体验、可用性和易用性。