本文根据 StarRocks Summit 2023 演讲实录整理而成,演讲信息如下:
演讲人:王日宇 | StarRocks Committer,阿里云高级软件开发工程师
大家好,我是来自阿里云EMR团队的工程师,在团队里,主要负责 StarRocks 内核研发和产品推广工作。在社区方面,我的主要角色是作为一名 Committer,负责 DLA 方向的研发和社区指导工作。今天我为大家分享的主题是“基于 StarRocks 和 Paimon 打造湖仓分析新范式”。我的分享主要分为三部分,首先,我会介绍基于 StarRocks 和 Paimon 的湖仓分析方案,然后介绍一下这个方案背后的技术原理,最后介绍 StarRocks 和 Paimon 的湖仓分析的未来技术规划。
StarRocks 湖仓分析的发展历程
第一部分我会介绍一下 StarRocks 湖仓分析的发展历程。
这一部分分为两块内容,我会先分享一下湖的发展历程,然后再去介绍一下 StarRocks 对湖仓支持的发展过程。
先简单介绍下湖的发展历程。湖的发展,大家可能比较熟悉,就是经常被提到的数据湖的四剑客:Iceberg、Delta Lake 和 Hudi,以及 Apache Paimon 。他们都是一种新兴的数据湖格式。湖的技术发展方向,大致分为两类,第一类是湖格式的实现方案,简单来说就是“全量+增量”的分析构建。什么叫“全量+增量”呢?以 Iceberg、Delta Lake 和 Hudi 为例,它底层的数据格式都是开源的列存储格式,如 ORC 及 Parquet 等。它们为什么能做到实时更新、增量以及实时事务的处理呢?主要是通过引入了一些行存或者列存的 delta 文件记录更新数据,以 Iceberg 为例,它有 Position Delete File,也有 Equality Delete File ; 以 Hudi 为例,它叫 Delta log 文件。然后 Delta log 以这种行存的格式,先把新写入的数据先以行存的形式存起来,读取的时候,先读列存数据,再读行存增量数据,这两部分数据按照 key merge 起来,形成最终结果。
第二种湖格式的实现方案,比较主流的,比如说 Clickhouse,RocksDB 等。以我本次分享的主题 Paimon 为例,它是基于 LSM 来实现的。它的优点是相对于 Hudi 等,入库速度特别快,经过实际测试,它的速度是 Hudi 几倍以上。
综合来看,所有的湖格式实际上都为了解决这个三角形的问题。分别是新鲜度、成本和查询延时。如果要保证其中一块的性能,就需要适当的牺牲其他两个。以新鲜度为例,如果引入了 Hudi,它分为 MOR 表和 COW 表,如果你是为了提升新鲜度,引入 MOR 表,那你就会牺牲成本和查询延时成本。成本是怎么来的,就比如说会引入 delta log 文件,占用额外存储成本。查询延迟怎么来?就是因为他读的时候要做一些 merge 合并,他要把 Delta log 文件和 ORC 及 Parquet 文件的数据结合起来,从而最终能得到最新鲜的数据。
第二部分我将介绍 StarRocks 在湖格式支持上的发展历程。
第一部分就是湖仓的重大特性,另一部分就是 StarRocks 底层的持续优化。大家都知道 StarRocks,从开源到现在,已经步入了3.x版本。然后从1.x、2.x到3.x发展历程中, StarRocks 湖仓格式主要有以下重要里程碑。从刚开始开源,其实 StarRocks 已经支持 Hive 外表,然后常见的 Mysql 外表,StarRocks 外表都已经做了支持,底层性能,包括 CBO、向量化、Runtime Filter 等等。StarRocks 对湖格式的支持的重大的飞跃在2.x时代,StarRocks 引入了统一的 Catalog 数据目录,具体 Catalog 数据目录是做什么的呢?比如在 StarRocks 1.x 的时候,你想要读一个 Hive 外表,你是要针对每一个表都去执行 create external table,还需要指定表的 scheme,字段的类型,就像建普通内表一样,一个一个建。但在湖仓领域,它的库和表会非常多。如果一个一个建库表,人工的操作会特别多,而且容易出错。所以,2.x的时候,为了解决这个问题,我们就引入了 Catalog 数据目录这个特性,实现简单配置,创建 catalog 之后自动同步所有库表信息。这个也是我们阿里云 EMR 团队贡献给社区的重大特性之一。
在 Catalog 数据目录支持之后,我们还引入了 Iceberg、Delta Lake 和 Hudi 外表的支持,数据湖三剑客支持完成。随后我们引入了 JNI Connector,这个特性开始主要是为了做 Hudi MOR 外表的支持,后来逐渐泛化到通用场景,现在可以用 JNI Connector 接入所有用 JAVA 写的数据格式, 包括你自己的,比如说自己写的一个数据格式。如果是 Java 的 ,想接入 StarRocks,用 JNI Connector 就可以接过来。而不是说之前,需要用C++写一个 reader,会有些非常大的工作量。
然后第四个就是外表物化视图。外表物化视图是 StarRocks 和 Paimon 建设湖仓分析的一个基础。
第五个就是我们支持了复杂类型,比如说 Map/Struct/Json 等等。性能也一直在持续优化中,主要的优化有 IO 性能优化、延迟物化、Pipeline 执行引擎以及直方图统计信息等的支持。
现在 StarRocks 已经步入到3.0时代,Paimon 外表是从3.0时代开始支持的。也把之前的工作 JNI Connector 复杂类型做了支持,算子也可以做 spill,还有 Trino 的兼容性,以前想把 Trino 迁移到 StarRocks 的话,由于语法上的区别,迁移作业的 SQL 需要来回改,特别耗精力。现在直接执行 set sql_dialect=trino, 直接就可以使用 Trino 的语法,运行在 StarRocks 之上。同时3.0还支持了外表物化视图的分区刷新,然后 Hive、Iceberg 等现在可以直接使用 StarRocks 进行写入。在外表读取性能上,我们引入了 Data Cache、 JNI Connector 的性能优化等。
使用 StarRocks+Paimon 构建湖仓分析的介绍
可以看下这张架构图,以我们传统的数据数据仓库为例,经常会分为 ODS、DWD、DWS、ADS 等。我们最底层的数据存储引擎一般是传统的 HDFS 或者对象存储 OSS 或者 OSS-HDFS 等,数据湖格式可以使用 Paimon 来达到数据快速入湖的目的,上层可以使用 StarRocks 统一数据湖的 DLA 分析,以及湖仓的构建。我们构建湖仓,如何对湖仓分层呢,以 ODS 层为例,ODS 是最底层的原始数据,直接使用 StarRocks 外表就可以做 DLA 分析,然后再使用外表物化视图,然后通过这个外表物化视图去做一些清洗、聚合、分层、业务指标分类等这些工作。构建上层的 DWD、DWS 和 ADS。DWD 和 DWS 就是基于物化视图构建,因为物化视图本身是支持嵌套的,可以在物化视图之上再建物化视图。最后达到这个数仓分层的目的。当前 paimon 数据湖格式已经支持了物化视图,会在社区的3.2版本发布。
使用 StarRocks+Paimon 构建湖仓分析方案的关键技术原理介绍
第三部分我会介绍一下使用 StarRocks+Paimon 构建湖仓分析方案的一些关键技术原理。
首先,构建数据湖分析方案的关键原理就在于 JNI Connector。这个是我们阿里云EMR团队在去年的时候贡献给社区的一个重大特性。如刚才所说,Paimon 也是基于 Java 的,如果没有 JNI Connector 支持的话,我们需要写很多C++代码。其实就相当于把 Java Reader 的代码翻译成C++,然后套进 BE 里,然后运行起来,这样就会很hack。
比如说 Paimon 有了什么新特性,Reader 需要做出改变的时候,那我同样的C++代码也得改变。然后两个社区就不容易耦合在一起,太分散,在跟进Paimon的一些新特性的时候,Reader 可能会有一些滞后性,为了弥合这个差异,同时想直接使用Paimon社区 Java Reader 一些特性,我们就直接开发一套 JNI Connector 去适配Java 层, JNI Connector 主要的工作实际上就是屏蔽C++代码在读取java的时候一些技术细节。
它的使用也比较简单,比如说现在有一个新的 Java 的数据源,只需要套用这个 JNI Connector 框架使用Java实现三个方法:open,getNext 和 close,打出一个 Jar 包,放到 BE 的目录下,就可以直接使用 StarRocks 读取 Java 的数据源了。
Java 和 C++ 之间的内存转换,这些其实都是在 JNI Connector 里面做的。这里比如 Java 的memory,如何 copy 到 C++ 的 memory,然后不同的字段类型,比如说 int、long 、string 等怎么处理,JNI Connector 都会帮你做好。
现在 JNI Connector 已具有能力快速接入各类 Java 数据源以及提供简单易用的 Java 接口,社区当前基于 JNI Connector 已经实现了 Hudi MOR table 的支持和 Paimon table的支持,也支持了 Struct、Map、Array 等复杂类型。使用 JNI Connector 对 BE 的代码是零侵入的,用户不需要考虑 C++ 具体实现。
然后介绍一下不同字段如何在 Java 内存和C++内存的保存分布。
Spark有个项目是Spark photon,大家也都知道,开源 Spark 也是用 Java 写的,但是Databricks 内部是有做 native 算子优化的,然后这些 Java 和C++之间内存交互的事情,其实就是Spark photon那个项目做的。在实现 JNI Connector 的时候,我们参考了 Spark photon 那篇论文。把所有的数据分为两类,一类是定长字段,就比如说最简单的int,4个字节,这些都是定长字段类型。然后第二类就变长的,就比如String等。分为两类之后,对于定长的时候,定长的的字段在内存的存储相当于打平,就比如说一列数据有五行,四个字节四个字节的排着排在一起,存在内存里。这里主要是考虑每个类型的字段在BE中是怎么存的,比如说BE中存 int ,就是这样打平存的,保持内存布局一致的好处就是,在BE端可以直接调用memory copy,把JNI Connector排列好的一整段内存复制过去,然后给BE去读取。然后第二部分就是变长字段存储。变长字段存储跟定长字段存储就是多了 offset存储,因为它需要知道每个字段之间的边界在哪里。下一个 offset 减去上一个 offset 减一就等于这个字段的长度,然后把这个数据排列起来存起来。
这就是 JNI Connector 最核心的技术原理。
本质上就是根据字段类型对内存布局的构建和适配,所有的字段在内存里需要对齐 StarRocks BE 对应字段类型的个内存布局。因为涉及到内存间 copy,以及自定义布局,为了方便灵活控制,在 Java 侧都使用了堆外内存,没有使用 JVM 的堆内内存。
构建湖仓分析方案最关键技术原理就是物化视图。
我们经常会遇到一些业务场景,尤其湖仓领域,数据明有明显的冷热特性,数据量每天都在累积。但其实我们业务经常会读取读写更改的,也就是近几天的或者近几个月的数据。我们可以使用 StarRocks 物化视图的特性,在建物化视图的时候,指定 Partition TTL。通常情况下,物化视图就使用 Partition by进行分区 ,比如时间字段dt,这个字段会映射到外表的一个dt 字段,然后物化视图会自动的感知外表分区的更新,将更新的数据 load到物化视图内,最后加速查询。比如指定了这个TTL等于3 month的时候,每次物化视图刷新的时候,会把最新的三个月的数据 load 到 StarRocks 。
load到StarRocks之后,就可以使用Starrocks内表的优势,构建索引和统计信息,去加快整体的查询速度。尤其是外表经常存储在对象存储里的。对象存储经常会受到比如说网络的影响,导致IO性能不稳定。对于对于这些 load 到StarRocks的热数据,就可以实现稳定的加速查询。
StarRocks 物化视图支持自动改写。在Starrocks里,会根据dt的范围自动进行冷热改写。假如现在要查询进半年的数据,SQL里只需要指定查询6个月的范围就行,近三个月的我们会到物化视图内表里取查询。另外的三个月我们会从去比如说对象存储的外表里查询。然后我们会自动做一个Union功能,把最后的结果返回出来。这样你还是可以利用物化视图的加速功能对近三个月的数据进行加速,而且所有的SQL都是自动查询改写,你不需要知道StarRocks是从哪拉的数据,是从物化视图还是从真实的外表,这些对于用户都是透明的。
使用 StarRocks+Paimon 的未来技术规划
最后一部分我会介绍使用 StarRocks+Paimon 的未来技术规划。主要有以下六点,第一点就是支持 Append Only 表类型。现在 Paimon 其实有两种表类型,一种是 PK 表,一种是Append Only 表。Append Only 表也是在最新的版本中发布的。然后我们需要把这个类型去支持掉。为什么会有 Append Only 表类型?就是为了更适应写入活速度快这个特性,推出这个表的类型。
第二点,就是优化 date/datetime 类型的处理效率。这块主要是 JNI Connector 的工作。之前是通过string做了一个层转换,我们希望把这层转换去掉,然后提高这个效率。
第三点,物化视图支持Paimon的分区刷新,这个特性下周估计就可以合入社区了。目前paimon物化视图还是整表刷新。比如说表可能有100个分区,然后执行一次fresh,背后还是100个分区一起刷新。但通常冷数据及老的分区早就不会做任何更新了。然后所以我们希望支持分区刷新,只刷新了一些有变动的分区,减少刷新成本。
第四点,使用native reader加速查询。
第五点,支持列统计信息。
第六点,就是支持元数据缓存。现有的Paimon元数据查询每次都现拉一次,并没有缓存起来。有时候对于那些比较大的表,元数据本身也会比较大,FE analyze节点会比较上耗时。
第七点,就是支持time travel和snapshot。
第八点,就是支持Paimon外表的sink能力。就是直接用StarRocks写出到Paimon格式的表。
以上,就是我今天给大家分享的主要的内容。也欢迎大家钉钉扫码下方用户交流群,跟我们做更进一步的交流。谢谢大家。
———————————————————————————————————————————————
欢迎钉钉扫码加入EMR Serverless StarRocks交流群(搜索钉钉群号加群:24010016636)