华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

背景

湖仓一体(LakeHouse)是一种新的开放式架构,它结合了数据湖和数据仓库的最佳元素,是当下大数据领域的重要发展方向。
华为云早在2020年就开始着手相关技术的预研,并落地在华为云 FusionInsight MRS智能数据湖解决方案中。

目前主流的三大数据湖组件 Apache Hudi、Iceberg、Delta各有优点,业界也在不断探索选择适合自己的方案。

华为湖仓一体架构核心基座是 Apache Hudi,所有入湖数据通过 Apache Hudi 承载, 对外通过 HetuEngine(Presto增强版)引擎承担一站式SQL分析角色,因此如何更好的结合 Presto 和 Hudi 使其查询效率接近专业的分布式数仓意义重大。查询性能优化是个很大的课题,包括索引、数据布局、预聚合、统计信息、引擎 Runtime优化等等。

本文主要介绍 Presto 如何更好的利用 Hudi 的数据布局、索引信息来加速点查性能。预聚合和统计信息我们将在后续分享。

数据布局优化

大数据分析的点查场景一般都会带有过滤条件,对于这种类型查询,如果目标结果集很小,理论上我们可以通过一定手段在读取表数据时大量跳过不相干数据,只读取很小的数据集,进而显著的提升查询效率。我们可以把上述技术称之为 DataSkipping
好的数据布局可以使相关数据更加紧凑(当然小文件问题也一并处理掉了)是实现 DataSkipping的关键一步。日常工作中合理设置分区字段、数据排序都属于数据布局优化。 当前主流的查询引擎 Presto/Spark 都可以对Parquet文件做 Rowgroup 级别过滤,最新版本甚至支持 Page 级别的过滤;选取合适的数据布局方式可以使引擎在读取上述文件可以利用列的统计信息轻易过滤掉大量 Rowgroup/Page,进而减少IO。
那么是不是 DataSkipping仅仅依赖数据布局就好了?其实不然。上述过滤还是要打开表里每一个文件才能完成过滤,因此过滤效果有限,数据布局优化配合 FileSkipping才能更好的发挥效果。
当我们完成数据布局后,对每个文件的相关列收集统计信息,下图给个简单的示例,数据经过排序后写入表中生成三个文件,指定点查 where a < 10
下图可以清楚的看出 a < 10的结果集只存在于 parquet1文件中, parquet2/parquet3 中 a 的最小值都比10大,显然不可能存在结果集,所以直接裁剪掉 parquet2parquet3即可。

File minValue_a maxValue_a parquet1 0 999 parquet2 1000 2000 parquet3 2001 3000

这就是一个简单 FileSkippingFileSkipping的目的在于尽最大可能裁剪掉不需要的文件,减少扫描IO,实现 FileSkipping有很多种方式,例如 min-max统计信息过滤、BloomFilter、Bitmap、二级索引等等,每种方式都各有优缺点,其中 min-max 统计信息过滤最为常见,也是 Hudi/Iceberg/DeltaLake 默认提供的实现方式。

Apache Hudi核心能力

1. Clustering

Hudi早在 0.7.0 版本就已经提供了 Clustering 优化数据布局,0.10.0 版本随着 Z-Order/Hilbert高阶聚类算法加入,Hudi的数据布局优化日趋强大,Hudi 当前提供以下三种不同的聚类方式,针对不同的点查场景,可以根据具体的过滤条件选择不同的策略

方式 使用场景 额外补充说明 Order 只有一个过滤列如: where a > 10

Clustering时只需按a排序即可 Order排序具有一定特殊性,当指定多列排序时,最终排序结果以第一列为准,其他列很难本有序。PS:主要这并不代表Order不能用于多列排序。以下场景可以直接用Order多列排序:1. 排序列都是低基字段;2. 只有一个高基字段,将该高基字段放到排序列最后 Z-Order 多个过滤字段,一般2到4个,超过4个效果要打折扣,Z-Order简单来说是一种均匀排序的思想,经过该算法参与排序的所有列都会基本有序,不会出现Order那种只排第一列的情况 多列排序效果绝大数情况下比Order要好,但是构建速度相比Order较慢。PS: 对于2列低基字段排序,选择Order比较合适 Hilbert 和Z-Order一样,不过排序效果更好,但构建速度更慢 同上

关于 Z-Order、Hilbert 具体原理可以查阅相关Wiki,https://en.wikipedia.org/wiki/Z-order 本文不再详细赘述。

Metadata Table(MDT):Hudi的元数据信息表,是一个自管理的 Hudi MoR表,位于 Hudi 表的 .hoodie目录,开启后用户无感知。同样的 Hudi 很早就支持 MDT,经过不断迭代 0.12版本 MDT 已经成熟,当前 MDT 表已经具备如下能力

Column_stats/Bloomfilter

上文我们介绍了数据布局优化,接下来说说 Hudi 提供的 FileSkipping能力。
当前 Hudi 支持对指定列收集包括min-max value,null count,total count 在内的统计信息,并且 Hudi 保证这些信息收集是原子性,利用这些统计信息结合查询引擎可以很好的完成 FileSkipping大幅度减少IO。
BloomFilter是 Hudi 提供的另一种能力,当前只支持对主键构建 BloomFilter。BloomFilter判断不存在就一定不存在的特性,可以很方便进行 FileSkipping,我们可以将查询条件直接作用到每个文件的 BloomFilter 上,进而过滤点无效的文件,注意 BloomFilter 只适合等值过滤条件例如 where a = 10,对于 a > 10这种就无能为力。

高性能FileList

在查询超大规模数据集时, FileList是不可避免的操作,在 HDFS 上该操作耗时还可以接受,一旦涉及到对象存储,大规模 FileList 效率极其低下,Hudi 引入 MDT 将文件信息直接保存在下来,从而避免了大规模 FileList

华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

Presto 与 Hudi的集成

HetuEngine(Presto)作为数据湖对外出口引擎,其查询 Hudi 能力至关重要。对接这块我们主要针对点查和复杂查询做了不同的优化,下文着重介绍点查场景。
在和 Hudi 集成之前首先要解决如下问题

  1. 如何集成 Hudi,在 Hive Connector 直接魔改,还是使用独立的 Hudi Connector?
  2. 支持哪些索引做 DataSkipping?
  3. DataSkipping 在 Coordinator 侧做还是在 Worker 端做?

问题1: 经过探讨我们决定使用 Hudi Connector承载本次优化。当前社区的 Connector 还略优不足,缺失一些优化包括统计信息、Runtime Filter、Filter不能下推等导致 TPC-DS 性能不是很理想,我们在本次优化中重点优化了这块,后续相关优化会推给社区。

问题2: 内部 HetuEngine 其实已经支持 Bitmap 和二级索引,本次重点集成了 MDT 的 Column statistics和 BloomFilter 能力,利用 Presto下推的 Filter 直接裁剪文件。

问题3: 关于这个问题我们做了测试,对于 column 统计信息来说,总体数据量并不大,1w 个文件统计信息大约几M,加载到 Coordinator 内存完全没有问题,因此选择在 Coordinator 侧直接做过滤。

华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

对于 BloomFilter、Bitmap 就完全不一样了,测试结果表明 1.4T 数据产生了 1G 多的 BloomFilter 索引,把这些索引加载到 Coordinator 显然不现实。我们知道 Hudi MDT 的 BloomFilter 实际是存在 HFile里,HFile点查十分高效,因此我们将 DataSkipping 下压到 Worker 端,每个 Task 点查 HFile 查出自己的 BloomFilter 信息做过滤。

华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

点查场景测试

测试数据

我们采用和 ClickHouse 一样的SSB数据集进行测试,数据规模1.5T,120亿条数据。

$ ./dbgen -s 2000 -T c
$ ./dbgen -s 2000 -T l
$ ./dbgen -s 2000 -T p
$ ./dbgen -s 2000 -T s

测试环境

1CN+3WN Container 170GB,136GB JVM heap, 95GB Max Query Memory,40vcore

数据处理

利用 Hudi 自带的 Hilbert 算法直接预处理数据后写入目标表,这里 Hilbert 算法指定 S_CITY,C_CITY,P_BRAND, LO_DISCOUNT作为排序列。

SpaceCurveSortingHelper
.orderDataFrameBySamplingValues(df.withColumn("year", expr("year((LO_ORDERDATE))")), LayoutOptimizationStrategy.HILBERT, Seq("S_CITY", "C_CITY", "P_BRAND", "LO_DISCOUNT"), 9000)
.registerTempTable("hilbert")
spark.sql("insert into lineorder_flat_parquet_hilbert select * from hilbert")

测试结果

使用冷启动方式,降低 Presto 缓存对性能的影响。

SSB Query

华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

文件读取量

华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践
  1. 对于所有 SQL 我们可以看到 2x – 11x 的性能提升, FileSkipping 效果更加明显过滤掉的文件有 2x – 200x 的提升。
  2. 即使没有 MDT ,Presto 强大的 Rowgroup 级别过滤,配合 Hilbert 数据布局优化也可以很好的提升查询性能。
  3. SSB模型扫描的列数据都比较少, 实际场景中如果扫描多个列 Presto + MDT+ Hilbert 的性能可以达到 30x 以上。
  4. 测试中同样发现了MDT的不足,120亿数据产生的MDT表有接近50M,加载到内存里面需要一定耗时,后续考虑给MDT配置缓存盘加快读取效率。

关于 BloomFilter 的测试,由于 Hudi 只支持对主键构建 BloomFilter,因此我们构造了 1000w 数据集做测试

spark.sql(
"""
    |create table prestoc(
    |c1 int,
    |c11 int,
    |c12 int,
    |c2 string,
    |c3 decimal(38, 10),
    |c4 timestamp,
    |c5 int,
    |c6 date,
    |c7 binary,
    |c8 int
    |) using hudi
    |tblproperties (
    |primaryKey = 'c1',
    |preCombineField = 'c11',
    |hoodie.upsert.shuffle.parallelism = 8,
    |hoodie.table.keygenerator.class = 'org.apache.hudi.keygen.SimpleKeyGenerator',
    |hoodie.metadata.enable = "true",
    |hoodie.metadata.index.column.stats.enable = "true",
    |hoodie.metadata.index.column.stats.file.group.count = "2",
    |hoodie.metadata.index.column.stats.column.list = 'c1,c2',
    |hoodie.metadata.index.bloom.filter.enable = "true",
    |hoodie.metadata.index.bloom.filter.column.list = 'c1',
    |hoodie.enable.data.skipping = "true",
    |hoodie.cleaner.policy.failed.writes = "LAZY",
    |hoodie.clean.automatic = "false",
    |hoodie.metadata.compact.max.delta.commits = "1"
    |)
    |
    |""".stripMargin)

最终一共产生了8个文件,结合 BloomFilter Skipping掉了 7 个,效果非常明显。

后续工作

后续关于点查这块工作会重点关注 Bitmap 以及二级索引。最后总结一下 DataSkipping 中各种优化技术手段的选择方式。

  1. Clustering中各种排序方式需要结合 Column statistics 才能达到更好的效果。
  2. BloomFilter 适合等值条件点查,不需要数据做排序, 但是要选择高基字段,低基字段 BloomFIlter 用处不大;另外超高基也不要选 BloomFilter,产出的 BloomFilter 结果太大。

Original: https://www.cnblogs.com/leesf456/p/16864900.html
Author: leesf
Title: 华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/799186/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 面试突击86:SpringBoot 事务不回滚?怎么解决?

    在 Spring Boot 中,造成事务不自动回滚的场景有很多,比如以下这些: 非 public 修饰的方法中的事务不自动回滚; 当 @Transactional 遇上 try/c…

    Python 2023年10月20日
    041
  • 有一点思考的2021年终总结!

    前言 2021阳历年即将过去,今年的我也将继续写下今年的年终总结!对过去的自己进行总结,对未来的自己给予展望! 今年事件 反抗996 年后第一天,老板在开会快结束的时候,说了我们需…

    Python 2023年6月3日
    081
  • Python教程:list.sort()和函数sorted(list)

    In [90]: x = [4, 6, 2, 1, 7, 9] In [91]: x.sort() In [92]: x Out[92]: [1, 2, 4, 6, 7, 9] I…

    Python 2023年8月28日
    034
  • 单元测试之pytest unittest

    1.需要安装pytest和pytest-html安装pytest: 在控制台输入 命令 pip install pytest 进行下载安装安装pytest-html:在控制台输入 …

    Python 2023年9月14日
    038
  • Python Matplotlib 子图

    目录 1、绘制多个子图 2、绘图在指定的子图上 3、subplots命令:快速生成多个子图框架 3.1 快速布局 3.2 画一个图形 3.3 多个图形共用一个轴 3.4 与seab…

    Python 2023年9月3日
    033
  • 线程锁在单例模式中的应用

    多个线程在执行过程中会因为竞争同一个资源而产生线程冲突,造成死锁,从而引出线程锁这个概念 先拿到锁再执行业务操作: 当然我对这一块了解的还不透彻,只是了解在不加锁的多线程情况下,会…

    Python 2023年10月30日
    027
  • pandas crosstab 输出结果在一行_Pandas 使用入门

    Pandas 使用入门 Pandas 数据基础 包含两种基本类型: 和. 是一个数据表格,而 可以看作是 的一列. 如何导入数据 方法一:通过词典导入 第一种导入的方法是把数据放在…

    Python 2023年8月8日
    065
  • ElasticSearch这些坑记得避开

    一、管理方式 二、结构维护 三、数据调度 1、同步方案 2、中断和恢复 四、刷新策略 五、深度分页 六、参考源码 Index用不好,麻烦事不会少; 一、管理方式 ElasticSe…

    Python 2023年10月16日
    026
  • Linux的前世今生

    啊哦~你想找的内容离你而去了哦 内容不存在,可能为如下原因导致: ① 内容还在审核中 ② 内容以前存在,但是由于不符合新 的规定而被删除 ③ 内容地址错误 ④ 作者删除了内容。 可…

    Python 2023年10月10日
    050
  • Python零基础入门的第一天——开发环境的搭建

    ​ 活动地址:CSDN21天学习挑战赛 ; 前言 2021年10月,语言流行指数的编译器 Tiobe将 Python加冕为 最受欢迎的编程语言,20年来首次将其置于 Java、 C…

    Python 2023年8月2日
    050
  • 编写运动控制器的 EtherCAT 初始化程序示例

    正运动控制器的EtherCAT 总线接口可用于连接 EtherCAT 伺服驱动器和 EtherCAT 扩展模块,无论连接什么模块, EtherCAT 总线都需要编写一段 Ether…

    Python 2023年10月28日
    059
  • pandas基础课程-实操(了解字段含义以及初步观察数据)

    1.4 知道你的数据叫什么 1.4.1 任务一:pandas中有两个数据类型DateFrame和Series,通过查找简单了解他们。然后自己写一个关于这两个数据类型的小例子🌰 im…

    Python 2023年8月22日
    038
  • 基础数据类型之集合

    1.集合的定义 在{}内用逗号分开多个元素,多个元素满足以下三个条件: 1.集合元素必须是不可变类型2.集合元素无序3.集合内元素没有重复(打印出来会自动去重) d = {} 默认…

    Python 2023年11月1日
    036
  • 房屋千千万,如何找到便宜实惠的呢,python采集数据并做数据可视化~

    Original: https://www.cnblogs.com/Qqun261823976/p/16417832.htmlAuthor: python倩Title: 房屋千千万…

    Python 2023年11月2日
    031
  • .NET Framework杂记

    这篇博客主要记录在用C#编写上位机时,不会的知识点,随时更新,方便查阅。 C#语法操作杂记 c#中让textbox选中不选中 C#无法使用实例引用来访问成员解决方法 * 针对不同定…

    Python 2023年10月24日
    036
  • py实现外星人入侵(二次开发)——2.添加音乐

    前言 这次的魔爪放在音乐部分,主要使用的是 pygame.mixer以及其中的music。我在背景音乐上添加了内容,并在发射子弹和子弹碰到外星人的时候播放音乐(噪音)。 话不多说,…

    Python 2023年9月21日
    035
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球