paint-brush
采用 Hudi 和 MinIO 建设流数据统计湖 通过@minio
7,233 讀數
7,233 讀數

使用 Hudi 和 MinIO 开发流数据湖

MinIO14m2023/08/29
Read on Terminal Reader

太長; 讀書

Apache Hudi 是第一个数据湖开放表格式,在流式架构中值得考虑。使用 MinIO 进行 Hudi 存储为多云数据湖和分析铺平了道路。
featured image - 使用 Hudi 和 MinIO 开发流数据湖
MinIO HackerNoon profile picture
0-item
1-item
2-item
Apache Hudi 一个流统计资料湖app,可将主要仓库库房和统计资料库作用进行建立统计资料湖。 Hudi 未满足了于称自身为或等发展资料各式,它打造表、事情、更新系统读取/删除图片、高层指数、免疫印迹摄食提供服务、统计资料集群服务器/减少SEO优化和消息队列性。


Hudi 于 2016 年投放市场,紧紧根扎于 Hadoop 生态环保设计,其称呼后面的代表什么意思是:Hadoop Upserts and Incrementals。它是考虑到操作 HDFS 上个型介绍统计资料集的保存而设计规划的。 Hudi 的最主要的目的是减低流统计资料摄取量前几天的延缓。


胡迪表


随之时段的逝去,Hudi 现已壮大到安全使用和物体储存,包扩 MinIO。 Hudi 从 HDFS 的转移与天下的新趋势英文齐头并举,拋弃传统意义的 HDFS,转型稳定性高指标、可改善和云原本物体储存。 Hudi 诚若可以提供改善,使 Apache Spark、Flink、Presto、Trino 等的定量分析事情额定负载较快,这与 MinIO 大企业规模云原本程序流程图稳定性指标的诚若更加符合。


在生产中使用 Hudi 的公司包括 、 、 和 。这些是世界上最大的一些。在这个用例中,Hudi 的关键在于它提供了一个增量数据处理堆栈,可以对柱状数据进行低延迟处理。通常,系统使用 Apache Parquet 或 ORC 等开放文件格式一次性写出数据,并将其存储在高度可扩展的对象存储或分布式文件系统之上。 Hudi 充当数据平面来摄取、转换和管理这些数据。 Hudi 使用与存储进行交互,该 API 与从 HDFS 到对象存储再到内存文件系统的实现兼容(但不一定是最佳的)。

Hudi 文件格式

Hudi 运行总体文本下载和指标配电网见证文本下载来储存方式对给定总体文本下载的的更新/修该。框架文本下载能是 Parquet(列式)或 HFile(检索式)。指标配电网见证同步保存为 (行),毕竟在总体文本下载引发修该时见证这样的修该是刻意议的。


Hudi 将给定关键文书目录的全部改动编号为块字段。块能是数值块、删掉块或回滚块。一些块被合同时以有升级的理论知识文书目录。此编号还是会建立一家独立空间的系统日志。



Hudi 文件格式

Hudi表格式

表格中式由表的文档空间布局、表的组织架构相应监测表更变的元数据表格分为。 Hudi 强行下达刻录状态,这与对流传热补救的注意相一致,以确保安全管材不会受非向后兼容的更变而中止。


Hudi 将给定表/构思布局的资料分成小组在一并,并在统计键和资料组间展开投射。如上根据上述,其他更新系统软件都统计到某一资料组的增加工作日记资料中。这样构思比 Hive ACID 比较高效,Hive ACID 需求将其他信息统计与其他前提资料合拼就能治理 在线查询。 Hudi 的构思预想基本概念键的加快更新系统软件复制和卸载,如果它适用人群于资料组的增加工作日记,而并非一个信息集。


Hudi 将给定表/系统盘的zip档案排序在走到最后,并在计录键和zip档案组当中进行开映射。如上所讲,其它提升软件都计录到某些zip档案组的增长量配电网笔记zip档案中。这般开发比 Hive ACID 更高一些效,Hive ACID 不得不将其它统计资料表格计录与其它根本zip档案伴有功能操作查到。 Hudi 的开发预期目标研究背景键的迅猛提升软件添加和去除,如果它使适用zip档案组的增长量配电网笔记,而不算这个统计资料表格集。


Hudi表格式


时间线对于理解至关重要,因为它是所有 Hudi 表元数据的真实事件日志来源。时间线存储在.hoodie文件夹中,或者在我们的例子中存储在存储桶中。事件会保留在时间线上,直到被删除。时间线适用于整个表以及文件组,从而可以通过将增量日志应用到原始基础文件来重建文件组。为了优化频繁写入/提交,Hudi 的设计使元数据相对于整个表的大小较小。


事件处理线上直播的新事件处理被保护到室内元动态数值表格腕表,并且做好为一类型读时伴有表完成,最后身为低输入增加。所以,Hudi 需要迅速的吸收率元动态数值表格的迅速的发展。还有,元动态数值表格表操作 HFile 核心程序夹程序类型,经过一队字段键快速搜索进每一步SEO优化性能参数,防范导出整体的元动态数值表格表。身为表一本分的那些物理防御程序夹线路都带有在元动态数值表格中,以防范最贵且时长的云程序夹所有。

胡迪作家

Hudi 调用器推进了如此一来的架构部署:Hudi 取代高功能输入层,还具有 ACID 业务认可,可进行十分加快的指标改成,列举刷新和误删。


典型的 Hudi 架构依赖于 Spark 或 Flink 管道将数据传输到 Hudi 表。 Hudi 写入路径经过优化,比简单地将 Parquet 或 Avro 文件写入磁盘更有效。 Hudi 分析写入操作并将其分类为增量操作( insertupsertdelete )或批量操作( insert_overwriteinsert_overwrite_tabledelete_partitionbulk_insert ),然后应用必要的。


Hudi 编排者还担任维护保养元统计资料源。而对于一条收录,一般会读取统计资料撤回耗时和该收录唯一性的编码密钥(这像于 Kafka 摆动量),故而可不也也就能够导进收录级別的改成。玩家还可不也也就能够在进入统计资料源流大拇指定行为真相耗时信息类型,并使用的元统计资料源和 Hudi 耗时线追踪定位我们。这可不也也就能够相关调整流治疗,根据 Hudi 其中包含不同收录的走到耗时和行为真相耗时,故而可不也也就能够为繁琐的流治疗管打造雄厚的。

胡迪读者

输入器和载入器两者之间的网页浏览隔离防晒禁止从大部分关键数值湖查询网站系统领头羊(包涵 Spark、Hive、Flink、Prest、Trino 和 Impala)高度地查询网站系统表网页浏览。与 Parquet 和 Avro 一个,Hudi 表能被和等载入为间接表。


Hudi 阅续器被激发为轻频度。仅仅有将,就可能用到的目标于搜索引擎的矢量图化载入器和缓存,举例说明 Presto 和 Spark 中的那种。当 Hudi 须得并入查看个人的几乎相关资料和工作日志相关资料时,Hudi 用到的可冒泡溢出镜像和时间延迟载入等制度化来提升 并入功能,还还给予载入优化系统的查看个人。


Hudi 收录好几种非常的厉害的指标查到技能。元数剧分析是其价值体系,它兼容将新型出具身为较小的块动用,并全部解耦数剧分析的读取动态数据统计和指标查到。能够合理动用元数剧分析,時间出游只 另外一只个具备有的定义的终站和终站的指标查到。 Hudi 在任意给定時间点以共价键方法将键地址映射到单一程序组,兼容 Hudi 表上的完整详细 CDC 技能。尽管顶端 Hudi writers 区域所专题讨论的,各个表都由程序组构成,各个程序组都存在个人收录的元数剧分析。

胡迪万岁!

Hudi 的最大优势在于它摄取流数据和批量数据的速度。通过提供upsert功能,Hudi 执行任务的速度比重写整个表或分区快几个数量级。


为了能让用 Hudi 的摄食快慢,信息湖屋应该存在高 IOPS 和运输量的贮存层。 MinIO 的可扩容性和高能的结合实际又是 Hudi 所应该的。 MinIO 可以就能需要满足为实时公交机构信息湖保证苹果支持的需求要的的能 — 在 GET 上变现了 325 GiB/s (349 GB/s),在 PUT 上变现了 165 GiB/s (177 GB/s)。 32 个顶点的现做 NVMe SSD。


频繁的中小款企业 Hudi 数值湖资料存储不少小款 Parquet 和 Avro 资料。 MinIO 包涵大多,可做到快点的数值湖。小群体与元数值内联存储,降低了读写 Hudi 元数值和字段等小资料想要的 IOPS。


模式是每个 Hudi 表的重要组成部分。 Hudi 可以强制执行模式,也可以允许模式演变,以便流数据管道可以在不中断的情况下进行调整。此外,Hudi 强制执行 schema-on-writer 以确保更改不会破坏管道。 Hudi 依赖 Avro 来存储、管理和发展表的架构。


Hudi 为数据湖提供ACID 事务保证。 Hudi 确保原子写入:提交以原子方式提交到时间线,并给出一个时间戳,该时间戳表示操作被视为发生的时间。 Hudi 将写入器、表和读取器进程之间的快照隔离开来,以便每个进程都对表的一致快照进行操作。 Hudi 通过写入器之间的乐观并发控制 (OCC) 以及表服务和写入器之间以及多个表服务之间的基于非阻塞 MVCC 的并发控制来解决此问题。

Hudi 和 MinIO 教程

本方法步骤将诱导您提交 Spark、Hudi 和 MinIO 的设计,并的介绍部分最基本的 Hudi 模块。本方法步骤应主要用于,主要用于于云安卓原生系统 MinIO 物体贮存。


请需要注意,施用最新版本化文件存储桶会添加 Hudi 的某些保护开销。所以删掉除的群体都要开启这个。当 Hudi 施用删去箭头的量会不断地精力的增多而添加。对的标准配置以清除这样的删去箭头更加重要的,这是因为假若删去箭头的量实现 1000,列表框运作将会会堵赛。Hudi 建设项目保护人群意见与建议在施用生命安全的周期条件那天后清除删去箭头。

先决条件

Apache Spark。


MinIO。记录表掌控台的 IP 网址、TCP 服务器端口、访问权限秘钥和神秘秘钥。


MinIO 客服端。


在线下载 AWS 和 AWS Hadoop 库并将它是生成到您的类路径名中,以便运用 S3A 来处理另一半贮存。
  • AWS: aws-java-sdk:1.10.34 (或更高版本)

  • Hadoop: hadoop-aws:2.7.3 (或更高版本)


Jar 文件,解压缩并将其复制到/opt/spark/jars

创建 MinIO 桶

利用 MinIO 加盟商端創建一款 存贮桶来是储存 Hudi 数据分析:
 mc alias set myminio //<your-MinIO-IP:port> <your-MinIO-access-key> <your-MinIO-secret-key> mc mb myminio/hudi

使用 Hudi 启动 Spark

启动时 Spark shell,并将 Hudi 性能为采用 MinIO 来进行随意调节。切实保障采用 MinIO 设置成性能 S3A 搜索结果。


 spark-shell \ --packages org.apache.hudi:hudi-spark3.3-bundle_2.12:0.12.0,org.apache.hadoop:hadoop-aws:3.3.4 \ --conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer' \ --conf 'spark.sql.catalog.spark_catalog=org.apache.spark.sql.hudi.catalog.HoodieCatalog' \ --conf 'spark.sql.extensions=org.apache.spark.sql.hudi.HoodieSparkSessionExtension' \ --conf 'spark.hadoop.fs.s3a.access.key=<your-MinIO-access-key>' \ --conf 'spark.hadoop.fs.s3a.secret.key=<your-MinIO-secret-key>'\ --conf 'spark.hadoop.fs.s3a.endpoint=<your-MinIO-IP>:9000' \ --conf 'spark.hadoop.fs.s3a.path.style.access=true' \ --conf 'fs.s3a.signing-algorithm=S3SignerType'


那么,在 Spark 中原始化 Hudi。
 import org.apache.hudi.QuickstartUtils._ import scala.collection.JavaConversions._ import org.apache.spark.sql.SaveMode._ import org.apache.hudi.DataSourceReadOptions._ import org.apache.hudi.DataSourceWriteOptions._ import org.apache.hudi.config.HoodieWriteConfig._ import org.apache.hudi.common.model.HoodieRecord


请准备,它将抽象化 Hudi 的重叠选择来组建。

创建一个表

选择一段时间并利用 Scala 创造一两个轻松的中大型 Hudi 表。 Hudi DataGenerator 有的是种体系结构合成范本读取和更新软件的迅速且轻松的方式。


 val tableName = "hudi_trips_cow" val basePath = "s3a://hudi/hudi_trips_cow" val dataGen = new DataGenerator

向Hudi插入数据并将表写入MinIO

下面将生成新的行程数据,将它们加载到 DataFrame 中,并将我们刚刚创建的 DataFrame 作为 Hudi 表写入 MinIO。如果表已存在, mode(Overwrite)将覆盖并重新创建该表。行程数据依赖于记录键 ( uuid )、分区字段 ( region/country/city ) 和逻辑 ( ts ) 以确保每个分区的行程记录是唯一的。我们将使用默认的写入操作upsert 。当您的工作负载没有更新时,您可以使用insertbulk_insert ,这可能会更快。


 val inserts = convertToStringList(dataGen.generateInserts(10)) val df = spark.read.json(spark.sparkContext.parallelize(inserts, 2)) df.write.format("hudi"). options(getQuickstartWriteConfigs). option(PRECOMBINE_FIELD_OPT_KEY, "ts"). option(RECORDKEY_FIELD_OPT_KEY, "uuid"). option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath"). option(TABLE_NAME, tableName). mode(Overwrite). save(basePath)


打开浏览器并使用您的访问密钥和秘密密钥通过//<your-MinIO-IP>:<port>登录 MinIO。您将在存储桶中看到 Hudi 表。


MinIO 控制台


该存储桶还包含包含元数据的.hoodie路径以及包含数据的americasasia路径。


元数据


查看元数据。这就是完成整个教程后我的.hoodie路径的样子。我们可以看到我在2022年9月13日星期二的9:02、10:37、10:48、10:52和10:56修改了表格。


完成教程后的 .hoodie 路径

查询数据

令我们大家将 Hudi 数据资料初始化到 DataFrame 中并运转举例查询系统。
 // spark-shell val tripsSnapshotDF = spark. read. format("hudi"). load(basePath) tripsSnapshotDF.createOrReplaceTempView("hudi_trips_snapshot") spark.sql("select fare, begin_lon, begin_lat, ts from hudi_trips_snapshot where fare > 20.0").show() spark.sql("select _hoodie_commit_time, _hoodie_record_key, _hoodie_partition_path, rider, driver, fare from hudi_trips_snapshot").show()

与胡迪一起穿越时空

不,我们大家不算在讨论 1988 年一起看音乐歌曲会。


两遍读入 Hudi 表都要创立新的百度网页快照。将百度网页快照视作适用于时期行程查找的表的版本。


去尝试一个的时间段穷游检查(您务必改动的时间段戳才可与您相关内容)。


 spark.read. format("hudi"). option("as.of.instant", "2022-09-13 09:02:08.200"). load(basePath)

更新数据

这历程与我国以往放入新参数时相近。成了分享 Hudi 内容的更新参数的技能,我国将导出对现存旅行路线记录好的内容的更新,将鸟卵数据加载到 DataFrame 中,以后将 DataFrame 读取数据已储存在 MinIO 中的 Hudi 列表中。


请注意,我们使用的是append保存模式。一般准则是使用append模式,除非您要创建新表,这样不会覆盖任何记录。使用 Hudi 的典型方法是实时摄取流数据,将它们附加到表中,然后编写一些逻辑,根据刚刚附加的内容合并和更新现有记录。或者,使用overwrite模式写入会删除并重新创建该表(如果该表已存在)。


 // spark-shell val updates = convertToStringList(dataGen.generateUpdates(10)) val df = spark.read.json(spark.sparkContext.parallelize(updates, 2)) df.write.format("hudi"). options(getQuickstartWriteConfigs). option(PRECOMBINE_FIELD_OPT_KEY, "ts"). option(RECORDKEY_FIELD_OPT_KEY, "uuid"). option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath"). option(TABLE_NAME, tableName). mode(Append). save(basePath)


咨询的数据会呈现内容更新的里程纪录。

增量查询

Hudi 能够 便用指标看出示自给随机间戳来说改成的日志流。当我门要做的说是出示一名起時间,从该時间起流式细胞术传送数据改成,以看现在去提交事先的改成,然后当我门能够 便用终结時间来束缚流。


增长量搜索对于那些 Hudi 比喻无比首要,为了它可以您在大批量数据源上创设流式的线路。


 // spark-shell // reload data spark. read. format("hudi"). load(basePath). createOrReplaceTempView("hudi_trips_snapshot") val commits = spark.sql("select distinct(_hoodie_commit_time) as commitTime from hudi_trips_snapshot order by commitTime").map(k => k.getString(0)).take(50) val beginTime = commits(commits.length - 2) // commit time we are interested in // incrementally query data val tripsIncrementalDF = spark.read.format("hudi"). option(QUERY_TYPE_OPT_KEY, QUERY_TYPE_INCREMENTAL_OPT_VAL). option(BEGIN_INSTANTTIME_OPT_KEY, beginTime). load(basePath) tripsIncrementalDF.createOrReplaceTempView("hudi_trips_incremental") spark.sql("select `_hoodie_commit_time`, fare, begin_lon, begin_lat, ts from hudi_trips_incremental where fare > 20.0").show()

时间点查询

Hudi也可以查询网站公布对应時间和起止日期的数据信息。


 // spark-shell val beginTime = "000" // Represents all commits > this time. val endTime = commits(commits.length - 2) // commit time we are interested in //incrementally query data val tripsPointInTimeDF = spark.read.format("hudi"). option(QUERY_TYPE_OPT_KEY, QUERY_TYPE_INCREMENTAL_OPT_VAL). option(BEGIN_INSTANTTIME_OPT_KEY, beginTime). option(END_INSTANTTIME_OPT_KEY, endTime). load(basePath) tripsPointInTimeDF.createOrReplaceTempView("hudi_trips_point_in_time") spark.sql("select `_hoodie_commit_time`, fare, begin_lon, begin_lat, ts from hudi_trips_point_in_time where fare > 20.0").show()

使用软删除删除数据

Hudi 扶持五种区别的误删纪要的策略。软误删调取纪要键并清掉各个其他数据源类型的值。软误删会经久耐用同步保存在 MinIO 中,还必须便用硬误删从数据源湖内误删。


 // spark-shell spark. read. format("hudi"). load(basePath). createOrReplaceTempView("hudi_trips_snapshot") // fetch total records count spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count() spark.sql("select uuid, partitionpath from hudi_trips_snapshot where rider is not null").count() // fetch two records for soft deletes val softDeleteDs = spark.sql("select * from hudi_trips_snapshot").limit(2) // prepare the soft deletes by ensuring the appropriate fields are nullified val nullifyColumns = softDeleteDs.schema.fields. map(field => (field.name, field.dataType.typeName)). filter(pair => (!HoodieRecord.HOODIE_META_COLUMNS.contains(pair._1) && !Array("ts", "uuid", "partitionpath").contains(pair._1))) val softDeleteDf = nullifyColumns. foldLeft(softDeleteDs.drop(HoodieRecord.HOODIE_META_COLUMNS: _*))( (ds, col) => ds.withColumn(col._1, lit(null).cast(col._2))) // simply upsert the table after setting these fields to null softDeleteDf.write.format("hudi"). options(getQuickstartWriteConfigs). option(OPERATION_OPT_KEY, "upsert"). option(PRECOMBINE_FIELD_OPT_KEY, "ts"). option(RECORDKEY_FIELD_OPT_KEY, "uuid"). option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath"). option(TABLE_NAME, tableName). mode(Append). save(basePath) // reload data spark. read. format("hudi"). load(basePath). createOrReplaceTempView("hudi_trips_snapshot") // This should return the same total count as before spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count() // This should return (total - 2) count as two records are updated with nulls spark.sql("select uuid, partitionpath from hudi_trips_snapshot where rider is not null").count()

使用硬删除删除数据

不同之处之端,硬删去只是 企业所言的删去。记录好键和同步数据类型将从表里删去。


 // spark-shell // fetch total records count spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count() // fetch two records to be deleted val ds = spark.sql("select uuid, partitionpath from hudi_trips_snapshot").limit(2) // issue deletes val deletes = dataGen.generateDeletes(ds.collectAsList()) val hardDeleteDf = spark.read.json(spark.sparkContext.parallelize(deletes, 2)) hardDeleteDf.write.format("hudi"). options(getQuickstartWriteConfigs). option(OPERATION_OPT_KEY,"delete"). option(PRECOMBINE_FIELD_OPT_KEY, "ts"). option(RECORDKEY_FIELD_OPT_KEY, "uuid"). option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath"). option(TABLE_NAME, tableName). mode(Append). save(basePath) // run the same read query as above. val roAfterDeleteViewDF = spark. read. format("hudi"). load(basePath) roAfterDeleteViewDF.registerTempTable("hudi_trips_snapshot") // fetch should return (total - 2) records spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count()

插入覆盖

当数据湖获得更新现有数据的能力时,它就成为数据湖屋。我们将生成一些新的行程数据,然后覆盖现有数据。此操作比upsert更快,其中 Hudi 会立即为您计算整个目标分区。在这里,我们指定配置,以便绕过upsert为您执行的自动索引、预组合和重新分区。


 // spark-shell spark. read.format("hudi"). load(basePath). select("uuid","partitionpath"). sort("partitionpath","uuid"). show(100, false) val inserts = convertToStringList(dataGen.generateInserts(10)) val df = spark. read.json(spark.sparkContext.parallelize(inserts, 2)). filter("partitionpath = 'americas/united_states/san_francisco'") df.write.format("hudi"). options(getQuickstartWriteConfigs). option(OPERATION.key(),"insert_overwrite"). option(PRECOMBINE_FIELD.key(), "ts"). option(RECORDKEY_FIELD.key(), "uuid"). option(PARTITIONPATH_FIELD.key(), "partitionpath"). option(TBL_NAME.key(), tableName). mode(Append). save(basePath) // Should have different keys now for San Francisco alone, from query before. spark. read.format("hudi"). load(basePath). select("uuid","partitionpath"). sort("partitionpath","uuid"). show(100, false)

演进表架构和分区

网络架构模式发展准许您就要变更 Hudi 表的网络架构模式以认知数据统计直接间引发的的变化。


左右是该怎样在线查询和发易拉宝展网络架构和分区域的许多范例。越深入的探讨,请参阅。请需要注意,假如您行驶等操作命令,同旁内角将修该您的 Hudi 表网络架构以与本步凑的不同。


 -- Alter table name ALTER TABLE oldTableName RENAME TO newTableName -- Alter table add columns ALTER TABLE tableIdentifier ADD COLUMNS(colAndType (,colAndType)*) -- Alter table column type ALTER TABLE tableIdentifier CHANGE COLUMN colName colName colType -- Alter table properties ALTER TABLE tableIdentifier SET TBLPROPERTIES (key = 'value') #Alter table examples --rename to: ALTER TABLE hudi_cow_nonpcf_tbl RENAME TO hudi_cow_nonpcf_tbl2; --add column: ALTER TABLE hudi_cow_nonpcf_tbl2 add columns(remark string); --change column: ALTER TABLE hudi_cow_nonpcf_tbl2 change column uuid uuid bigint; --set properties; alter table hudi_cow_nonpcf_tbl2 set tblproperties (hoodie.keep.max.commits = '10');


目前, SHOW partitions仅适用于文件系统,因为它基于文件系统表路径。


本方法动用 Spark 来展览板 Hudi 的功能表。然而 ,Hudi 还也可以扶持好几种表类行/咨询个人网站类行,有时候还也可以从 Hive、Spark、Presto 等咨询个人网站双引擎咨询个人网站 Hudi 表。 Hudi 活动还有某个个,在鉴于 Docker 的快速设置上展览板了各种这部分文章,各种有关设计也都在网上运营。

叱!叱!让我们在 MinIO 上构建 Hudi 数据湖吧!

Apache Hudi 是首个统计统计数据库统计湖开启工作表格式,在流式的网络架构中引起顾虑。 充滿潜能,越变越重视的用 Hudi/對象内存用于 Hadoop/HDFS,以完成云原始流统计统计数据库统计湖。施用 MinIO 实施 Hudi 内存为多云统计统计数据库统计湖和深入分析刮平了路段。 MinIO 涵盖,可在本土、公用设施/私有云和边侧等的位置期间搜集统计统计数据库统计,而使完成机构需提交的突出系统,列如 初中地理短路电流动态平衡和更快热热报警变更。


目前在 MinIO 上试一试 Hudi。比如您有其中疑惑或若想分享图片销售技巧,请借助连接。


也发布信息。


바카라사이트 바카라사이트 온라인바카라