1、在官网下载
https://dlcdn.apache.org/paimon/paimon-1.2.0/apache-paimon-1.2.0-src.tgz
2、参考:尘锋信息基于 Apache Paimon 的流批一体湖仓实践-阿里云开发者社区

参考:使用 Doris 和 Paimon - Apache Doris
doris/samples/datalake/iceberg_and_paimon at master · apache/doris · GitHub
下载 Doris master代码

进入

/home/dockerinstall/doris/doris-master/samples/datalake/iceberg_and_paimon
目录下
执行
bash ./start_all.sh

报错了。
--------------------------
换个方式
下载Flink 2.0
wget https://dlcdn.apache.org/flink/flink-2.0.0/flink-2.0.0-bin-scala_2.12.tgz
下载hadoop-3.3.6
wget https://mirrors.aliyun.com/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz .
下载 paimon

下载 starRocks
Download StarRocks Free | StarRocks
最新版本为 4.0版本

---------------------------------------------------------------------------------------
Flink基于Paimon的实时湖仓解决方案的演进-阿里云开发者社区
参考:

一个典型的流式湖仓架构,首先业务数据会存储在 MySQL 表中,然后借助 Flink 及其 CDC Connector 的作业,将这些数据库的数据同步到 Paimon 的 ODS 层中,从而构成 ODS 层数据。
包含了 MySQL 的全量数据,并且会根据 MySQL 的更新实时地进行相应的更新。
在有了 ODS 层数据之后通常会进行数据过滤,并进行数据的 Join 操作,以生成一个宽表,这就是 DWD 层的数据。
DWD 层数据形成后会进一步进行数据过滤、数据的聚合和打宽表等操作,以生成 DWS 层的数据,用于进行指标的统计。
ODS层(操作数据存储层):
- 使用Flink及其CDC Connector将MySQL中的数据实时同步到Paimon的ODS层。
- ODS层包含MySQL的全量数据,并根据MySQL的更新实时进行相应的更新。
DWD层(数据仓库明细层):
- 在ODS层数据的基础上,进行数据过滤和Join操作,生成宽表,形成DWD层数据。
DWS层(数据仓库服务层):
- 在DWD层数据的基础上,进一步进行数据过滤、聚合和打宽表等操作,生成DWS层数据,用于指标统计。
1.2 关键组件及特性
- Apache Flink:
- 是一个流批一体的计算引擎,支持实时和离线作业。
- 通过Flink CDC Connector实现高效的数据同步。
- Paimon:
- 是一个流批一体的存储系统,支持实时和离线数据处理。
- 每一层数据都配备了CDC日志,能够直接接收数据变更,无需重写整个分区。
- Paimon最初是从Flink项目中孵化出来的,因此与Flink社区的合作非常紧密,结合完善。
1.3 主要优势
- 分钟级数据更新:每一层数据都能实现分钟级别的更新,确保数据的新鲜度。
- 简化系统复杂度:流批一体的设计减少了系统的复杂性,降低了维护成本。
- 实时与离线支持:既能支持实时作业,也能满足离线场景的需求,提升了灵活性。
- 高效的变更数据捕获:Paimon的CDC日志功能确保了数据变更的高效处理,避免了传统数仓架构中的全分区重写问题。

二、技术演进

ODS层的数据从数据库流入Paimon的过程分为两个阶段:全量阶段和增量阶段。
全量阶段:
- 当Flink CDC作业启动时,会全局扫描整个表,生成
insert类型的数据。 - 在这个阶段,Paimon记录的Change Log数据与Data数据是完全一致的。
增量阶段:
- 完成全表扫描后,Flink CDC作业进入增量阶段,只读取binlog数据,并生成相应的change log(包括
insert、update、delete等类型的数据)。 - Paimon在写入数据时,会记录两部分数据:
- Change Log数据:包含所有变更记录,保持原始性。
- Data数据:对Change Log数据进行合并后的结果。例如,如果某个字段的值发生了更新,Data表只会记录该字段的最终值。
- 区分全量阶段和增量阶段:
- 在Flink 1.19版本之后,引入了“流批融合”特性,允许CDC Source通过事件的方式通知下游算子(包括Paimon Sink)当前消费的数据属于全量阶段还是增量阶段。
- 基于这一事件,Paimon可以在全量阶段省去合并操作,直接将Change Log数据当作Data数据来使用。
- 性能提升:
- 经过Benchmark测试,结果显示在全量阶段下,Paimon Sink的性能提升了大约20%。
2.2 宽表构建
- 传统方法:
- 过去,可能会使用Flink的双流Join来实现宽表构建。然而,双流Join是一个资源消耗大且对State要求高的操作,因为它需要将两边流的数据都存储在State中。
- 优化建议:
- 通过上述优化方案,可以在全量阶段直接使用Change Log数据,避免复杂的双流Join操作,从而减少资源消耗和State管理的复杂性。
通过Flink 1.19版本引入的“流批融合”特性,可以有效区分全量阶段和增量阶段的数据处理方式。在全量阶段,Paimon可以直接使用Change Log数据,省去合并操作,从而显著提升性能。这种优化不仅提高了数据同步的效率,还简化了宽表构建的过程,减少了资源消耗和State管理的复杂性。

Flink 提供了一个非常有效的机制来实现宽表构建,即 Partial Update 。(Failover)
如图所示它可以使用两个 Flink 分别对一个表中的不同字段进行更新。例如左边的表只需要对 Column A 进行更新,并将 Column B 设置为 null ,而另一个 Sink 则可以对 Column B 进行更新。这样当下游读取这个表时,它会自动将这两个部分合并起来,将 null 值替换为对应的实际值。

在实际使用过程中经常会遇到一个问题:当一个作业包含多个Source ,并将数据写入同一个 Paimon 表时,如果多个 Flink 尝试同时对该表进行 Compaction 操作,Paimon 通常不支持这种行为。这会导致作业在执行 Compaction 时失败,进而引发作业持续 Failover ,最终导致作业不可用。为了解决这个问题,用户可以通过配置来关闭作业的自动 Compaction 功能。然而,这样做意味着需要启动另一个专门的作业来对该表执行 Compaction 操作。在很多情况下,用户可能只希望通过一个作业的多个 Flink 来完成必要的 Passbook 操作,而不希望额外启动一个专门的作业来进行 Compaction 。但遗憾的是当前可能无法直接让该作业自行处理 Compaction 。
为了实现这一目标需要在 Flink 的 Single Planner 中进行一些改造。改造完成后, Flink Single Planner 将能够自动识别是否多个 Flink 组件正在向同一张表写入数据。在满足特定条件时将多个 Flink 的上游结果进行 Union 操作,并仅使用一个 Flink 组件来统一写入所有数据。这样在进行 Compaction 操作时,就只有一个判断逻辑,从而避免了之前提到的冲突问题。

无主键表存在一个问题:它的所有数据都是根据写入时的顺序进行排序的,而在一个数据文件内部,所有列的数据是乱序的。这就导致了如果下游需要进行查询,就必须扫描整个表的所有数据文件,才能找到所需的数据。同时由于列数据的乱序,也会影响到列式存储格式的压缩率。为了解决这个问题在 Flink Single Planner 以及 Paimon 中进行了一些改动。
引入了一个名为“Range Partition and Sort”的优化方案。从名称上可以看出,这个方案包含两个主要步骤:首先是 Range Partition ,其次是 Sort 。首先来看一下 Range Partition 。

Range Partition 的目标是将用户指定列中值相近的数据放在一起。为了实现这一点会引入两个算子: Local Sample 和 Global Sample 。这两个算子的本质是对批处理作业的输入数据进行采样。
接下来分析列值的取值范围。一旦确定了这个范围,下游会有一个名为“Assign Range Index”的算子。
在数据写出之前会将这个 index 删除。这样就相当于为无模式表的数据划分了一系列 range ,每个range 内的数据值都比较接近。
接下来会进入 Sort 阶段,每个算子会对自己负责的 range 内的数据进行排序,并最终将数据写入到各自的数据文件中。这样就对用户指定的列完成了一次全局排序。经过这样的排序后可以加速下游的查询性能,同时提高列式存储文件的压缩率,从而节省存储空间的使用效率。

在湖仓场景中,有很多用户会将 Paimon 表作为维表,与实时进来的事实表进行 Join 操作。在这种场景下,为了避免每条事实表数据进来时都需要进行一次远程数据访问, Paimon 表在作业启动阶段会将其全量数据加载到每个并发算子上。这样在维表数据量较小的情况下,性能表现是非常出色的。

随着维表数据量的逐渐增大,问题便逐渐显现。由于需要全量加载内存表,并将其存储在本地或内存中,且每个并发实例都需要进行全量加载,因此整个作业的内存占用会以极快的速度增长。此外由于作业在启动阶段就需要进行这个加载操作,并且在整个作业运行过程中还需要定期刷新,即重新加载维表,因此作业的启动开销会变得非常高。同时由于每个算子中的数据量增多, lookup 性能也会相应下降

由于 Paimon 通常是 bucket 存储的,在主键表的情况下,分桶是一种常见的做法。然而为什么事实表不能根据Paimon表的分桶分配方式进行 shuffle 呢?原因是目前还没有办法让 Paimon 表指定事实表的 shuffle 方式。因此在 Flink Single Planner 中引入了一个名为“Support Lookup Custom Shuffle”的接口。这个接口的本质是允许 connector 为维表实现指定事实表的数据 shuffle 方式。有了这个接口后 Paimon 表的维表就能够执行一些特定的操作了。

首先关于 Paimon 的维表, Paimon 的主键表中包含两种分Bucket 的方式。最简单的一种是 Fixed Bucket 。 Fixed Bucket 指的是在作业定义时,而非在 Paimon 表定义时,就已经确定了 Bucket 的数量。对于任意一条数据,其对应的 Bucket 可以通过一个简单公式计算得出。本质上这个计算过程是对 Bucket Key 取哈希值,然后再对 Bucket 的总数取模,从而确定数据具体属于哪个 Bucket 。实际上只需要让事实表也按照同样的方式进行 shuffle 。例如在事实表中可以将 K 1 和 K 2 分配到 Lookup 算子上。这个 Lookup 算子知道,它只需要读取 Bucket 1 的数据,并且只需将 Bucket 1 的数据存储在本地即可。通过这种方式,可以大大降低每个 Lookup 算子的并发量,减少其需要读取的 Paimon 数据量。同时也能降低其实际要存储到本地以及内存中的数据量。

Dynamic Bucket 。在这种情况下 Paimon 表对于数据的 Bucket 分配是动态的。也就是说随着 Key 的增多,它可能会增加一些 Bucket 。此时对于一条数据来说,无法像之前那样通过一条简单的公式来计算出它属于哪个 Bucket 。在这种情况下可能也无法像之前那样进行整体的优化。
即可以通 Custom Shuffle 接口来指定其 Sort of 的方式。这里的分配方式是指根据 Join Key 取一个哈希值,然后在取模时根据下游 Subtask 的数量,即 Lookup Join 的 Subtask 数量来进行。这时每个 Lookup 算子,或者说每个 Lookup 的并发实例,在读取维表时就会知道它可能会接收到哪些与事实表相关的数据。因此它就可以对其存储的缓存进行一些裁剪。
比如说,虽然事实表仍然是按照如 K 1 、 K 3 这样的 Key 发送给上游的并发实例,但这些并发实例在读取数据时还是需要全量读取。但是当数据存储到本地时可以进行过滤,只存储与 K 1 和 K 3 相关的数据。因为他知道事实表的分配算法策略是他指定的,所以他可以只存储与 K 1 、 K 3 相关的维表数据。尽管在读取时仍然需要访问全量的数据,但实际上他只需要在本地保存一部分维表数据。

在实时表中有时会产生一些 Hot Key 。就像在这个图示中可以明显看到 K 1 的数据量明显多于 K 2 和 K 3 。如果此时将 K 1 的数据分配到第一个并发实例上,那么这个并发实例很可能会成为整个作业的性能瓶颈。
Skew Join 的优化策略。这个优化策略的本质是,如果作业对 Per Key 的顺序没有特定要求,那么就可以启用它。在这种情况下 Paimon 通过 Lookup 自定义分配,会将同一个 Key 的数据随机分发到 N 个并发实例上,其中 N 是用户可以自行指定的。
设定 N 等于 2 ,事实表中的 K 1 可能会被分发到第一个和第二个并发实例上,从而尽可能地将一个 Hot Key 打散。由于需要进行一个类似于复制的操作,因此第一个和第二个 Lookup 并发算子都需要额外读取一个 Bucket 。这实际上是一个 Trade-off 。如果将 N 设置得很大,那么数据被打散得会更加平均,但每个算子需要读取的数据量也会相应增加。以上就是关于数据读写以及查询优化方面的一些讲解。
Flink 2.0 中的一个重要功能,即 Materialized Table 的功能。这个功能的主要目的是希望用户能够只关注自己的业务逻辑,而让 Flink 自动根据用户要求的数据新鲜度来决定是启动流作业还是批作业,以确保 Paimon 表中的数据符合数据新鲜度的要求。

只需要在第一步定义一个 Materialized Table ,然后在第二步指定要求的数据新鲜度为三分钟。此时系统应该会启动一个流作业来定期更新 Paimon 表的数据。

在湖仓管理方面, Paimon 其实提供了丰富的 Action 和Procedure



Action 的流程通常是怎样的呢?以创建一个表的操作为例。在 0.9版本之前,当 Paimon 还没有实现对应的 Procedure 来创建空表时,用户首先需要从 Paimon 官网上下载一个 Action 的 JAR 包。然后,用户需要将这个 JAR 包上传到 Flink 的运行环境上。接下来,用户需要通过执行 Flink Run 命令来启动创建空表的作业。同时,作业的参数也需要通过命令行参数来传入。

在 0.9 之后所有的 Action 都实现了对应的 Procedure 。此后用户就可以直接在 Flink SQL 中像调用函数一样调用这些 Procedure ,加上 Named Argument 的优化,用户在传递参数时也变得更加直观和方便。这些优化是在 Flink 2.0 和 Paimon 1.0 中完成的。
---------------------------------------------------------------------------------------------------
参考:零售数据湖的进化之路:滔搏从Lambda架构到阿里云Flink+Paimon统一架构的实战实践-阿里云开发者社区


大规模数据入湖性能对比
- 5亿条数据入湖 MOR (Merge-On-Read) 模式
在大规模数据入湖的 MOR 模式测试中,Paimon 表现出了显著的性能优势。以 Paimon 作为基准性能参照,Hudi MOR 模式的表现明显落后,整体性能比 Paimon 慢了4.2倍。性能差异的根本原因在于两种技术的设计理念不同。Hudi MOR 的 Compaction 完全异步运行,导致太多数据没有得到及时合并,使得读取性能极差。相比之下,Paimon 在设计上默认会在写入和读取性能之间取得平衡,当 Compaction 过程太慢时会等待其完成,从而保证了整体性能的稳定性。
- 1亿条数据入湖 COW (Copy-On-Write) 模式
在 COW 模式的性能测试中,Paimon 的优势更加明显。同样以 Paimon 作为基准性能,Hudi COW 模式性能明显落后,整体表现比 Paimon 慢了14倍,这个差距体现了两种技术在 COW 模式实现上的根本性差异。
多维度性能优势
除了基础的写入性能,Paimon 在多个维度都表现出显著优势。在宽表合并能力方面,相比传统方案有4倍性能提升。在生态兼容性上,其强大的生态支持能力比传统方案强2倍。最为突出的是在变更日志流读方面,CDC 入湖性能提升达到了惊人的12倍。
-------------------------------------------------------------------------------------
参考:数据湖技术选型指南:Iceberg vs Delta Lake vs Paimon-阿里云开发者社区
在现代数据湖格式中,元数据 是保证数据一致性与可管理性的核心。
数据写入时,原始数据会被转换为实际的数据文件,然后通过一次快照提交原子化完成写入。
每次成功提交都会生成一个全新且一致的快照,查询引擎只需访问指定快照即可获得一致的数据视图,从而实现读写分离、版本回溯和并发写入下的一致性保障。
数据湖格式的核心思想是将表的状态信息(实际文件组成、Schema、分区等)集中管理。
- 元数据(Metadata):记录了每一个 快照 的状态,包括写入了哪些文件,文件存储的位置等信息。它可以存储在文件系统(如 JSON、Avro)或托管服务(如 Hive Metastore)中。
- 数据文件(Data Files):真正存储用户数据的 物理文件,通常是 Parquet、ORC 等列式格式,写入后不可变。

数据写入
下面通过一个简单的例子来理解数据湖的核心原理,假设我们有一张用户表(users),要执行以下操作:
- 初始写入 2 条用户记录。
- 再插入 1 条新用户记录。
- 更新 1 条用户记录。
步骤一:写入 2 条用户记录

- 引擎将这两条记录写入到一个新的 Parquet 文件中,例如 file_A.parquet。
- 引擎创建一个元数据文件,记录下当前表的第一个快照(snapshot_1)包含了 file_A 这个文件。
- 最后引擎通过一次原子操作,将一个指针指向这个最新的 元数据文件。
任何查询 users 表的查询请求,都会先找到 pointer.txt,读取 snapshot_1,然后直接去访问 file_A。
步骤二:插入 1 条新记录

- 引擎将这条新记录写入一个新的 Parquet 文件 file_B.parquet。
- 引擎创建一个新元数据文件 snapshot_2.json,这个文件会记录当前最新状态(snapshot_2)由 file_A 和 file_B 两个文件组成。
- 通过原子操作,将 pointer.txt 指向 snapshot_2。
老的快照 snapshot_1 依然存在,这为查询历史版本的数据提供了可能。
步骤三:更新数据与合并

- 由于 Parquet 文件不可变,引擎需要读取 file_A 的内容,在内存中进行修改,然后将修改后的结果(连同未修改的数据)写入到一个新的 Parquet 文件 file_C.parquet。
- 同时,为了优化小文件问题,系统可能会触发一个合并(Compaction)任务,将 file_B 和 file_C 合并成一个更大的文件 file_D.parquet。
- 引擎创建 snapshot_3.json,记录当前最新状态只由 file_D 组成。
- 最后,原子地更新 pointer.txt 指向 snapshot_3。
在这个过程中,不再被最新快照引用的文件(如 file_A,file_B)会成为“孤立文件”,并由后台垃圾回收机制清理。这种设计将复杂的数据操作,转化为了对元数据文件的原子操作,从而保障了事务的 ACID 特性。
数据查询
查询时,引擎会经历以下步骤:

- 先读取 pointer.txt,解析到当前最新快照或用户指定的历史快照。
- 从快照拿到要扫描的数据文件列表与其统计信息(分区、行数、列 min/max、行组统计、bloom 过滤器等)。
- 基于谓词做 分区裁剪 与 列统计裁剪,只保留可能命中的文件或行,并做 列裁剪与谓词下推 到 Parquet/ORC。
- 合并读取文件
- CoW:直接读取被选中的最新文件。
- MoR:读取 文件 + 增量/删除向量文件,在读取阶段完成 合并与应用删除。
综上,数据湖的本质是将复杂的数据操作转化为对元数据的原子操作,从而实现 ACID 事务与高效查询。
Paimon
元数据
Paimon 借鉴了数据库的 LSM-Tree 思想,其分层式的架构特别擅长处理源源不断流入的实时数据。
Paimon 借鉴了数据库的 LSM-Tree 思想,其分层式的架构特别擅长处理源源不断流入的实时数据。
- 临时写入区(L0):新来的数据会立刻被写入 L0 层的小文件中,保证写入延迟极低。此时,同一主键的数据可能会有多个版本共存。
- 后台自动合并(Compaction):后台线程会自动将 L0 的小文件合并到 L1、L2 等更大的、更有序的文件层中。在合并过程中,相同主键的数据会自动去重,只保留最新版本。
- 状态快照 (Snapshot):同样用快照来记录在任一时刻,表由哪些层级(L0, L1, ...)的文件构成。

更新数据
- 将包含更新后数据的 新版本,写入另一个 L0 文件。
- 后台的 Compaction 任务 会在稍后自动将这两个 L0 文件合并,在合并过程中根据主键保留最新版本的数据,生成一个更大的 L1 文件。
查询数据
- 引擎需要同时读取所有层级的文件,并在内存中进行归并去重,以确保返回给用户的是最新数据。

三者的差异核心在于 元数据组织方式 与 更新模型:
- Iceberg:适合 批量处理 + 多引擎分析,强调灵活 Schema/分区演进与查询性能。
- Delta Lake:适合 强依赖 Spark 生态 的场景,特别是需要 可审计的事务日志。
- Paimon:在 高频实时 CDC 与 流批一体 场景下表现突出。
--------------------------------------------------------------------------------------
参考:尘锋信息基于 Apache Paimon 的流批一体湖仓实践-阿里云开发者社区
Paimon
- 基于LSM ,具有很高的更新能力,默认的 Changelog 模型可以处理 CDC 采集的变更数据(实测入湖端到端延迟能控制在 1分钟左右)。另外Paimon 支持 Append Only 模型,可以覆盖没有更新的日志场景,该模型在写入和读取时不用耗费资源处理更新,可以带来更高的读写性能和更低的资源消耗。
- 支持 批写 、批读 ,并且支持 (Flink、Spark、Hive 等多种批处理引擎)
- 支持 流写、流读
- Paimon 支持将一张表同时写入 Log System(如 kafka) 和 Lake Store (如 OSS 对象存储),结合 Log System 可以覆盖秒级延迟的业务场景,并且解决了 Kafka 不可查询分析的问题
- 支持 OSS 、S3、COS 等文件系统 ,且支持 FileSystem catalog ,可以完全与 Hadoop 、Hive 解耦
--------------------------------------------------------------
参考:湖仓-Apache Paimon:实时数据湖的存储底座特性解读.pdf-原创力文档








-------------------------------------------------------
参考:[湖仓架构] Apache Paimon核心原理 - 千千寰宇 - 博客园
Flink 社区希望能够将 Flink 的 Streaming 实时计算能力和 Lakehouse 新架构优势进一步结合,推出新一代的 Streaming Lakehouse 技术,促进数据在数据湖上真正实时流动起来,并为用户提供实时离线一体化的开发体验。为此,Flink 社区内部孵化了 Flink Table Store (简称 FTS )子项目,一个真正面向 Streaming 以及 Realtime 的数据湖存储项目。
读/写:Paimon 支持多种读/写数据和执行 OLAP 查询的方式
-
(1)对于读取,它支持以下方式消费数据
从历史快照(批处理模式)、从最新的偏移量(在流模式下),或以混合方式读取增量快照。 -
(2)对于写入,它支持来自数据库变更日志(CDC)的流式同步或来自离线数据的批量插入/覆盖。
内部
- 在底层,Paimon 将列式文件存储在文件系统/对象存储上,并使用 LSM 树结构来支持大量数据更新和高性能查询。
- Paimon 提供表抽象。它的使用方式与传统数据库没有什么区别:
- 在批处理执行模式下,它就像一个Hive表,支持Batch SQL的各种操作。查询它以查看最新的快照。
- 在流执行模式下,它的作用就像一个消息队列。查询它的行为就像从历史数据永不过期的消息队列中查询流更改日志。
3 基本概念
Snapshot
快照捕获表在某个时间点的状态。用户可以通过最新的快照来访问表的最新数据。通过时间旅行,用户还可以通过较早的快照访问表的先前状态。
Partition
-
Paimon 采用与 Apache Hive 相同的分区概念来分离数据。
-
分区是一种可选方法,可根据日期、城市和部门等特定列的值将表划分为相关部分。每个表可以有一个或多个分区键来标识特定分区。
-
通过分区,用户可以高效地操作表中的一片记录。
-
如果定义了主键,则分区键必须是主键的子集。
Bucket
-
未分区表或分区表中的分区被细分为存储桶,以便为可用于更有效查询的数据提供额外的结构。
-
桶的范围由记录中的一列或多列的哈希值确定。用户可以通过提供bucket-key选项来指定分桶列。如果未指定bucket-key选项,则主键(如果已定义)或完整记录将用作存储桶键。
-
桶是读写的最小存储单元,因此桶的数量限制了最大处理并行度。不过这个数字不应该太大,因为它会导致大量小文件和低读取性能。一般来说,建议每个桶的数据大小为1GB左右。
Consistency Guarantees一致性保证
-
Paimon writer使用两阶段提交协议以原子方式将一批记录提交到表中。每次提交在提交时最多生成两个快照。
-
对于任意两个同时修改表的writer,只要他们不修改同一个存储桶,他们的提交都是可序列化的。如果他们修改同一个存储桶,则仅保证快照隔离。也就是说,最终表状态可能是两次提交的混合,但不会丢失任何更改。
4 文件布局

面简单介绍文件布局。
Snapshot Files
- 所有快照文件都存储在快照目录中。
- 快照文件是一个 JSON 文件,包含有关此快照的信息,包括:
- 正在使用的Schema文件
- 包含此快照的所有更改的清单列表(manifest list)
Manifest Files
- 所有清单列表(manifest list)和清单文件(manifest file)都存储在清单(manifest)目录中。
- 清单列表(manifest list)是清单文件名(manifest file)的列表。
- 清单文件(manifest file)是包含有关 LSM 数据文件和更改日志文件的文件信息。例如对应快照中创建了哪个LSM数据文件、删除了哪个文件。
Data Files
- 数据文件按分区和存储桶分组。每个存储桶目录都包含一个 LSM 树及其变更日志文件。
- 目前,Paimon 支持使用 orc(默认)、parquet 和 avro 作为数据文件格式。
LSM Trees
- Paimon 采用 LSM 树(日志结构合并树)作为文件存储的数据结构。
-
LSM 树将文件组织成多个Sorted Run。Sorted Run由一个或多个数据文件组成,并且每个数据文件恰好属于一个Sorted Run。
-
数据文件中的记录按其主键排序。在Sorted Run中,数据文件的主键范围永远不会重叠。

-
正如您所看到的,不同的Sorted Run可能具有重叠的主键范围,甚至可能包含相同的主键。查询LSM树时,必须合并所有Sorted Run,并且必须根据用户指定的合并引擎和每条记录的时间戳来合并具有相同主键的所有记录。
-
写入LSM树的新记录:将首先缓存在内存中。当内存缓冲区满时,内存中的所有记录将被排序并刷新到磁盘。
Compaction
-
当越来越多的记录写入LSM树时,Sorted Run的数量将会增加。由于查询LSM树需要将所有Sorted Run合并起来,太多Sorted Run将导致查询性能较差,甚至内存不足。
-
为了限制Sorted Run的数量,我们必须偶尔将多个Sorted Run合并为一个大的Sorted Run。这个过程称为Compaction。
-
然而,Compaction是一个资源密集型过程,会消耗一定的CPU时间和磁盘IO,因此过于频繁的Compaction可能会导致写入速度变慢。这是查询和写入性能之间的权衡。Paimon 目前采用了类似于 Rocksdb 通用压缩的Compaction策略。
-
默认情况下,当Paimon将记录追加到LSM树时,它也会根据需要执行Compaction。用户还可以选择在“专用Compaction作业”中独立执行所有Compaction。
多Writer并发写入
-
Paimon的快照管理支持向多个writer写入。
-
默认情况下,Paimon支持对不同分区的并发写入。推荐方式是
streaming job将记录写入Paimon的最新分区;同时批处理作业(覆盖)将记录写入历史分区。
- Compaction会将某些数据文件标记为“已删除”(并未真正删除)。如果多个writer标记同一个文件,则在提交更改时会发生冲突。Paimon 会自动解决冲突,但这可能会导致作业重新启动。
- 为了避免这些缺点,用户还可以选择在writer中跳过Compaction,并仅运行专门的作业来进行Compaction。由于Compaction仅由专用作业执行,因此writer可以连续写入记录而无需暂停,并且不会发生冲突。

Flink SQL目前不支持compaction相关的语句,所以我们必须通过flink run来提交compaction作业。
- 如果提交一个批处理作业(execution.runtime-mode:batch),当前所有的表文件都会被Compaction。如果您提交一个流作业(execution.runtime-mode: Streaming),该作业将持续监视表的新更改并根据需要执行Compaction。
表管理
管理快照
1)快照过期
-
Paimon Writer每次提交都会生成一个或两个快照。每个快照可能会添加一些新的数据文件或将一些旧的数据文件标记为已删除。然而,标记的数据文件并没有真正被删除,因为Paimon还支持时间旅行到更早的快照。它们仅在快照过期时被删除。
-
目前,Paimon Writer在提交新更改时会自动执行过期操作。通过使旧快照过期,可以删除不再使用的旧数据文件和元数据文件,以释放磁盘空间。
-
设置以下表属性:

自如基于 Apache StreamPark™ + Paimon 实现数据一键入湖最佳实践 | Apache StreamPark

3.3 Paimon 实现一键入 Hive
在 Apache Paimon 0.5 版本后,提供了 CDC 数据集成能力,通过官方提供的 paimon-action jar 可以很方便的将 MySQL、Kafka、Mongo 等中的数据实时摄入到 Paimon 中,我们正在使用的是 paimon-flink-action ,采用了 mysql-sync-database(整库同步),并通过“—including_tables” 参数选择要同步的表。这种同步模式有效地节省了大量资源开销,相比每个表启动一个 Flink 任务而言,避免了资源的大量浪费。
引入 Paimon 后缩短了整个数据接入链路,消除了对 Canal、Kafka、Airflow 的依赖,使得 MySQL 直接以分钟级速度与 Hive 对接,整体环境清爽高效。此外,Paimon 完全兼容 Hive 端数据读取,转换成本极低,对原始架构脚本的使用也具备良好的兼容性,Paimon 还支持 Tag 功能,可以视为轻量级的快照,大幅降低了存储成本。
--------------------------------------------------------------
参考:结合Paimon与StarRocks构建流式湖仓-实时计算 Flink版-阿里云



---------------------------------------------------
StarRocks+Paimon 落地阿里日志采集:万亿级实时数据秒级查询-阿里云开发者社区

StarRocks 内表可以存储实时数据,且查询性能良好。但考虑到 Paimon 数据湖存储的扩展性,StarRocks 的高效数据湖分析能力,选择 Paimon 存储 + StarRocks 计算。
StarRocks 和 Paimon 方案优势如下:
(1)Paimon 存储复用实时公共层能力,高效承接实时日志数据
实时公共层采用 Paimon 存储来管理公共层的数据,支持多地多机房 Flink 实时订阅。公共层表的存储格式为 Aliorc。
StarRocks+Paimon 方案,复用实时公共层的能力。实时公共层以 Aliorc 格式(基于 ORC 格式的内部优化版本)存储消息队列中的实时日志。进一步地,通过 Flink 订阅 Aliorc 格式的实时公共层 Paimon 表,写入到 Parquet 格式的 Paimon 分桶表中,供计算引擎查询。目前 StarRocks 引擎对 Aliorc 格式数据正在支持中,等待支持后,日志查询直接通过 StarRocks 查询实时公共层数据,不需要额外的存储和实时数据订阅。
(2)StarRocks 高效数据湖分析能力实现秒级查询
StarRocks 可以作为计算引擎直接分析数据湖中的数据。用户可以通过 StarRocks 提供的 External Catalog,轻松查询存储在 Apache Hive、Apache Iceberg、Apache Hudi、Delta Lake、Apache Paimon 等数据湖上的数据。

在日志查询场景中,StarRocks 主要负责数据的计算分析,而 Paimon 数据湖则主要负责日志数据的存储、组织和维护,StarRocks 作为 Paimon 数据湖的计算引擎,可以大大提升日志查询的性能。StarRocks 对于 Paimon 湖格式的读取支持能力非常优秀,相对传统的 OLAP 查询引擎,主要有以下优势:
- 高效的向量化执行引擎,硬件资源使用率最大化
- 充分利用 Paimon 的表统计信息,高效完成最优的 CBO 查询规划
- 支持 native 方式高效读取 Paimon Deletion Vector,降低实时更新场景查询时延
- 优秀的谓词下推和分区裁剪能力,大大减少远端 I/O 的请求成本
(3)Paimon 存储成本低,扩展性高
Paimon 作为一个新兴的数据湖格式,近些年发展十分迅猛,该格式的主要特点有:
a. 强大的流批一体数据处理能力,支持大规模更新和写入。
b. 创新性地引入 LSM 结构来处理更新数据,显著降低业务数据写入延迟。
c. 支持 Deletion Vector 和多种索引技术,大大提升 OLAP 查询引擎执行效率。
Paimon 的设计基于存储与计算分离的理念,阿里的 Paimon 数据存储在分布式文件系统 Pangu 中,Pangu 是阿里云存储服务的底层存储系统。Paimon 支持多种计算引擎的接入。除了日志查询通过 StarRocks 读取 Paimon数据,其他计算任务也可以通过 Spark 等引擎消费 Paimon 日志表。
出于 StarRocks 查询性能高、复用 Paimon 实时公共层、Paimon 存储成本低扩展性高这几方面的考虑,日志查询选择 Paimon 数据湖作为存储,StarRocks 引擎用于查询计算。


2.2.2 控制文件大小
Paimon 存储中的文件大小,会对下游引擎(StarRocks)的查询性能造成以巨大影响:
- 小文件
-
- Scan File 开销增加:StarRocks 在扫描文件时需要逐一加载每个文件的元数据(如 Manifest 文件)。如果文件数量过多,元数据加载的时间会显著增加,导致查询延迟。
- I/O 瓶颈:小文件通常意味着更多的随机 I/O 操作,增加了磁盘读取的开销。
- 大文件
-
- 单个 Row Group 的限制:Flink 默认使用 Arrow Parquet 写文件,单个 Row Group 上限是按照 max_row_group_length 来控制,默认值 1Mi(1024*1024) Rows,阿里日志明细单行数据较大,平均有 500B,导致单个 RowGroup 会到 600M+。如果文件过大,Row Group 的大小也会随之增大,这可能导致读取效率下降,尤其是对于随机读取场景。
- 查询延迟增加:大文件在加载时需要一次性读取更多数据,可能会增加内存压力和查询延迟。
为了控制 Paimon 存储文件大小,优化 StarRocks 查询性能,尝试了文件合并与调整 Checkpoint 两种方法,最终选择通过 Checkpoint 控制文件大小。
Checkpoint 控制文件大小
对于日志查询的 Paimon 表,通过调整 Flink 任务的 Checkpoint 时间间隔可以控制文件大小。针对不同的 Flink 任务,根据其数据流量和写入模式,设置不同的 Checkpoint 时间间隔,简介且有效。
通过对不同的 Flink 作业设置不同的 Checkpoint 时间间隔,Paimon 中大多数文件的大小控制在 100M 到 400M 之间,既避免文件过小导致 Scan File 开销增加和 I/O 瓶颈,也避免文件过大导致查询延迟增加。
分区方案
用一张表保存全量的 UT 日志,在写入过程是稳定的,但是 Compact 文件的过程中,删除文件频繁发生冲突,造成 flink 作业中断,数据延迟不断累积。可以通过拆分多个 Flink 作业单独写入,针对性地配置 Checkpoint 大小,以此控制文件大小,提高查询性能。
采取单表多分区的形式来存储日志数据,同时通过 Checkpoint 控制文件大小,flink写入作业运行稳定,StarRocks 引擎查询日志不存在明显瓶颈。
----------------------------------------------------------------------------------------
1. 方案背景与核心组件
-
Paimon:
Apache Paimon(原Flink Table Store)是一种流批统一的湖存储格式,支持高吞吐写入、低延迟查询及ACID事务。它通过LSM(Log-Structured Merge)架构实现高效数据追加与合并,兼容HDFS/S3等存储,适合作为实时数仓的ODS层。 -
StarRocks:
一款极速全场景MPP数据库,采用列式存储与向量化执行引擎,支持实时OLAP分析。其CBO优化器与物化视图技术可显著提升复杂查询性能,兼容MySQL协议,适合作为分析引擎。
2. 集成架构与优势
(1)湖仓一体架构
-
数据湖层(Paimon):
存储原始数据(如日志、Binlog)及预聚合结果,支持分钟级新鲜度查询。通过Flink/Spark写入,利用Paimon的LSM索引加速过滤。 -
分析引擎层(StarRocks):
通过外表(External Table)直接读取Paimon数据,或通过物化视图构建DWD/DWS层。支持嵌套物化视图(如DWD→DWS→ADS),简化ETL流程。
(2)核心优势
-
性能提升:
-
StarRocks的向量化引擎使复杂查询速度提升10倍以上。
-
Paimon的列式存储(Parquet/ORC)减少I/O开销。
-
-
成本优化:
-
冷数据存Paimon(S3/OSS),热数据存StarRocks,降低存储成本90%。
-
饿了么案例:Flink资源缩减50%,查询性能损失仅5%。
-
-
开发效率:
-
统一SQL接口,支持跨引擎查询(如Flink+StarRocks联合分析)。
-
物化视图自动刷新,减少重复开发。
-
3. 典型应用场景

---------------------------------------------------------------------------
京东物流基于Flink & StarRocks的湖仓建设实践-阿里云开发者社区

我们对 StarRocks 的一些特性进行了调研,特别是 3.0 以上版本中推出的物化视图增强功能。此外,还研究了其存算分离的场景,这对于京东物流当前长周期数据存储的优化以及对业务查询的支持是非常有帮助的,可以为我们带来非常大的成本节约。这一点将在后面分析案例中重点探讨一下。StarRocks 的 Spilldown 过程对于数据优化查询的帮助也相当大。最重要的是,联邦查询的引入。联邦查询之所以重要,是因为在京东物流复杂的业务场景下,它能提供多样化的数据服务。例如,团队可以通过联邦查询快速迭代满足外部存储或业务方的数据构建需求。业务方的原始数据可能存储在 MySQL、Oracle 甚至其他非关系型数据库中,我们不可能迅速将这些数据进行实时化数据支持。联邦查询在在我们这里应用最广的是我们内部的 UData平台,它基于 StarRocks 的联邦查询功能,实现了数据平台化的数据服务,支持业务人员进行报表分析和业务分析。根据团队内部的统计,全国所有省份及地区的报表业务分析人员总数大约在万人级别,即大约有一万多人从事数据分析工作,包括站点分拣、仓库运营中心以及京东总部等大量运营人员,都是通过这种方式进行数据分析。

StarRocks 湖仓一体建设的整体架构方案,通过 Flink 或 Kafka 的流式处理,数据实时写入到 StarRocks 中,实现数据的实时入湖。然后通过联邦查询进行外部数据链接,以满足业务方对快速数据模型构建和数据分析的需求。

分层建设主要分为外表物化、聚合服务和数据服务三层架构。数据服务层主要负责快速响应外部数据的查询需求,并适应多种数据分析场景。至于模型聚合分层下文也会简要分享如何实现模型聚合分层,以及如何实现分钟级的数据分层建设方案,这里使用多种方式结合,例如流批一体进行数据聚合、定时调度等方案设计。


我们利用 Paimon 存储和 StarRocks 的物化视图替换了上图中间部分,并利用Udata平台以接口服务的形式将数据提供给外部用户。经过这样的架构升级,我们不再需要将部分数据推送给外部存储,而是直接调用数据接口,进行数据查询和报表展示。外部商家的开发人员可以调用接口,直接访问我们底层存储的数据。这不仅缩短了数据加工的链路,也大幅降低了数据服务的开发成本,缩短了开发迭代周期,快速响应需求。这种模式的优势在于能够以天为单位的响应速度甚至更快地满足数据需求,能够及时对接外部服务。
遇到一些问题,比如在使用 Flink 同步 Paimon 时,需要调整 Checkpoint 的设定,处理 Paimon 小文件的合并时机的合理性,以及将 Paimon 小文件合并异步化的过程等。解决小文件异步合并过程中遇到过一个问题,在执行检查点时,如果小文件过多,可能会导致底层合并或查询操作的延迟很大,甚至产生长尾效应,对 Flink 任务产生反压。
希望快速进行当前数据和历史数据的数据分析,这一点离线数据分析不能达到他们的要求。为了便于既能快速数据分析又能查询较久以前的历史数据,我们采用了存算分离的措施进行数据存储。访问频次较高的数据即热数据,我们缓存在本地磁盘,而访问频次较低的数据即冷数据,我们存在云端。底层存储方面,我们直接选用京东云的 OSS,即对象存储,它支持标准的 S3 协议,这大大降低了团队的存储成本。

我们在存算分离集群上,创建了长周期存储的实时表,和存算一体的集群不同的点在于,我们可以进行分钟级的长周期表更新,更新量非常大,往往需要横跨多个分区。因此,团队必须对主键进行持久化的存储,并建议将主键索引存储到本地盘中。
在存算分离的场景下,由于 OSS 已经采取了多副本策略,指定额外的副本数量是不必要的。但是,在使用云存储时,必须指定存储卷,例如在京东云上指定 Bucket 的数量或存储卷。
此外,应避免自动创建存储卷,而应选择手动创建,以防止认证问题和数据交互中可能出现的 Bug。
--------------------------------------------------------------------------
基于 StarRocks 和 Paimon 打造湖仓分析新范式 - 知乎
当前数据湖四剑客 Iceberg、Hudi、Delta 和 Paimon,主要解决的问题是原始数据经常大量批更新、ACID 的事务管理、并发处理以及 Schema Evolution 等
Apache Paimon 是由 Flink Tablestore 项目孵化而来的,其最大的特点是入湖速度特别快,Compaction 也特别及时,所以适用于对实时性要求很高的场景,并且 Paimon 是原生流处理。

StarRocks 是一个极速、统一的数据湖分析查询引擎。如上图,StarRocks 定位是分析层。从下到上看,最下面是存储层,包括常见的 HDFS,也有廉价的对象存储,如 S3、OSS 等。
在使用 StarRocks 之前,我们常用 Hive、Impala、Presto、Trino 等各种分析引擎去分析。StarRocks 的定位是统一这些分析引擎,把复杂的语义都放在一个引擎里去操作,再通过 StarRocks 直接对接上层的业务报表、Adhoc 查询等工作。

之前如果想建Hive 表,需要按表来建,即执行 create external table,指定各种字段。然而大数据领域库表是非常多的,可能几十张、几百张,如果这样逐一建表,会浪费很多时间,也容易出错。所以 StarRocks 引入了 Catalog 数据目录,只需要指定一个 MetaStore URL 或一个 File system 的 URL,就能自动加载整个目录下的库表,不用建表就可以直接进行查询分析。
StarRocks 的优势是 native,它是用 C++ 语言写的,如果不构造一个类似 JNI Connector 中间层,而使用 C++ 去对接 Java 的湖格式,就要用 C++ 重写各种湖格式的 reader,代码量会非常大,而且也不容易跟社区进行完整的结合。所以引入了 JNI Connector,简单配置几个类,如 reader 的类名就可以直接使用 C++ 读取 Java 的数据。
另一个重大特性就是引入外表物化视图,这就解决了如何查得更快的问题。比如Hive 外表或者 Paimon 外表,放到物化视图里以后,这些数据会使用 StarRocks 自己的存储格式存在自己的存储管理系统里,这样就可以用到大量的 StarRocks 内部的索引优化、CBO 优化等,存储和查询引擎相结合带来的查询优势。
延迟物化,比如谓词有两个列,查询列 a 和列 b。这两个列的选择度可能不同。选择度指的是,比如一百行数据,通过谓词下推之后,可能只剩下 10 行,另外一个谓词下推之后还有 80 行,那么第一个列的选择度就更高。我们就可以直接用第一个列的谓词结果再读取其他列,大部分数据就不用读了,只需要读 10 行就行。
Pipeline 执行引擎,指的是调度优化。
一个 SQL 的查询效率很大一部分除了格式和 IO 优化,还取决于它的执行计划。得到的统计信息越多、越丰富,执行器优化器出来的执行计划也就会越好,执行效率也就会越高。但是在外表情况下,统计信息很多都是缺失的,这是现实问题,所以要使用外表物化视图把它物化进来,通过StarRocks 自动索引以及统计信息机制。把需要的统计信息都构建好,后面的查询就可以更快了,这就是为什么可以使用 StarRocks 加速外表查询。
算子落盘 Spill,这个也是 StarRocks 3.0 最重大的特性之一,支持了 Spill 之后,才能容纳大规模数据量的查询。比如机器内存比较小的情况,几个 G 或十几个 G,有了 Spill 之后,所有算子的中间结果可以落盘之后再复用。之前很难做到在小内存的机器下做大数据量的查询,在Spill 基础上就可以用 StarRocks 做大数据量 ETL 了。
最后一个重大特性是支持 Hive、Iceberg 数据写入,现在完全可以使用StarRocks 去做数据湖仓分层的主要引擎。
Data Cache 顾名思义就是缓存,现在的 Hive、Iceberg、Delta lake 或 Paimon,大多使用对象存储,对象存储走 HTTP 有网络波动可能会带来不稳定。在遇到带宽瓶颈时,查询效率就上不来。这种情况下 CPU 是空闲的,只是网络占用高。因此引入 Data Cache 在本地做缓存。
第二个部分介绍使用 StarRocks 和 Paimon 可以做哪些事。
1. 联邦查询
联邦查询可以跨数据源查询,目前已经支持了大部分数据源,如 Hive、Paimon、Iceberg、Hudi、Delta Lake,能直接分析湖上数据。并且这些不同格式的数据可以联合在一起查询,比如一个 Paimon 表 Join 一个 Iceberg 表,一个 Hudi 表 Join 一个 Hive 表。当然 StarRocks 本身有自己的内表格式,这个内表格式也可以跟湖格式进行互相访问和 Join 查询。最终可以做到跨数据源的联邦分析,内外表的数据访问统一管理。
引入 Catalog 机制之后,使用 StarRocks 查 Paimon 表,只需要 create external catalog,指定 type 等于 Paimon。Paimon 目前有两种 Catalog 类型,StarRocks Catalog 的实现目前映射到 Paimon Catalog,这两种类型是Hive Metastore 和 File system。
Metastore 相当于元数据存在 Hive Metastore 里,而 File system 相当于 Paimon 表不依赖 Hive Metastore,它本身存在文件系统里。实际上使用 Metastore Catalog 的一般也能用 File system 查询,因为所有数据就是落在存储上的。
HMS 实现只是为了兼容重度依赖 HMS 系统的场景提供的。这里以 File system 这种 Catalog 为例,再指定一个 Warehouse 地址。可能很多业务都是多个 Warehouse,一个 Warehouse 有不同的库和表,只需要指定这个 Warehouse 地址,StarRocks 就会自动取到这个 Warehouse 下所有的库和表,然后就可以执行查询。Select * from 刚刚建的 Paimon FS catalog,之后 .db.table 就可以直接查到表。这是联邦查询的第一个场景,相对比较常见。
2. 透明加速
透明加速。如果直接查同样外表的话,SQL 也会有很多种,比如经常用到某两张表的聚合,有时候 Select A,有时候 Select B,有时候 Count* 以及 SUM 不同字段。
在传统的数据分析引擎里,每次查询都要扫描全表,现场做一些计算再返回。这就可以用到物化视图。如下面的 Select 语句(这是一个 TPCCH 查询),这个查询是最简单的聚合查询,执行一次要扫全表,执行第二次还是要扫全表。但如果先建立一个物化视图,如图中所示,三张表的内容就物化到 StarRocks 内部存储系统里了。
StarRocks 会自动构建索引,作为统计信息来优化它的执行计划。在查询时,比如写一个类似下面的 SQL,当匹配到能用的物化视图时就会直接使用物化视图预计算的结果,从而实现加速。这就是透明加速,声明物化视图让优化器自动改写,解决了 BI 报表不易修改 SQL、不易调优的问题。
3. 数据建模

第三个场景是数据建模。数仓一般都采用分层结构,最底层是 ODS 层,往上是 DWD、DWS、ADS 等。每一层都会面向不同的业务场景去做分析。StarRocks 的物化视图支持嵌套,前面的例子是在一个 Paimon 表里建物化视图,还可以在已有的物化视图之上再建立一个物化视图,达到数仓分层的效果。
底层存储可以使用 HDFS 或者 OSS 等作为基座,上面使用 Paimon 格式,最上面使用 StarRocks 做分析。
4. 冷热融合

首先 create materialize view,里面可以指定一些 property 属性。只需要告诉Paimon 物化视图的 partition TTL 等于 3 month,那么物化视图在构建的时候就会把这三个月的物化视图自动拿到 StarRocks 里做加速。假如要查三个月的数据,全量地读物化视图即可,可以天然地用到索引加速。如果要查五个月,那三个月内的数据还是会走物化视图做加速,另外两个月不在物化视图内,会去走远端,拉取原始的 Paimon 或者外表信息,然后自动将五个月的数据做 union 再返回。不需要像传统一样全部 5 个月的数据都要从外部存储做一次 IO 查询。在热数据本身已经在物化视图里的场景,就会自动使用热数据加速。用户在 SQL 语义上不需要做任何改动。
03使用 StarRocks+Pamon 数据湖分析的关键技术原理

StarRocks 查询是用 C++ 写的,为了便捷地读取 Java 数据,引入了JNI Connector 存储层,整体架构如上图所示。底层 Java Data Source 是数据源,可能是 Paimon、Hudi 等。在接入一个新数据源时,只需要实现 Open、GetNext 和 Close 三个方法。调用原始 Java Reader 的一个封装,告诉 JNI Connector 数据信息。再进行一些配置,比如对于 Paimon,配置 Paimon Reader 的类名称,再配置一些必要的信息,就可以使用这套 JNI Connector 读取外部的 Paimon 数据源了。中间所有 Java 和 C++ 内存转换都不需要操心,所有的类型都在 JNI Connector 里封装好了。
主要功能有五点:
- 可以快速接入各类的 Java 数据源,无需考虑数据转换。
- 提供了简单易用的 Java 接口,只需要实现 open、getNext、close 三个方法即可。
- 已支持 Hudi MOR table、Paimon table 等新兴的数据格式。
- 支持 Struct、Map、Array 等复杂类型。
- 完全做到 BE(Backend)C++ 代码的零侵入,不需要考虑任何 C++ 具体实现。

定长字段类型比如 long、int 等;变长字段类型有 varchar、string 等。实现 JNI Connector 的时候,要在 Java 开启一块堆外内存,因为要让 C++ 的代码去访问它,C++ 不太方便直接访问 Java 堆内存。另外,使用堆外内存所有的分配和释放都可以由自己来控制,相对比较灵活。直接使用堆内存的话,还需要考虑 Java 回收机制的影响。
对于定长字段类型,会有两块区域去存信息,第一块是 null indicator,每一个块都由一个个字节挨着放在一起。如果是 true,就说明这一行的数据为 null。如果 null 的话,就不用访问数据内存,如果非 null,就需要访问数据内存。对应的数据内存比较简单,比如 int 类型,就是四个字节内存排在一起。变长类型的存储多了 offset 地址,因为变长需要把 offset 记录起来,在内存里一个个排列好,后一个减前一个加一,就是整个行的数据长度。
这里所有的核心都是围绕 C++ 内存的访问,围绕 StarRocks 在 C++ 里是如何对不同类型进行布局的。最后 Java JNI Connector 实现的时候,只要把内存布局在堆外放成 StarRocks 可识别的布局,C++ 代码就可以访问了。实际访问的C++ 代码也比较简单,直接把整块内存做 mem copy,即可直接进行读取。
---------------------------------------------------------------------------
淘宝闪购实时分析黑科技:StarRocks + Paimon撑起秋天第一波奶茶自由 - 知乎
物化视图优化:StarRocks 的异步物化视图功能被用于预计算高频查询场景,通过将复杂计算结果持久化存储,将原本需要扫描千亿级数据的查询耗时从分钟级压缩至秒级
RoaringBitmap 去重:针对超大数据量多维度实时交叉去重指标计算场景,团队引入RoaringBitmap 技术,结合Paimon 的流读流写能力和 StarRocks 丰富的 Bitmap 函数支持,在保障查询性能的同时,业务可以查询实时数据进行任意维度的灵活分析
存储成本大幅降低,实时分析链路端到端延迟显著下降,并支撑海量日志数据的高并发查询场景,为业务决策提供了可靠的实时数据支撑。
StarRocks 作为一款极速统一的 MPP 数据库,利用其 Catalog 功能,可以接入多种外部数据源,如 Paimon、Hive、MaxCompute、Hudi、Iceberg 及其他可通过 JDBC 协议连接的各种数据库等。StarRocks 内部通过维护这些外部数据源的元数据信息,直接访问外表数据,我们无需在不同介质间进行数据的导入导出。
在开启 Paimon 表的 deletion-vectors 属性后,StarRocks 查询 Paimon湖表的性能有了十倍以上的提升。因此,我们业务上可以不经过 ETL 操作,直接使用 StarRocks+Paimon 的方案迅速搭建数据看板。

我们将实时流量数据通过 Flink 入湖,维表数据通过 Spark 入湖,StarRocks 作为计算引擎直接查询Paimon湖表,FBI接入SQL数据集搭建实时看板,快速解决了业务实时看数需求。

三、物化视图:StarRocks 助力 Paimon 解锁查询新体验
物化视图分层加速架构
预计算层:针对高频访问的复杂查询(如多表关联、窗口聚合),通过 StarRocks 物化视图预计算结果集,查询响应时间降低 80% 以上
更新机制:我们维护了 120+ 个物化视图,平均 15min 刷新间隔,最高支撑了单分区千亿级别的数据物化加速
资源隔离策略:通过 FE 节点(25个)与 CN 节点(120个,总9280 CU)的混合部署,将物化视图刷新任务与实时查询流量隔离,支撑单日业务有效查询数量峰值为 17万/天(含1万+物化刷新任务),项目后期 CN 节点扩至 300 个,集群规模达到 20800 CU。
实时看板建设实践基于优化后的架构,我们搭建了覆盖全链路的实时分析体系:
流量全景看板:聚合用户行为、渠道来源、访购转化等多维度数据,支持分钟级漏斗分析与流量渠道 ROI 计算
动态资源看板:通过 StarRocks 内置的资源监控接口,实现集群负载动态可视化,物化视图刷新成功率稳定在99.9% 以上
异常诊断看板:集成 EMR Serverless StarRocks 的智能诊断平台,快速定位慢查询,问题定位效率提升 60%
3.1 StarRocks&Paimon 物化视图原理
StarRocks 的物化视图主要分为同步物化视图和异步物化视图两大类:
- 同步物化视图:只支持单表,在导入过程中同步刷新。基表只能是内表,不支持 Paimon 表
- 异步物化视图:支持多表,同时支持异步刷新/手动刷新。基表支持 Paimon 表
非分区物化视图:执行完整查询,全量覆盖视图数据,可以用于热点数据加速
分区物化视图:根据参数及基表数据变更情况,以分区粒度刷新视图,可以用于长周期存储数据。其中物化视图分区支持下面两类
Range 分区:通常以 date 类型作为分区字段,可使用 date_trunc 函数实现分区上卷
List 分区:3.3.5 版本支持,分区字段为可枚举的 string 类型或不连续的 int 类型

同步物化视图作为基表的附属结构,与基表数据实时同步,但使用场景较为局限,比较典型的场景是使用 Bitmap 或HLL 在内表中进行去重计算,我们所使用的物化视图通常为异步物化视图。

异步物化视图的调度框架主要有两个核心概念:Task 是周期运行的刷新任务,TaskRun 为每次刷新周期的运行实例。我们可以通过系统参数来设置 TaskRun 的最大 Pending 数量,Running 的并发数量及生命周期等。

对于带分区的物化视图,主要通过与上游基表的分区依赖和数据变化来刷新对应视图分区,可以通过参数控制刷新行为,对比物化视图与基表对应分区的可见版本,来判定需要刷新的分区,以防止过多分区刷新导致的资源浪费;

每次刷新都是通过生成一个 insert overwrite 任务,先创建临时分区并写数据,然后将临时分区与目标分区进行原子替换

3.2.1 优化1:基础 Paimon 物化视图

在 StarRocks 与 Paimon 之间,针对看板数据集的查询 SQL 进行了物化处理,每十分钟进行一次刷新,加速查询的同时缓解集群大查询带来的压力。
3.2.2 优化2:针对长周期历史数据的查询优化
业务需要查看日环比、周同比指标,提出了长周期数据存储诉求,于是在原有方案基础上,加了一条 DataWorks 凌晨离线 insert 调度任务将前一天数据写到 StarRocks 内表,然后将当日实时数据与历史离线数据 UNION 为一个虚拟视图。

3.2.3 优化3:引入带分区的物化视图
阿里云 EMR StarRocks 3.3 版本中,支持了基于 Paimon 湖表的分区物化视图以及多基表分区对齐特性,我们将优化1 中的物化视图直接改为分区物化视图以支持历史数据存储。
使用分区物化时,只需要使用 PARTITION BY 指定分区字段(需要与基表分区对应)。
分区物化视图定义中不需要限制分区字段取值范围,我们在创建分区物化视图时通过设置 PROPERTIES 来控制刷新行为,存储近 30 天分区("partition_ttl_number" = "30"),并根据事实表数据变动每次至多触发两个分区刷新("auto_refresh_partitions_limit" = "2"),每个调度实例只刷新一个分区("partition_refresh_number" = "1"),同时配置 excluded_trigger_tables 参数来忽略维度表变动触发的刷新行为。

- 当基表分区字段为字符串类型的日期时,物化视图会创建List分区,且在刷新时触发全表刷新,可以使用 str2date函数转为日期类型,创建 Range 分区物化视图;
- 视图始终依赖于基表,物化视图刷新前会进行分区检查,基表中不存在的分区也会在物化视图中删除,即便视图属性中设置了更长时间的 partition_ttl 也无法阻止这一操作;
四、RoaringBitmap:StarRocks&Paimon 实时去重的极速神器
物化视图更应作为 ADS 层的数据加速,而DWD 到 ADS 层的 ETL 过程应尽可能在 Paimon 中完成。即让数据在湖里流动,StarRocks 物化视图做链路终端的查询加速。比如可以利用 Paimon 的 Partial Update 解决双流 JOIN 的场景,Aggregation 特性处理聚合场景等。
在湖上利用 RoaringBitmap 解决大数据量级精确去重,流量域中多维数据的快速分析,基于 Bitmap 的不同人群下钻、访购率计算,流量域中长周期指标的实现等场景。通过 StarRocks 的 Bitmap 相关函数直接查询存储在 Paimon 中的 RoaringBitmap 数据,大幅提升了实时 UV、多数据域分析的数据新鲜度和查询性能。
4.1 RoaringBitmap去重原理浅析
Bitmap 去重方案中,每个维度仅需存放一个 UID 位图即可,去重即是对多个 Bitmap 进行位运算(OR),然后直接统计位图中1的个数即为 UV 计算结果。大数据场景下,Bitmap 的存储方式相比与 UID 去重后的明细数据显然节省了大量存储空间。

但当某个维度为稀疏分布时,此时长度为 n 的位图仅有少部分是有效位,存在大量的无效 0 占用空间,所以,需要一种更灵活的存储方式来解决这个问题。RoaringBitmap 是一种高效压缩位图结构,专为快速存储和操作大规模整数集合设计。它通过智能分桶和动态容器选择,在空间压缩和计算性能之间实现最佳平衡,在当下主流的大数据计算和存储引擎中,RoaringBitmap 也被越来越广泛的应用。以32位 RoaringBitmap 为例,内部会将高16位进行分桶,低16位根据桶内数据分布特征选择Array Container(数组容器)、Bitmap Container(位图容器)、Run Container(游程编码容器)三者中空间利用率最高的容器存储。

十进制数 131397 转为十六进制为 0x00020145,其中 0x0002 为高位分桶,该分桶内元素小于 4096,低位 0x0145(16*16*1+16*4+5=325)采用 Array Container 存储,二分法找到对应数组位置。当元素个数达到 4096时,数组容器占用的空间为 2*4096=8192 字节,此时与位图容器所占空间一致。即当一个分桶内的元素个数超过 4096 时,会选择位图容器存储,并根据数据的连续程度来判断是否优化为行程编码以进一步压缩存储空间。

4.2 RoaringBitmap 去重适用场景
4.2.1 多维预计算(CUBE)
使用 RoaringBitmap,将中间层的轻度去重数据由 UID 改为聚合后的 Bitmap,原方式下,每组最细维度下有多少UID,就需要存储多少行数据,新的存储结构每组维度只需要存储一行 Bitmap 即可,极大节省了存储空间。同时下游使用位运算计算 UV 指标,计算效率也提升数倍。

4.2.2 时间上卷(UNION)
位图 UNION 的本质是 OR 运算,使用 bitmap_union 和 bitmap_union_count 可以实现时间上卷或细粒度向粗粒度的聚合和去重统计,在数据湖中,可以利用 Paimon 流读流写特性和 Aggregation merge-engine 简单快速地实现bitmap 的聚合计算,当前 Paimon 的 Aggregation 已支持 rbm32 和 rbm64 函数。
bitmap_or 是对两个 Bitmap 做并集,bitmap_union 是聚合函数,对同一列的多个 Bitmap 做并集计算。

4.2.3 人群下钻(AND)
Bitmap 的交集计算适用于电商业务中常见的留存、复购、多维交叉分析等场景,即粗粒度模型存储实现更细粒度的实时分析。也可以利用交集来进行人群下钻。与其他维度不同,用户人群维度通常不是一成不变的,且开发人员无法按照既定规则去预判这种变化,业务会按需圈选各种各样的人群包。为应对不同人群的灵活下钻分析需求,在设计数据模型时我们可以把人群维度单独处理。如我们在流链路里做了一张分钟流量的 Bitmap 表,批链路加工一张人群维度的 Bitmap表,使用 bitmap_and 函数计算交集后即可得到每个人群对应的小时切片 UV。

5.3 资源隔离
StarRocks 通过资源组(Resource Group)实现多租户资源隔离,允许按用户、角色或查询类型动态分配 CPU、内存及并发资源。通过设定资源配额和优先级规则,确保关键任务独享资源,避免资源竞争,保障高负载下查询性能和稳定性,支持灵活配置与实时弹性调整。StarRocks 内置了两个资源组 default_wg 和 default_mv_wg,分别对应普通查询任务和物化视图刷新任务,用户也可以根据业务场景自定义资源组配额,使用也非常简单,只需要创建资源组和分类器即可。
但需要注意的是,通过 Resource Group 实现的资源隔离通常为软隔离,即假设有三个资源组 rg1、rg2、rg3,资源配额为 1:2:3,当 BE/CN 节点满载时,集群资源会按照配额分配;当 rg1、rg2 有负载而 rg3 无负载时,rg1 和 rg2 会按照 1:2 比例分配掉全部资源。
5.4 SQL 及物化视图治理
常见的优化手段包括:
- 如果关联字段也是过滤条件,将过滤条件写在大表上,以便谓词正确下推至存储层;
- 大表与小表关联时,可以添加 JOIN HINT,使用 BROADCAST 方式关联减少节点间数据 shuffle;
- 聚合场景添加查询 HINT 选择合适的聚合算法,如低基数维度去重统计添加 set new_planner_agg_stage=4;
- 当多表关联时优化器未选择最优的连接顺序,可以尝试添加 JOIN HINT 或将连接条件书写完整,如 a、b、c 三表关联,ab、bc、ac 三个连接条件都写出来。
将物化视图的刷新任务与 SQL 查询进行资源隔离。
在创建视图时规避以下错误或不恰当的用法:
- 日期写死,等于固定日期(无效视图),大于等于固定日期(高危视图);
- 非分区物化视图未添加分区限制条件,即每次刷新全表数据;
- 分区物化视图未设置参数控制刷新行为,存在全表刷新风险,如维表数据变动;
- 多个测试版本视图未及时删除,下游无业务,空跑浪费集群资源;
- 视图定义中存在多组维度的 CUBE 且刷新频率极高。
351

被折叠的 条评论
为什么被折叠?



