1. 摘要

在之前的一篇博客中,我们介绍了Clustering(聚簇)的表服务来重新组织数据来提供更好的查询性能,而不用降低摄取速度,并且我们已经知道如何部署同步Clustering,本篇博客中,我们将讨论近期社区做的一些改进以及如何通过HoodieClusteringJobDeltaStreamer工具来部署异步Clustering

2. 介绍

通常讲,Clustering根据可配置的策略创建一个计划,根据特定规则对符合条件的文件进行分组,然后执行该计划。Hudi支持并发写入,并在多个表服务之间提供快照隔离,从而允许写入程序在后台运行Clustering时继续摄取。有关Clustering的体系结构的更详细概述请查看上一篇博文。

3. Clustering策略

如前所述Clustering计划和执行取决于可插拔的配置策略。这些策略大致可分为三类:计划策略执行策略更新策略

3.1 计划策略

该策略在创建Clustering计划时发挥作用。它有助于决定应该对哪些文件组进行Clustering。让我们看一下Hudi提供的不同计划策略。请注意,使用此配置可以轻松地插拔这些策略。

  • SparkSizeBasedClusteringPlanStrategy:根据基本文件的小文件限制选择文件切片并创建Clustering组,最大大小为每个组允许的最大文件大小。可以使用此配置指定最大大小。此策略对于将中等大小的文件合并成大文件非常有用,以减少跨冷分区分布的大量文件。

  • SparkRecentDaysClusteringPlanStrategy:根据以前的N天分区创建一个计划,将这些分区中的小文件片进行Clustering,这是默认策略,当工作负载是可预测的并且数据是按时间划分时,它可能很有用。

  • SparkSelectedPartitionsClusteringPlanStrategy:如果只想对某个范围内的特定分区进行Clustering,那么无论这些分区是新分区还是旧分区,此策略都很有用,要使用此策略,还需要在下面设置两个配置(包括开始和结束分区):

    hoodie.clustering.plan.strategy.cluster.begin.partition
    hoodie.clustering.plan.strategy.cluster.end.partition

注意:所有策略都是分区感知的,后两种策略仍然受到第一种策略的大小限制的约束。

3.2 执行策略

在计划阶段构建Clustering组后,Hudi主要根据排序列和大小为每个组应用执行策略,可以使用此配置指定策略。

SparkSortAndSizeExecutionStrategy是默认策略。使用此配置进行Clustering时,用户可以指定数据排序列。除此之外我们还可以为Clustering产生的Parquet文件设置最大文件大小。该策略使用bulk_insert将数据写入新文件,在这种情况下,Hudi隐式使用一个分区器,该分区器根据指定列进行排序。通过这种策略改变数据布局,不仅提高了查询性能,而且自动平衡了重写开销。

现在该策略可以作为单个Spark作业或多个作业执行,具体取决于在计划阶段创建的Clustering组的数量。默认情况下Hudi将提交多个Spark作业并合并结果。如果要强制Hudi使用单Spark作业,请将执行策略类配置设置为SingleSparkJobExecutionStrategy

3.3 更新策略

目前只能为未接收任何并发更新的表/分区调度Clustering。默认情况下更新策略的配置设置为SparkRejectUpdateStrategy。如果某个文件组在Clustering期间有更新,则它将拒绝更新并引发异常。然而在某些用例中,更新是非常稀疏的,并且不涉及大多数文件组。简单拒绝更新的默认策略似乎不公平。在这种用例中用户可以将配置设置为SparkAllowUpdateStregy

我们讨论了关键策略配置,下面列出了与Clustering相关的所有其他配置。在此列表中一些非常有用的配置包括:

配置项 解释 默认值
hoodie.clustering.async.enabled 启用在表上的异步运行Clustering服务。 false
hoodie.clustering.async.max.commits 通过指定应触发多少次提交来控制异步Clustering的频率。 4
hoodie.clustering.preserve.commit.metadata 重写数据时保留现有的_hoodie_commit_time。这意味着用户可以在Clustering数据上运行增量查询,而不会产生任何副作用。 false

4. 异步Clustering

之前我们已经了解了用户如何设置同步Clustering。此外用户可以利用HoodiecClusteringJob设置两步异步Clustering

4.1 HoodieClusteringJob

随着Hudi版本0.9.0的发布,我们可以在同一步骤中调度和执行Clustering。我们只需要指定-mode-m选项。有如下三种模式:

  • schedule(调度):制定一个Clustering计划。这提供了一个可以在执行模式下传递的instant

  • execute(执行):在给定的instant执行Clustering计划,这意味着这里需要instant

  • scheduleAndExecute(调度并执行):首先制定Clustering计划并立即执行该计划。

请注意要在原始写入程序仍在运行时运行作业请启用多写入:

hoodie.write.concurrency.mode=optimistic_concurrency_control
hoodie.write.lock.provider=org.apache.hudi.client.transaction.lock.ZookeeperBasedLockProvider

使用spark submit命令提交HoodieClusteringJob示例如下:

spark-submit \
--class org.apache.hudi.utilities.HoodieClusteringJob \
/path/to/hudi-utilities-bundle/target/hudi-utilities-bundle_2.12-0.9.0-SNAPSHOT.jar \
--props /path/to/config/clusteringjob.properties \
--mode scheduleAndExecute \
--base-path /path/to/hudi_table/basePath \
--table-name hudi_table_schedule_clustering \
--spark-memory 1g

clusteringjob.properties配置文件示例如下

hoodie.clustering.async.enabled=true
hoodie.clustering.async.max.commits=4
hoodie.clustering.plan.strategy.target.file.max.bytes=1073741824
hoodie.clustering.plan.strategy.small.file.limit=629145600
hoodie.clustering.execution.strategy.class=org.apache.hudi.client.clustering.run.strategy.SparkSortAndSizeExecutionStrategy
hoodie.clustering.plan.strategy.sort.columns=column1,column2

4.2 HoodieDeltaStreamer

接着看下如何使用HudiDeltaStreamer。现在我们可以使用DeltaStreamer触发异步Clustering。只需将hoodie.clustering.async.enabledtrue,并在属性文件中指定其他Clustering配置,在启动Deltastreamer时可以将其位置设为-props(与HoodieClusteringJob配置类似)。

使用spark submit命令提交HoodieDeltaStreamer示例如下:

spark-submit \
--class org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer \
/path/to/hudi-utilities-bundle/target/hudi-utilities-bundle_2.12-0.9.0-SNAPSHOT.jar \
--props /path/to/config/clustering_kafka.properties \
--schemaprovider-class org.apache.hudi.utilities.schema.SchemaRegistryProvider \
--source-class org.apache.hudi.utilities.sources.AvroKafkaSource \
--source-ordering-field impresssiontime \
--table-type COPY_ON_WRITE \
--target-base-path /path/to/hudi_table/basePath \
--target-table impressions_cow_cluster \
--op INSERT \
--hoodie-conf hoodie.clustering.async.enabled=true \
--continuous

4.3 Spark Structured Streaming

我们还可以使用Spark结构化流启用异步Clustering,如下所示。

val commonOpts = Map(
"hoodie.insert.shuffle.parallelism" -> "4",
"hoodie.upsert.shuffle.parallelism" -> "4",
DataSourceWriteOptions.RECORDKEY_FIELD.key -> "_row_key",
DataSourceWriteOptions.PARTITIONPATH_FIELD.key -> "partition",
DataSourceWriteOptions.PRECOMBINE_FIELD.key -> "timestamp",
HoodieWriteConfig.TBL_NAME.key -> "hoodie_test"
) def getAsyncClusteringOpts(isAsyncClustering: String,
clusteringNumCommit: String,
executionStrategy: String):Map[String, String] = {
commonOpts + (DataSourceWriteOptions.ASYNC_CLUSTERING_ENABLE.key -> isAsyncClustering,
HoodieClusteringConfig.ASYNC_CLUSTERING_MAX_COMMITS.key -> clusteringNumCommit,
HoodieClusteringConfig.EXECUTION_STRATEGY_CLASS_NAME.key -> executionStrategy
)
} def initStreamingWriteFuture(hudiOptions: Map[String, String]): Future[Unit] = {
val streamingInput = // define the source of streaming
Future {
println("streaming starting")
streamingInput
.writeStream
.format("org.apache.hudi")
.options(hudiOptions)
.option("checkpointLocation", basePath + "/checkpoint")
.mode(Append)
.start()
.awaitTermination(10000)
println("streaming ends")
}
} def structuredStreamingWithClustering(): Unit = {
val df = //generate data frame
val hudiOptions = getClusteringOpts("true", "1", "org.apache.hudi.client.clustering.run.strategy.SparkSortAndSizeExecutionStrategy")
val f1 = initStreamingWriteFuture(hudiOptions)
Await.result(f1, Duration.Inf)
}

5. 总结和未来工作

在这篇文章中,我们讨论了不同的Clustering策略以及如何设置异步Clustering。未来的工作包括:

  • Clustering支持更新。

  • 支持Clustering的CLI工具。

另外Flink支持Clustering已经有相应Pull Request,有兴趣的小伙伴可以关注该PR。

可以查看JIRA了解更多关于此问题的开发,我们期待社会各界的贡献,希望你喜欢这个博客!

一文彻底掌握Apache Hudi异步Clustering部署的更多相关文章

  1. 深入理解Apache Hudi异步索引机制

    在我们之前的文章中,我们讨论了多模式索引的设计,这是一种用于Lakehouse架构的无服务器和高性能索引子系统,以提高查询和写入性能.在这篇博客中,我们讨论了构建如此强大的索引所需的机制,异步索引机制 ...

  2. Apache Hudi异步Compaction方式汇总

    本篇文章对执行异步Compaction的不同部署模型一探究竟. 1. Compaction 对于Merge-On-Read表,数据使用列式Parquet文件和行式Avro文件存储,更新被记录到增量文件 ...

  3. 一文彻底理解Apache Hudi的多版本清理服务

    Apache Hudi提供了MVCC并发模型,保证写入端和读取端之间快照级别隔离.在本篇博客中我们将介绍如何配置来管理多个文件版本,此外还将讨论用户可使用的清理机制,以了解如何维护所需数量的旧文件版本 ...

  4. 一文彻底掌握Apache Hudi的主键和分区配置

    1. 介绍 Hudi中的每个记录都由HoodieKey唯一标识,HoodieKey由记录键和记录所属的分区路径组成.基于此设计Hudi可以将更新和删除快速应用于指定记录.Hudi使用分区路径字段对数据 ...

  5. 基于 Apache Hudi 极致查询优化的探索实践

    摘要:本文主要介绍 Presto 如何更好的利用 Hudi 的数据布局.索引信息来加速点查性能. 本文分享自华为云社区<华为云基于 Apache Hudi 极致查询优化的探索实践!>,作者 ...

  6. 数据湖框架选型很纠结?一文了解Apache Hudi核心优势

    英文原文:https://hudi.apache.org/blog/hudi-indexing-mechanisms/ Apache Hudi使用索引来定位更删操作所在的文件组.对于Copy-On-W ...

  7. 官宣!ASF官方正式宣布Apache Hudi成为顶级项目

    马萨诸塞州韦克菲尔德(Wakefield,MA)- 2020年6月 - Apache软件基金会(ASF).350多个开源项目和全职开发人员.管理人员和孵化器宣布:Apache Hudi正式成为Apac ...

  8. 使用Apache Spark和Apache Hudi构建分析数据湖

    1. 引入 大多数现代数据湖都是基于某种分布式文件系统(DFS),如HDFS或基于云的存储,如AWS S3构建的.遵循的基本原则之一是文件的"一次写入多次读取"访问模型.这对于处理 ...

  9. 使用Apache Hudi构建大规模、事务性数据湖

    一个近期由Hudi PMC & Uber Senior Engineering Manager Nishith Agarwal分享的Talk 关于Nishith Agarwal更详细的介绍,主 ...

随机推荐

  1. C++进阶—>带你理解多字节编码与Unicode码

    参考网址:https://blog.csdn.net/u011028345/article/details/78516320 多字节字符与宽字节字符 char与wchar_t 我们知道C++基本数据类 ...

  2. C#多线程详解(二)

    在上一节介绍了线程的基础知识,下面来研究多线程的优先级 using System; using System.Threading;namespace Test{    class TestThread ...

  3. C# 启动 Flask for Python

    概览 最近有个需求是通过c#代码来启动 python 脚本.嘿~嘿!!! 突发奇想~~既然可以启动 python 脚本,那也能启动 flask,于是开始着手操作. 先看gif图 准备 因为使用的是.N ...

  4. mac下用clion进行sdl2游戏开发de环境搭建

    1. 故事背景 想从unity转unreal了,于是要使用c++进行开发.unreal引擎那么大,每次打开,我的小本都嗡嗡嗡的,想着不如用个轻量一些的引擎先开发吧,核心代码独立出来,到时候如果真要移植 ...

  5. Mysql 日期格式化 复杂日期区间查询

    前言 最近在做项目涉及到Mysql的复杂日期查询,日期查询其实在数据库中查询其实还是用的挺多的,比如查询开始日期到结束日期的区间信息,查询日期小于有效日期的信息,查询当天的日期,明天的日期,做比较等. ...

  6. Robot framework随机文件

    *** Variables *** @{Example} One Two Three *** Test Cases *** Example ${value}= Evaluate random.choi ...

  7. Metasploit用法详解

    Metasploit简介 1. Auxiliaries(辅助模块) 该模块不会直接在测试者和目标主机之间建立访问,它们只负责执行扫描.嗅探.指纹识别等相关功能以辅助渗透测试. 2. Exploit(漏 ...

  8. Java最大栈深度有多大?-从一道面试题开始学习JVM

    一.问题:Java最大支持栈深度有多大? 1.分析 有JVM的内存结构我们可知: 随着线程栈的大小越大,能够支持越多的方法调用,也即是能够存储更多的栈帧: 局部变量表内容越多,那么栈帧就越大,栈深度就 ...

  9. git02

    Git Gui的使用 Ssh key 介绍及使用 Ssh key介绍 我理解的就是每台电脑上会产生出一个ssh key,然后自己有一个远程账户,但是自己有可能有很多台电脑, 包括家里的电脑还有公司的电 ...

  10. 20210712考试-2021noip11

    这篇总结比我写的好多了建议直接去看 T1 简单的序列 考场:愣了一会,想到以最大值分治.每次枚举最大值两侧更小的区间,st表预处理前缀和和最大值,用桶统计答案. 注意分治时要去掉最大值. const ...