Apache Paimon 在同程旅行的实践进展

摘要:本文整理自同程旅行大数据计算组负责人吴祥平,在 Apache Paimon Meetup 的分享。本篇内容主要分为四个部分:

    1. Apache Paimon 引入

    2. Apache Paimon 应用建设

    3. Apache Paimon 优化实践

    4. 未来规划和期待

Tips:点击「阅读原文」免费领取 5000CU*小时 Flink 云资源

3 月底,在 Paimon 的公众号上发表了一篇文章,展示了 Paimon 在内部的调研和实践效果。三个月过去了,今天将通过更深入的实践和应用,与大家分享一下 Paimon 在内部的一些实践经验和大数据量场景下的优化细节。希望能够对正在调研和即将接入的一些伙伴有所帮助。

1787b35761c9a446607d554b37d4d5a7.jpeg

在开始之前,先简单介绍一下同程旅行大数据平台的建设历程。

2013 年我们开始建设了大数据平台,经历了多个阶段的引进。2014-2018 年主要基于 Hadoop 的大数据平台建设,然后基于 Hive 和 Spark 的数据仓库以及数据湖。2020 年开始引入 Hudi 构建了基于 Hudi 的数据湖,将大部分 ODS 层的表都迁移到了 Hudi 上。2022 年开始关注 Paimon,当时的名字是 Flink TableStore。

8a5369ac44b06397f8dde77227619cf4.jpeg

上图是目前的整体架构图。湖仓部分是 Hudi 和 Paimon 混用的阶段,加速层的 OLAP 主要使用 Starrocks。

01

Apache Paimon 引入

Apache Paimon 是一款支持高吞吐数据摄入、变更追踪、高效分析的数据库平台。底层存储利用了 LSM 的数据结构,支持高效的写入和查询的同时,能够支持多种分布式文件系统和计算引擎。

如果大家想了解跟多 Apache Paimon 的原理和细节,可以去看 Paimon 的官网,那里有非常详尽的文件操作流程和原理,在这里就不再赘述了。接下来主要和大家分享一下,我们在引入 Paimon 的一些考虑和背景。

0f04c961578c608ab830878055926a08.jpeg

首先是数据一致性。排查过数据湖,数据丢失的同学都知道这个过程非常痛苦。原因有很多,有可能是因为现场安全,或者是状态管理,又或者是数据写入的顺序问题。这些问题都有可能会导致数据丢失,而且非常难排查,这也是我们引入 Paimon 的一个重要原因。

在 Paimon 的实践过程中,我们几乎没有碰到任何一起数据丢失或者一致性的问题,我想这应该是得意于 Paimon 简单的湖仓抽象的设计,以及它良好的状态管理机制和严谨的测试用例,这些都保证了 Paimon 的数据一致性。

其次是生态。Paimon 的生态非常丰富,支持多种分布式文件系统和计算引擎。而且如果你去看 Paimon,它在各个引擎上集成的代码,你会发现大道至简,各个引擎的集成都非常自然,而且很容易让人理解,这对组建的维护者来说是非常重要的。而且 Paimon 的生态也在不断的扩展,包括 Doris、Starrocks 的集成。

最后是性能。Paimon 的性能非常优秀,这里我想和大家分享一下我们在 Paimon 性能测试中的一些结果。我们在全量+增量写入的场景中,相对 Hudi,Paimon 在相同计算资源的情况下,摄入的速度要优于 Hudi MOR 的摄入,大概有 3 倍左右的差距。这个差距主要是因为 Paimon 的写入是基于 LSM 的,而 Hudi MOR 是基于类 LSM,底层文件的无序会导致整个合并过程更加重量一点。

查询场景下会更明显,我们在同样数据量的情况下,Paimon 的查询速度要优于 Hudi,大概有 7 倍左右的差距,特别是点查。这个差距主要也是因为 Paimon 底层有序的数据组织,能够在查询的时候裁剪掉大部分的数据。而 Hudi 的查询是基于文件的,需要遍历整个文件,这个差距在数据量越大的情况下也会越明显。

2a4fa6c380146f055849afe846ce0016.jpeg

下面介绍一下内部 Paimon 的一些实践规模,我们主要实践的应用场景有以下三个:

  • 第一个,实时写入 ODS 层场景。目前有 114 家实时 Paimon 表,在运行中摄入 ODS 层的任务。最大单表日增量是 2000 万+,最大单表数据量是 90 亿+。所有的任务已经稳定运行了两个月以上,目前还在不断的迁移中。

  • 第二个,局部更新场景。众所周知,宽表在湖仓的构建中是非常常见的,Paimon 提供的局部更新能力能够很好的支持宽表的构建,目前我们有十多张宽表在 Paimon 上运行。随着 Paimon 做到真正局部更新之后,我们也会把更多的宽表场景迁移到 Paimon 中来,这个后面会进行详细的介绍。

  • 第三个,流读\增量读场景。这个场景主要是为了支持实时数仓的建设,目前我们主要有 20+的流毒场景在 Paimon 上运行。通过流读的方式极大地缩减了数据可见时间,提升了数据的实时性,同时也降低了底层数仓的压力。这个场景也是我们后续会大量迁移的场景之一。

ccab7dbaad8f163e49fab5022369b2cd.jpeg

场景的应用是需要结合收益的,实践下来我们发现,Paimon 在摄入计算资源层面相对 Hudi 减少了 30%左右,实时 ODS 层的存储减少了 40%。其次在写入和查询性能上,全量和增量在相同内存配置的情况下,摄入的性能提升了 3 倍左右,查询的性能提升了 7 倍。在各大企业都在降本增效的背景下,这些收益对我们来说是非常可观的。

02

Apache Paimon 应用建设

d520be4dba99300fada9fdd09d2c2a15.jpeg

区别于社区的 CDC 模式,我们对 CDC 的集成做了一层抽象。库和 Binlogo 之间有一层抽象层,Binlogo 解析中间件主要负责各个数据源的 Binlogo,包括 MySQL、PG、Mango,以及一些内部资源的 DB。这样做是为了将 Binlogo 进行服务化,解耦上层集成平台和 Binlogo 的抽象,更容易进行扩展,而且 API 保存不变。

那么 Binlogo 解析中间键之后是消息队列。我们采用基于增量 MQ 的一个 Binlogo 的消息队列。这样做是为了减少 Binlogo 在应用过程中的重复生产,让同一个队列可以让多个消费者去使用。但这套框架的缺点也比较明显,就是无法像社区 CDC 那样进行完备的结构引进或者整库同步,未来我们也会去强化这一点。

18538c292995bc0b246b94a67b879824.jpeg

有了基础抽象能力之后,我们希望终端用户不用太关心中间 Binlogo 采集的中间件以及队列的信息,只需要关注数据源表和它的目标表就可以了。让终端用户更加专注于业务,而不是关心技术细节。

我们将集成进行了抽象,将集成分为两个层面。第一个是用户层,用户可以选择他们熟悉的业务数据。第二个是对接层,可以自动对接我们的数据库团队、中间件团队、消息队列团队。通过这样的抽象,在底层组件替换的时候就会非常方便。当时 Paimon 上线的时候大概只花了 1-2 天的时间进行对接。

89d4e0f21209ec79a94da315559228b3.jpeg

下面介绍一下湖仓表的任务以及指标的管理。我们沿用了 Hudi 的一些指标,比如消费延迟、合并延迟、写入 writer 的数量,同时我们也制定了一些我们非常关心的指标,通过图表的方式全局的呈现这个指标进行全局的监控。

此外,社区也在不断的完善中,PIP-3 已经正式引入了 Paimon 的一些指标体系,相信未来能够在更多维度上,对 Paimon 表进行更加全面的监控,第一时间发现写入的问题。

03

Apache Paimon 优化实践

4654218ad9e55f83355b5dd1144ed5d8.jpeg

接下来分享一下我们在实践过程中,碰到的一些问题,主要是分为三个方面。首先是写入性能和稳定性,包括一些初始化和内存控制上的问题;其次是查询性能和稳定性上的问题;最后是局部更新以及字段注释的问题。

下面我将会结合我们的实践,分享一些和社区的解决方案给大家,希望能够帮助大家更好的使用 Paimon。

ccbd8b3151d4951d3c7450be47124d11.jpeg

第一个问题,Paimon 在写入任务的二次初始化慢。Paimon 在写入任务不依赖于 checkpoint 重启的时候,它需要从 Manifest 里面加载已有的分区、bucket 和 LSM 树 Level 信息,用于后面的续写。在实践过程中,随着 commit 数量的增加,Manifest 数量的上涨也非常明显。我们实践下来单分区加载最大要花费 18 秒左右。并发写分区越多的情况下,初始化加载比较慢的情况就会比较严重。

下面看下 Paimon 的元数据文件的组织结构。每个分区的元数据信息都存储在元数据目录下的 Manifest 文件里,每个 Manifest 里又存储了分区 bucket 信息、LSM 树信息以及 Level 信息。默认每一个 Manifest 的大小大约为 8M 左右,每个分区 Manifest 的数量会随着 commit 数量的增加而增加,同时元数据文件的数量也会增加,然后初始化的时间就会被拉长。

解决方案也很简单,主要有两个方向,第一个是分缓存,第二个是增加一些筛选。

d7096f27ca703e05620fa39fa4b1ad93.jpeg

分缓存是通过缓存减少与底层文件交互的次数,提升加载性能。同时在加载过程中,根据当前写入的分区和 Bucket 的信息裁剪掉不必要的 Manifest 文件,减少加载的实体数量,加快加载速度。

有兴趣的同学也可以参考一下上图中的两个链接,如果在实践过程中碰到类似的问题,可以尝试去配置'write-manifest-cache'这个参数,增加它的缓存,然后根据实际应用大小去调整它的大小。

我们实践下来,上千个分区并发写 200 多个分区情况下,配置 2 个 G 左右的 Manifest 缓存就够了。

另外,社区在 1199 这个 PR 里也对 Manifest 的合并进行了优化,理论上 Manifest 的文件会小很多。

最终我们应用了这两个优化项后,实际测试下来,单个分区的初始化时间由原来的 18 秒降低到了 50 毫秒左右,整个任务二次初始化的时间大大减少了。

f52d2ad10e73a9b3962a162b6f72cdc5.jpeg

第二个问题,commit 阶段的内存控制。这个和 Manifest 的加载也有一定的关系,因为单次 commit 的变更分区和桶数是不固定的,commit 阶段可能会加载非常多的 Manifest,就会导致内存的占用过高,甚至出现 OOM 的情况。

最终社区通过更改整个加载 Manifest 里的一个并发框架,将原来的 stream 模式改为了消费队列的模式,更加细粒度的控制 commit 阶段的内存使用。

8980ec6f5bada9177adba4360db38764.jpeg

如果大家在实践过程中,commit 阶段出现类似的问题,可以尝试去配置'scan.manifest.parallelism'这个参数,目前我们配置的是 15,相对来说比较保守,任务基本能稳定运行。大家在实践过程中也可以不断尝试,去找到一个比较合适的配置。

a94d8fae200f013c1f903a7002a4bf96.jpeg

第三个问题,流批 Split 大小控制。随着 Paimon 表数据量不断的增长,流批读 Paimon 的时候,他的 Split 下发阶段可能会触发 akka.framesize 的限制,导致任务报错。从上图可以看到,这个报错不是很明显,所以不能很快的去定位到它的根因。

ca103762feac85e3db70750abcbb240a.jpeg

大家如果在实践过程中碰到了这样的错误,可以尝试去调整'scan.split-enumerator.batch-size'这个参数,控制流读的时候下发 Split 的大小。

fa7d977fcd8d9b20c7651b89e881f805.jpeg

第四个问题,加速时间戳旅行读。在时间旅行过程中,比如我们读取某一个时间戳的数据量的时候会发现,初始化 Jobmanager 耗时非常久。经过分析主要是在根据时间戳定位 Snapshot 这个阶段,原来用的是遍历的模式,耗时基本上会在 10 分钟左右。后来我们改成了二分的模式,耗时从原来 10 分钟缩短到了 1 分钟不到,就能根据具体的时间戳定位到某一个快照信息,快速的将整个数据读取出来。

19ac8c073913ad5817025b53dcc4ae2c.jpeg

第五个问题,多表流读数据均衡问题。在多流读的时候,我们发现有一些 task 和 slot 没有被分配任务,也就是说它处于一个空闲的状态。内部我们增加了表名和分区的 Hash 条件,如上图。

241b78be14bf41fb774c48248c6c380e.jpeg

然后让流读的数据更加均衡的流入到各个算子中,提升了整个容器的利用率。近期我们也会把 pr 提交到社区里,大家可以关注一下。

422d42fd856b1c934e4418af8823b401.jpeg

第六个问题,局部更新。在实践过程中我们发现,局部更新在延时场景中可能会出现数据更新异常的情况。如上图所示,两条数据在经过 Merge 之后,比较字段变成了 4637 的值,但 4635 的延时更新就无法应用了。因为 4635 比 4637 要小,最终导致数据不一致。

这个问题的主要原因是数据来源有很多不同的字段,来源于不同的流,但是只有一个比较近的,是无法满足我们数据延时到达的场景的。

f2eaf11dcd6f9b69a56ded3412312824.jpeg

最后社区也引入了 sequence group 的概念,即将不同的字段对应到不同的比较字段里,实现独立比较,最终实现真正的更新能力。大家在实践局部更新的时候也可以采用这样的声明方式,去解决局部更新延时到达的问题。

86b665acbc3a3e7b1dd7b1e5e0debaac.jpeg

第七个问题,中文 Comment 乱码的问题。目前在 Flink 1.17.2 上已经有 Flink 的 pr 进行修复了,大家可以升级到 1.17.2 上去解决。

59d4c53f2cf317852b6ab0527f44bce0.jpeg

或者参考这个 pr,改到自己 Flink 源码里。我们内部因为是 1.17.0 的版本,所以主要是通过在 Comment 前增加一个 utf-8 这样的形式解决了这个乱码的问题。

16824c1d475b06c9edb84084e6428ddd.jpeg

最后总结一下整个实践过程,首先,Paimon 的读写性能是令人印象非常深刻的;其次,其非常简单的抽象设计,带来非常强的扩展性;最后也是最重要的一点,有一帮非常活跃的人,基本上有什么问题都能非常迅速的得到解决。

04

未来规划和期待

222b1e6a815a2d2025975a28fab813d4.jpeg

关于未来规划主要分为了以下三个方面。

  • 统一的管理。未来我们将会借鉴或者引入网易的 Arctic 能力,更好管理数据湖中的表,包括整个表的合并、监控等等。

  • 强化集成能力。因为我们的架构不能很好的应对结构演进或者总库同步,未来我们将会参考 CDC 的设计,通过 stream 的方式完成整个同步或者结构演进能力的补齐。

  • 扩大 Paimon 的应用范围。比如 Paimon 里类似于 Kafka Consumer group 的能力,取代有部分需要保留时间更长的 kafka 的场景。同时也会扩大局部更新的应用范围,以及正在设计中的 No bucket table 的能力,能够很好的去替代 Hive 场景。此外,还会跟进 AIGC 的能力,加上 Paimon 构建 Fabric 的能力,未来会有更多的应用场景。

Q&A

问:ODS 表接入数量达到 100+,200+以后,入湖任务的稳定性这块如何治理?

答:我们目前通过采集 Flink,消息队列以及自定义部分 Paimon 表指标,结合指标制定稳定性阈值,第一时间发现同步延迟,合并延迟或者资源问题,再根据实际情况进行调优。

问:如果某个超大表入湖效率比较慢,除了拆分超大表单独入湖的方式之外,请问还有方式加快 Paimon 入湖效率吗?

答:超大表的话可以考虑加大分桶数,或者使用最新的动态分桶,同时全量入湖阶段可以适当增加任务资源(内存和并行度),另外 Paimon 入湖时,也可以增大 checkpoint 的间隔,调大:write-buffer-size 在内存中缓存更多数据,同时开启 write-buffer-spillable;最后也可以考虑将 Compaction 独立,让入湖任务所有资源都用于数据摄入。

活动视频回顾 & PPT 获取


PC 端

建议前往 Apache Flink 学习网

https://flink-learning.org.cn/activity/detail/f7aeb46d723678642e1a96d780d78baa

移动端

视频回顾/PPT 下载:关注 Apache Flink 公众号/ Apache Paimon 公众号,回复 0615

往期精选

fe871d09ea6ee5920d816b8a361984cf.png

53fa25c5155abde48ab560b8e3d99588.png

5ac711fd6decd245fb55dd850a056c2e.png

78f1672403d5dac94848b4c23757bf0f.jpeg

2603dc266eec29bca7afe1fef4b91e45.png


▼ Apache Paimon Meetup 活动回顾」扫下方图片观看全场直播回放▼

19528595b8f7f6320a9ff406c01484ca.jpeg

▼ 关注「Apache Flink」,获取更多技术干货 ▼

c4e50ed812accd6f2340957316315507.png

 c679cf2f5e9ec0af6def7d3ad8a4ecd8.gif  点击「阅读原文」,免费领取 5000CU*小时 Flink 云资源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1383165.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Linux运维

目录 第一章、Linux概述 一、Linux的概念 二、Linux的特点 三、Linux VS Windows ​四、Linux的发展优势与存在问题-------不足 五、Linux常用发行版 六、CentOS简介 七、VMWare虚拟机简介 第二章、Linux初示 一、虚拟控制台 二 、Linux启动 (1&#xf…

Linux极客汇总常用运维大全

一、基础篇 1、Linux版本 内核版本 发行版本 RedHat Enterprise Linux-(公司级别,付费) Fedora(组建一个社区,免费) CentOS(基于红帽源代码编译的,免费) Debian(华丽界面&#xf…

Linux云服务器的使用,以及运行Python程序、相关Linux指令

目录 1、使用Linux云服务器的软件 1.1、MobaXterm_Personal 1.2、WindTerm 1.3、FileZilla FTP 2、Linux系统运行Python程序 3、Linux系统查看包、虚拟环境、安装包等 以下几个深度学习服务器都不错:智星云、AutoDL、恒源云 1、使用Linux云服务器的软件 1.1…

linux运维21

linux运维篇21 一、简述redis集群的实现原理二、基于redis5的redis cluster部署 一、简述redis集群的实现原理 工作原理:虽然redis有主从结构,但是无法解决只能单机写入数据的问题,无法实现分布式数据保存。而redis集群会预先分配16384个槽位…

linux运维15

linux运维篇15 一、实现基于MYSQL验证的vsftpd虚拟用户访问二、配置samba共享,实现/www目录共享三、使用rsyncinotify实现/www目录实时同步四、LVS调度算法总结五、LVS的跨网络DR实现 一、实现基于MYSQL验证的vsftpd虚拟用户访问 FTP服务器搭建: 数据库…

linux运维19

linux运维篇19 一、haproxy https实现二、总结tomcat的核心组件以及根目录结构三、tomcat实现多虚拟主机四、nginx实现后端tomcat的负载均衡调度五、简述memcached的工作原理 一、haproxy https实现 路由拓扑 后台web服务器搭建 LAMP架构看这个:LAMP yum install…

收集的 Linux VPS 在线重装系统脚本

因为 VPS 上预装的操作系统我并不习惯,所以打算重装一个。有的 VPS 服务商提供了较多种类的系统选择,有的却没有。如果你发现你希望重装的系统服务商没有提供,可以考虑自己安装。 本文内容 重装脚本 - 来自萌咖CentOS -> Debian 重装脚本 …

【运维】——服务器装Linux系统

一、用软碟通刻录系统光盘 1打开软碟通软件,打开文件-------选择Linux系统 2选择启动----写入硬盘映像 3开始写入硬盘映像,静等进度条走完即可。 二、开始安装Linux系统 1给主机插上刚刚刻录好的系统光盘,选择启动项 2设置信息:…

Linux入门---环境搭建(腾讯云服务器)、XShell远程登陆Linux

Linux环境搭建和远程登陆Linux Linux环境搭建XShell远程登陆Linux Linux环境搭建 主要有三种方式: 1.直接安装在物理机上,但是由于Linux桌面使用起来非常不友好,不推荐。 2.使用虚拟机软件,将Linux搭建在虚拟机上,但是…

Linux系统运维1 运维 项目研发 网站 服务器 计算机基础 Linux操作系统

运维的基本概念 运维行业前景 企业运作模式 四大部门 项目研发流程 职责描述&#xff1a; 运维的作用&#xff1a; 网站的相关概念 网站运行流程&#xff1a; IP<–>域名 重要概念&#xff1a; 服务器图片&#xff1a; 服务器&#xff1a;为用户提供服务的机器&…

linux运维14

linux运维篇14 一、简述CGI与FASTCGI区别二、 编译安装基于fastcgi模式的多虚拟主机的wordpress和discuz的LAMP架构三、通过loganalyzer展示数据库中的日志&#xff08;cgi模式&#xff09; 一、简述CGI与FASTCGI区别 CGI模式&#xff1a;当用户访问网站的动态资源时&#xff…

【从零开始学习JAVA | 第四十五篇】动态代理

目录 前言&#xff1a; 动态代理&#xff1a; 动态代理实现步骤&#xff1a; 动态代理的应用场景&#xff1a; 总结&#xff1a; 前言&#xff1a; 动态代理作为一种强大的编程技术&#xff0c;不仅为我们提供了灵活性和可扩展性&#xff0c;还为软件开发和系统设计带来了…

布隆过滤器在缓存系统中的实践

一. 背景 在业务开发中&#xff0c;在并发量很高的情况下&#xff0c;通常会使用缓存对系统查询性能进行优化&#xff0c;在缓存命中率很高的情况下&#xff0c;缓存的使用能够大幅提升系统查询性能。但是在缓存命中率非常低场景下&#xff0c;如果采用传统缓存读取模式&#…

Redisson_布隆过滤器

应用场景 去重 诞生背景 Java应用一般通过JDK自身提供的HashSet去重&#xff0c;通过contains()方法判断当前元素是否存在于Set中。该方式要求在调用contains()前&#xff0c;已经将数据列表加载到内存中&#xff08;即该方法基于内存存储实现判断功能&#xff09;。 缺点: 1.满…

【布隆过滤器】

我是&#x1f31f;廖志伟&#x1f31f;&#xff0c;一名&#x1f315;Java开发工程师&#x1f315;、&#x1f4dd;Java领域优质创作者&#x1f4dd;、&#x1f389;CSDN博客专家&#x1f389;、&#x1f339;幕后大佬社区创始人&#x1f339;。拥有多年一线研发经验&#xff0…

xmind用例数据上传至禅道

xmind格式参考&#xff0c;只需要在一级子主题填写对应用例模块ID&#xff0c;其余格式随意即可生成用例并直接上传到禅道&#xff1a; 代码里需填写禅道对应登录账号及用例所属产品 import requests import json import re import hashlib import pprint import threading fr…

认识相机

认识相机 在Threejs中相机的表示是THREE.Camera&#xff0c;它是相机的抽象基类&#xff0c;其子类有两种相机&#xff0c;分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。类图如下所示&#xff1a; 透视投影相机&#xff08;PerspectiveCam…

【项目实践】海康威视工业相机SDK开发小白版入门教程(VS2015+OpenCV4.5.1)

本文目录 前言怎么查找资料&#xff1f;数据手册例程 项目开发VS版本与OpenCV版本选择VS配置OpenCVVS添加MVS安装目录下的头文件和库VS项目开发 编程问题记录相机数据如何转换为OpenCV的Mat类型&#xff1f;函数不能修改全局指针变量&#xff1f;OpenCV运行报错“有未经处理的异…

Azure Kinect sdk 入门,简单使用深度相机

首先要安装azure Kinect dk传感器和人体跟踪的软件 先安装传感器&#xff1a;Azure-Kinect-Sensor-SDK/usage.md at develop microsoft/Azure-Kinect-Sensor-SDK GitHub 在这个网址里下载&#xff0c; 点击红笔画出来的地方&#xff0c;下载安装&#xff0c;记住安装路径&a…

入门级数码相机

为了满足不同层次顾客的购买要求&#xff0c;小编今天给大家交上一篇家用DC完全导购。从200万像素到800万像中间&#xff0c;分别选取了几款各级别中值得推荐的DC为大家推荐。在这里先给朋友们提一下目前数码相机市场相素与价位之间的简单联系。 目前&#xff0c;200万像素的数…