摘要:本文整理自计算平台软件研发工程师钟宇江老师在 Flink Forward Asia 2024 流式湖仓(一)专场中的分享。内容主要为以下三部分:
一、背景介绍
二、基于 Paimon 构建近实时数据湖仓
三、未来展望
一、背景介绍
第一部分是背景介绍,简单介绍之前的典型的实时数仓的架构,以及引入 Apache Paimon 的原因。
1.1 当前实时湖仓计算框架以 Flink + Talos + Iceberg 为主
上图展示了我们之前的实时湖仓计算架构。上半部分是实时链路,主要由 Flink、Talos 和 Iceberg 组成。Talos 是我们内部自研的消息队列。此部分链路中的数据通常来自在线系统生成的交易数据或终端上报的日志。数据经过采集平台上报到 Talos 后,用户可以对其进行自定义的数据转换操作,生成实时数仓,供下游系统消费。下游系统通常是 OLAP BI 应用平台或即时查询系统。
图的下半部分展示了离线链路。由于实时链路为了稳定性或计算资源的原因,可能会丢弃部分属性并且不会保留完整周期的数据,实时链路计算出的结果并不完整。因此,我们使用离线链路来计算最终的正确数据结果。
1.2 当前架构痛点
这套架构主要存在以下几个痛点:
(1)实时计算成本高:湖仓主要使用 Iceberg,但 Iceberg 对流计算语义的支持有限。例如,流计算中常用的一些频繁更新操作,如 Stream Join、实时去重以及部分列的更新,Iceberg 都无法支持。因此,许多计算操作需要在计算层面完成,即在 Flink 作业中进行。这导致作业资源消耗较多,且稳定性较差。
(2)架构复杂,作业稳定性差:在进行实时化处理时,整个作业架构较为复杂,稳定性较差。从之前的图中可以看到,除了实时数仓中的 Iceberg 和消息队列外,还会根据需求引入外部的 KV 系统。这部分 KV 系统会增加用户的运维成本,并且使用不便,无法直接通过 OLAP 引擎查询。
(3)存储成本高:由于存在实时和离线两条链路,并且在 KV 系统中存在数据冗余,存储成本较高。KV 系统中的数据价格通常比湖仓成本高很多。
1.3 对于实时数仓的期待
针对实时入仓的问题,主要有以下几个期待:
(1)降低计算成本:希望能够更好地结合流计算和数据湖仓,尽可能减少实时化所带来的额外资源消耗。
(2)简化架构,提升稳定性:期望通过一套架构完成实时链路的开发,最好是使用 SQL 或 SQL + 数据湖仓的平台,以此来提升系统的稳定性。
(3)统一数据链路:努力避免因实时和离线两套链路带来的重复开发和运维成本,同时减少数据冗余。
二、基于 Paimon 构建近实时数据湖仓
第二部分介绍基于 Paimon 构建近实时数据湖仓,对 Paimon 的能力做介绍,介绍经典的应用场景和应用之后带来的收益。
2.1 Apache Paimon
对 Paimon 的理解可以简要总结如下:
(1)Lakehouse 表格式:Paimon 与 Iceberg 和其他 Data Lake 项目相似,属于 Lakehouse 的表格式。这意味着其底层存储可以是 HDFS 或 S3,具有很强的可扩展性且成本低廉。同时支持 AICD 和 Schema Evolution,Paimon 像传统数仓一样,支持 AICD(添加、插入、变更、删除)操作,并支持 Schema 演变,确保数据更新的可靠性和安全性,同时可以根据业务需求对 Schema 进行调整。
(2) LSM 存储结构:在 Lake House 架构的基础上,Paimon 创新性地引入了 LSM(Log-Structured Merge-Tree)存储结构,带来了以下三个主要能力:
- Streaming Upsert 功能:能够进行实时数据去重和高效的 CDC(Change Data Capture)更新。
- Partial update:支持对部分列进行更新。
- Aggregation:近实时数据聚合
总结而言,Paimon 在 Lakehouse 结构之上,通过引入 LSM 数据结构,实现了对流计算语义的有效支持,同时对批处理也提供了良好的支持。
2.2 应用场景 1:使用 Paimon Partial-Update 实现数据打宽
应用场景可以描述为,使用 Paimon 的部分列更新功能来实现数据的打宽。在引入 Paimon 之前作业通常使用典型的双流 Join 方案。作业会消费两条事件流,进行过滤和转换操作,然后进行双流 Join。由于数据量较大,状态可能轻松达到 TB 级别。为了减少 Flink 作业的状态,通常会将更长周期的数据存放在 HBase 或 Pegasus 等外部 KV 系统中,而在 Flink 作业中只保存最近几个小时的数据状态。
这样做带来了两个问题。首先,状态过大导致作业不稳定;其次,需要使用额外的 KV 系统,增加了开发和运维成本,并且 KV 系统的管理并不方便。分析这些问题的根本原因,可以发现双流 Join 的效率非常低。由于双流数据量过大,Flink 状态数据大部分都缓存在本地磁盘中,Join 时如果内存中的数据缓存被击穿,就需要进行磁盘的随机读。由于整体数据流量很大,磁盘随机读的频次非常高。此外,当需要查找更长周期的数据时,必须访问外部的 KV 系统,这不仅带来了网络开销,还导致数据冗余。
为了解决上述问题,可以利用 Paimon 的部分列更新功能。Paimon 支持一种名为 Partial-Update 的 Merge 引擎。这个功能能够对相同主键的多条记录进行合并,取每个列的最后一个非空值。然而,这种 Merge 操作并不是在 Flink 的计算任务中完成的,而是在 Paimon 表的 Compaction 任务中进行的。由于 Paimon 的存储采用 LSM(Log-Structured Merge-Tree)分层有序的数据结构,在进行 Compaction 时,能够轻松地将不同层的相同记录合并。
通过使用 Paimon 的 Partial-Update 功能,可以将之前双流 Join 的随机磁盘读操作转变为顺序磁盘读操作,从而消除之前的磁盘随机读。使用 Paimon Partial-Update 后,带来的收益如下:
首先,它完全消除了 Streaming Join 的磁盘随机读问题。其次,数据存储可以统一收敛到数据湖仓,这意味着不再需要外部的 HBase 或其他 KV 系统,从而节省了相关成本。在实际案例中,仅省去 HBase 的一部分存储,每月就能节省约五万元。
此外,系统的稳定性得到了提升,因为 Flink 的状态不再需要保存 TB 级别的数据。最后,作业逻辑得以简化。通过使用 Paimon,只需使用 SQL 就能完成任务,而不再需要像以前那样编写 Flink 的定制 Timer 逻辑进行优化。
2.3 应用场景 2:Streaming Upsert
第二个应用场景是 Paimon 的 Streaming Upsert 功能,主要应用于两个方面:首先是在流计算过程中产生的 Changelog 数据被写入 Paimon 表;其次是通过 CDC 技术将在线数据库的增量更新数据集成到 Paimon 表中。
在引入 Paimon 之前,传统的解决方案主要有两种:
- 保存原始 Changelog 数据:这种方法直接保存原始的 Changelog 数据,在查询时通过 View 按照主键和时间进行聚合,让用户查询到聚合后的表。优点是维护简便,数据直接以追加形式写入,维护时只需清理较旧的 Changelog 数据。然而,这种方法的可扩展性不足,对于更新频繁的场景,清理旧 Log 数据的频率较高。此外,每次查询时的聚合操作会引入较大的延迟。
- 离线批量数据导入:这是离线链路的方式,其缺点是数据新鲜度低,因为每次导入都需要全量数据。这样导致数据更新不及时,无法满足时效性要求。
在上述两种传统方式之外,还探索过使用 Iceberg Upsert 的方案。Flink 支持以 Upsert 的方式写入 Iceberg。在写入过程中,Iceberg 通过 Equality Delete 的 Position Delete 文件将更新操作与数据写入解耦,把数据合并和负载转移到读取和 Compaction 阶段。这种方式的优点是可以实现高效的数据摄入。
然而,这种方法也存在一些问题。首先,Equality Delete 目前缺乏排序和分层机制,导致读取时负载可能过大,并且需要频繁进行 Compaction 以消除 Delta Delete 文件。其次,每次写入操作可能需要写三个文件:Data File、Equality Delete 和 Position Delete 文件,这使得文件数量增加了三倍,带来了小文件问题。最后,Iceberg 对增量读取的支持不够友好,因为数据更新是以 Lazy 模式进行的,计算增量数据需要耗费大量精力,目前它不支持增量读取。
Paimon 通过其数据存储结构有效地解决了上述问题。Paimon 采用 LSM(Log-Structured Merge-Tree)存储架构,合并操作是通过两层之间的顺序合并来实现的,并且合并是分层进行的。这样,每次合并时无需重写所有历史文件,这与 Iceberg 的 Equality Delete 不同。Iceberg 的 Equality Delete 作用范围覆盖所有历史文件,因此每次可能都需要重写几乎所有的历史文件。
经过对比测试,通过使用两种数据表写入同一批数据进行 Upsert 测试,并使用 Compaction 任务保持两个表的 Delta Delete 文件不超过一定阈值,以测试空间放大的问题。测试结果显示,Paimon 的 Compaction 产生的空间放大远低于 Iceberg,具体数值大约是 16.1 比 6.7。
这种优势使得 Paimon 在数据更新和存储效率上具有显著的优越性,特别是在需要频繁更新和合并的场景中,Paimon 可以更有效地管理存储资源,减少不必要的文件重写和空间浪费。
Paimon 支持多种 Changelog Producer,适应不同的业务场景和需求。例如,在 Streaming Upsert 中,虽然很多计算场景下用户不需要消费精准的 Changelog,但如果有需求,Paimon 也能提供多种 Changelog 模式:
- INPUT 模式:适合写入 CDC 数据。
- LOOKUP 模式:适合数据量较小但对 Changelog 延迟要求较高的场景。
- FULL-COMPACTION 模式:适合数据量较大但延迟要求较高的场景,通常延迟在 10 到 20 分钟之间。
使用 Paimon 替换 Iceberg 的收益主要有以下几点:
- 降低 Compaction 的资源消耗:Paimon 的 LSM 结构在合并数据时更高效,减少了资源消耗。
- 减少写入的小文件:Paimon 不需要写两个额外的 Delete 文件,从而减少了小文件问题。
- 提升 Streaming read 体验:Paimon 的 LSM 结构非常适合增量读取的批处理场景,能够更高效地处理增量数据。
2.4 应用场景 3:维表 Lookup Join
在维表的 Lookup Join 场景中,传统链路中通常使用三种技术组件:HBase、Pegasus 和 Iceberg。我们在 Flink Iceberg connector 中扩展了 Lookup 接口,也可以实现 Lookup 表更新时增量加载功能。然而,之前的实现是将所有数据存放在内存中,这虽然成本低,但可扩展性很差。当数据量稍大时,内存资源就会不堪重负。
因此,当数据量增大时,通常需要将数据导入到 HBase 或 Pegasus 这样的 KV 存储系统中。HBase 和 Pegasus 作为专用的 KV 存储系统,具有很强的可扩展性。通过扩展存储服务的节点,可以提升 Join 的性能。但问题在于,这种方案的成本较高,对于一些业务而言,可能难以承受。
Paimon 支持作为 Lookup 的 source,支持将数据缓存在本地磁盘、按需从表存储中加载数据,还支持将数据缓存在 RocksDB 中。然而,它也有一些不足。
首先,本地磁盘性能仍然容易成为 Lookup 瓶颈。当数据存储在本地磁盘时,每次 Lookup 操作都会触发磁盘的随机读。这对于使用 HDD 磁盘的计算节点来说,Lookup Join 的性能容易受到限制,因为本地磁盘性能可能成为瓶颈。
此外,目前的实现模式要求每个节点都需要加载全量数据。这意味着,当数据更新时,尤其是在进行一次全面的 Compaction 之后,节点在启动时需要加载全部数据,导致启动时间过长,这显然不够高效。
在分析该问题时,我们发现之所以需要加载全量数据,是因为没有对流表进行合适的数据分区。通过对数据流采用与 Lookup 表相同的 Bucket 策略,可以有效避免在每个并发操作中加载全表数据的问题。优化后的系统能够自动进行分区,这样每个节点只需加载特定 Bucket 的数据,大幅减少了单个 Lookup 节点的数据加载量。
我们还发现本地磁盘性能容易成为 Lookup 瓶颈,因为 Lookup 操作大部分的读本质是高频次的磁盘随机读,磁盘 IO 很容易就成为性能的瓶颈,并且它很容易受到其他任务负载的影响,比如是有一些混部的集群,可能它和 HDFS 混布,如果 HDFS 的 Data Node 的数据任务就会占用很大的 IO 的比例,很容易影响 Flink Lookup 的性能,我们尝试把这部分磁盘数据存储到专用的远程的 SSD 上来进行优化,因为在我们的场景里面,通常网络 IO 不是瓶颈,磁盘反而是瓶颈,第二就是 SSD 的性能会比 HDD 要好太多,并且把磁盘的负载转移到远程的 SSD 上之后,本地的任务也不容易受节点上其他任务的影响。
使用 Paimon 进行 Lookup 操作后,可以替代部分原本通过 Join HBase 和 Pegasus KV 系统完成的任务。这带来了多方面的收益:
- 数据统一管理:可以将数据统一收敛到数据湖仓。在 Paimon 表中,可以使用 SQL 进行查询和写入,极大地方便了数据管理和操作。
- 简化数据链路:由于不再需要维护 KV 系统的部分,数据链路得以简化,减少了系统维护的复杂性,降低开发运维成本。
然而,Paimon 也存在一些不足之处:
- 性能与灵活性限制:Paimon 的性能和灵活性与专用的 KV 系统相比仍有很大差距,尤其在高更新频率的场景下表现不如 KV 系统。目前,Paimon 更适合用于更新频率很低的维表。
- 可扩展性依赖:Paimon 的可扩展性依赖于 Lookup 节点的水平扩展。与 KV 系统不同,KV 系统只需扩展其存储资源,而使用 Paimon Lookup 则需要扩展 Flink 的计算节点,甚至可能需要重新划分 Paimon 的 Bucket 并增加其数量。
三、未来展望
最后看一下未来的展望。
后续计划是继续深入挖掘 Paimon 在流计算场景中的应用,希望能将其推广到更多用户和使用案例中。目前已经有几个典型的应用场景,但仍希望能进一步拓宽其使用范围。
此外,计划建设自动化的维护服务。目前,Paimon 支持在作业内自动处理快照过期和 TTL 任务,这使得使用非常方便。然而,这些任务与数据更新任务之间存在耦合。为了解决这一问题,希望在平台侧实现自动化调度,从而减少任务间的耦合,提高效率。在此之前,已经为 Iceberg 构建了一套自动监控和维护治理服务,未来希望在这套治理服务中也能支持 Paimon。
同时,还计划提升 Paimon 的 Catalog 能力。Paimon 作为表,不仅支持 OLAP 或 SQL 的数据查询操作,还需要支持平台对其原数据的访问操作。借鉴 Iceberg 的做法,引入 REST Catalog 提供 REST API 的能力,希望 Paimon 也能建立类似的能力,以支持更广泛的应用场景。
更多内容
活动推荐
阿里云基于 Apache Flink 构建的企业级产品-实时计算 Flink 版现开启活动:
新用户复制点击下方链接或者扫描二维码即可0元免费试用 Flink + Paimon
实时计算 Flink 版(3000CU*小时,3 个月内)
了解活动详情:https://free.aliyun.com/?utm_content=g_1000395379&productCode=sc
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。