数据湖存储解决方案之Hudi

1.Hudi是什么?

Apache Hudi是一个Data Lakes的开源方案,Hudi是Hadoop Upserts Delete and Incremental的简写,它是由Uber开发并开源的Data Lakes解决方案。Hudi能够基于HDFS之上管理大型分析数据集,可以对数据进行插入、更新、增量消费等操作,主要目的是高效减少摄取过程中的数据延迟。

Apache Hudi官方网站是: Apache Hudi

官方对 Hudi 的定义如下:

Apache Hudi is a transactional data lake platform that brings database and data warehouse capabilities to the data lake. Hudi reimagines slow old-school batch data processing with a powerful new incremental processing framework for low latency minute-level analytics.

Apache Hudi将核心仓库和数据库功能直接引入数据湖。Hudi提供了表、事务、高效的upserts/delete、高级索引、流摄取服务、数据集群/压缩优化和并发,同时保持数据的开源文件格式。Hudi基于Parquet列式存储与Avro行式存储,同时避免创建小文件,实现高效率低延迟的数据访问。

Apache Hudi不仅非常适合于流工作负载,而且还允许创建高效的增量批处理管道。

Apache Hudi可以轻松地在任何云存储平台上使用。Hudi的高级性能优化,使分析工作负载更快的任何流行的查询引擎,包括Apache Spark、Flink、Presto、Trino、Hive、Impala等。

Apache Hudi 的特点:

  • 可插拔索引机制支持快速Upsert/Delete
  • 支持增量拉取表变更以进行处理
  • 支持事务提交及回滚,并发控制
  • 支持Spark、Presto、Trino、Hive、Flink等引擎的SQL读写
  • 自动管理小文件,数据聚簇,压缩,清理
  • 流式摄入,内置CDC源和工具
  • 内置可扩展存储访问的元数据跟踪
  • 向后兼容的方式实现表结构变更的支持
  • 写入器和查询之间的快照隔离
  • 用于数据恢复的savepoint保存点,Hudi通过Savepoint来实现数据恢复

Apache Hudi在DFS的数据集上提供以下流原语

  • 插入更新 (如何改变数据集?)
  • 增量拉取 (如何获取变更的数据?)

这两个原语是Hudi 使用最广泛的两个功能,这使用户能够吸收更改数据捕获,并将其大规模应用于数据湖。

Apache Hudi 设计原则:

  • 流式读/写:Hudi借鉴了数据库设计的原理,从零设计,应用于大型数据集记录流的输入和输出。为此,Hudi提供了索引实现,可以将记录的键快速映射到其所在的文件位置。同样,对于流式输出数据,Hudi通过其特殊列添加并跟踪记录级的元数据,从而可以提供所有发生变更的精确增量流。

  • 自管理:Hudi注意到用户可能对数据新鲜度(写友好)与查询性能(读/查询友好)有不同的期望,它支持了三种查询类型,这些类型提供实时快照,增量流以及稍早的纯列数据。在每一步,Hudi都努力做到自我管理(例如自动优化编写程序的并行性,保持文件大小)和自我修复(例如:自动回滚失败的提交),即使这样做会稍微增加运行时成本(例如:在内存中缓存输入数据已分析工作负载)。如果没有这些内置的操作杠杆/自我管理功能,这些大型流水线的运营成本通常会翻倍。

  • 万物皆日志:Hudi还具有 append only、云数据友好的设计,该设计实现了日志结构化存储系统的原理,可以无缝管理所有云提供商的数据。

  • 键-值数据模型:在写方面,Hudi表被建模为键值对数据集,其中每条记录都有一个唯一的记录键。此外,一个记录键还可以包括分区路径,在该路径下,可以对记录进行分区和存储。这通常有助于减少索引查询的搜索空间。

2.Hudi实现原理

写Hudi表的组件使用了一种受支持的方式嵌入到Apache Spark作业中,它会在支持DFS的存储上生成代表Hudi表的一组文件。然后,在具有一定保证的情况下,诸如Apache Spark、Presto、Apache Hive之类的查询引擎可以查询该表。

Hudi表的三个主要组件:

  1. 有序的时间轴元数据。类似于数据库事务日志。
  2. 分层布局的数据文件:实际写入表中的数据。
  3. 索引(多种实现方式):映射包含指定记录的数据集。

Hudi提供了以下功能来对基础数据进行写入、查询,这使其成为大型数据湖的重要模块:

  • 支持快速,可插拔索引的upsert();
  • 高效、只扫描新数据的增量查询;
  • 原子性的数据发布和回滚,支持恢复的Savepoint;
  • 使用mvcc(多版本并发控制)风格设计的读和写快照隔离;
  • 使用统计信息管理文件大小;
  • 已有记录update/delta的自管理压缩;
  • 审核数据修改的时间轴元数据;
  • 满足GDPR(通用数据保护条例)、数据删除功能。

下面分别对每个组件进行介绍。

2.1 时间轴

在它的核心,Hudi维护一条包含在不同的即时时间(instant time)对数据集做的所有instant操作的时间轴,从而提供,从不同时间点出发得到不同的视图下的数据集。时间轴类似于数据库的redo/transaction日志,由一组时间轴实例组成。Hudi保证在时间轴上执行的操作的原子性和基于即时时间的时间轴一致性。时间轴被实现为表基础路径下.hoodie元数据文件夹下的一组文件。具体来说,最新的instant被保存为单个文件,而较旧的instant被存档到时间轴归档文件夹中,以限制writers和queries列出的文件数量。Hudi时间轴包含以下组件:

  • 操作类型 : 对数据集执行的操作类型
  • 即时时间 : 即时时间通常是一个时间戳(例如:20190117010349),该时间戳按操作开始时间的顺序单调增加。
  • 状态 : 即时的状态

Hudi保证在时间轴上执行的操作的原子性和基于即时时间的时间轴一致性。

每个instant都有avro或者json格式的元数据信息,详细的描述了该操作的状态以及这个即时时刻instant的状态。执行的关键操作包括

  • COMMITS - 一次提交表示将一组记录原子写入到数据集中。
  • CLEANS - 删除数据集中不再需要的旧文件版本的后台活动。
  • DELTA_COMMIT - 增量提交是指将一批记录原子写入到MergeOnRead存储类型的数据集中,其中一些/所有数据都可以只写到增量日志中。
  • COMPACTION - 协调Hudi中差异数据结构的后台活动,例如:将更新从基于行的日志文件变成列格式。在内部,压缩表现为时间轴上的特殊提交。
  • ROLLBACK - 表示提交/增量提交不成功且已回滚,删除在写入过程中产生的所有部分文件。
  • SAVEPOINT - 将某些文件组标记为"已保存",以便清理程序不会将其删除。在发生灾难/数据恢复的情况下,它有助于将数据集还原到时间轴上的某个点

任何给定的即时都可以处于以下状态之一

  • REQUESTED - 表示已调度但尚未启动的操作。
  • INFLIGHT - 表示当前正在执行该操作。
  • COMPLETED - 表示在时间轴上完成了该操作。

示例:

上面的示例显示了在Hudi数据集上大约10:00到10:20之间发生的更新事件,大约每5分钟一次,将提交元数据以及其他后台清理/压缩保留在Hudi时间轴上。 观察的关键点是:提交时间指示数据的到达时间(上午10:20),而实际数据组织则反映了实际时间或事件时间,即数据所反映的(从07:00开始的每小时时段)。在权衡数据延迟和完整性时,这是两个关键概念。

如果有延迟到达的数据(事件时间为9:00的数据在10:20达到,延迟 >1 小时),我们可以看到upsert将新数据生成到更旧的时间段/文件夹中。 在时间轴的帮助下,增量查询可以只提取10:00以后成功提交的新数据,并非常高效地只消费更改过的文件,且无需扫描更大的文件范围,例如07:00后的所有时间段。

2.2 数据文件

Hudi将DFS上的数据集组织到基本路径下的目录结构中。数据集分为多个分区,这些分区是包含该分区的数据文件的文件夹,这与Hive表非常相似。 每个分区被相对于基本路径的特定分区路径区分开来。

在每个分区内,文件被组织为文件组,由文件id唯一标识。 每个文件组包含多个文件切片,其中每个切片包含在某个提交/压缩即时时间生成的基本列文件(*.parquet)以及一组日志文件(*.log*),该文件包含自生成基本文件以来对基本文件的插入/更新。 Hudi采用MVCC设计,其中压缩操作将日志和基本文件合并以产生新的文件片,而清理操作则将未使用的/较旧的文件片删除以回收DFS上的空间。

Hudi通过索引机制将给定的hoodie键(记录键+分区路径)映射到文件组,从而提供了高效的Upsert。 一旦将记录的第一个版本写入文件,记录键和文件组/文件id之间的映射就永远不会改变。 简而言之,映射的文件组包含一组记录的所有版本。

2.3 索引

Hudi通过索引机制提供高效的upsert操作,该机制会将一个记录键+分区路径组合一致性的映射到一个文件ID。这个记录键和文件组/文件ID之间的映射自记录被写入文件组开始就不会再改变。简而言之,这个映射文件组包含了一组文件的所有版本。Hudi 支持了多种类型的索引实现,典型的如 BLOOM、BUCKET 索引,以及自定义索引等方式。这些索引映射一个记录键到包含该记录的文件ID。这将使我们无需扫描表中的每条记录,就可显著提高upsert速度。Hudi索引可以根据其查询分区记录的能力进行分类:

  • 全局索引:不需要分区信息即可查询记录键映射的文件ID。比如,写程序可以传入null或者任何字符串作为分区路径(partitionPath),但索引仍然会查找到该记录的位置。全局索引在记录键在整张表中保证唯一的情况下非常有用,但是查询的消耗随着表的大小呈函数式增加。全表索引保证数据在表级的唯一性。
  • 非全局索引:与全局索引不同,非全局索引依赖分区路径(partitionPath),对于给定的记录键,它只会在给定分区路径下查找该记录。这比较适合总是同时生成分区路径和记录键的场景,同时还能享受到更好的扩展性,因为查询索引的消耗只与写入到该分区下数据集大小有关系。分区级别的索引可以保证数据在分区内的唯一性。

2.4 存储类型

Hudi支持以下存储类型。

  • 写时复制(copy-on-write,COW): 仅使用列文件格式(例如parquet)存储数据。通过在写入过程中执行同步合并以更新版本并重写文件。
  • 读时合并(merge-on-read,MOR): 使用列式(例如parquet)+ 基于行(例如avro)的文件格式组合来存储数据。 更新记录到增量文件中,然后进行同步或异步压缩以生成列文件的新版本。

写时复制:

写时复制存储中的文件片仅包含基本/列文件,并且每次提交都会生成新版本的基本文件。 换句话说,我们压缩每个提交,从而所有的数据都是以列数据的形式储存。在这种情况下,写入数据非常昂贵(我们需要重写整个列数据文件,即使只有一个字节的新数据被提交),而读取数据的成本则没有增加。 这种视图有利于读取繁重的分析工作。

示例1:

以下内容说明了将数据写入写时复制存储并在其上运行两个查询时,它是如何工作的。

随着数据的写入,对现有文件组的更新将为该文件组生成一个带有提交即时时间标记的新切片,而插入分配一个新文件组并写入该文件组的第一个切片。 这些文件切片及其提交即时时间在上面用颜色编码。 针对这样的数据集运行SQL查询(例如:select count(*)统计该分区中的记录数目),首先检查时间轴上的最新提交并过滤每个文件组中除最新文件片以外的所有文件片。 如您所见,旧查询不会看到以粉红色标记的当前进行中的提交的文件,但是在该提交后的新查询会获取新数据。因此,查询不受任何写入失败/部分写入的影响,仅运行在已提交数据上。

写时复制存储的目的是从根本上改善当前管理数据集的方式,通过以下方法来实现

  • 优先支持在文件级原子更新数据,而无需重写整个表/分区
  • 能够只读取更新的部分,而不是进行低效的扫描或搜索
  • 严格控制文件大小来保持出色的查询性能(小的文件会严重损害查询性能)。

示例2:

在instant 0 时刻写入一部分数据(ABCDE),在instant 1时刻更新A -> A',D -> D',在instant 2时刻更新A' -> A'',E -> E',并插入F 那么对于快照查询(Snapshot Query)每次都是读取的最新的FileSlice,增量查询(Incremental Query)读取指定commit之间的Parquet文件,然后再将时间范围下推至Parquet文件进行过滤,只读取符合条件的变更的数据。

读时合并:

读时合并存储是写时复制的升级版,从某种意义上说,它仍然可以通过读优化表提供数据集的读取优化视图(写时复制的功能)。 此外,它将每个文件组的更新插入存储到基于行的增量日志中,通过文件id,将增量日志和最新版本的基本文件进行合并,从而提供近实时的数据查询。因此,此存储类型智能地平衡了读和写的成本,以提供近乎实时的查询。 这里最重要的一点是压缩器,它现在可以仔细挑选需要压缩到其列式基础文件中的增量日志(根据增量日志的文件大小),以保持查询性能(较大的增量日志将会提升近实时的查询时间,并同时需要更长的合并时间)。

以下内容说明了存储的工作方式,并显示了对近实时表和读优化表的查询。

示例1:

  • 现在,我们每1分钟左右就有一次提交,这是其他存储类型无法做到的。
  • 现在,在每个文件id组中,都有一个增量日志,其中包含对基础列文件中记录的更新。 在示例中,增量日志包含10:05至10:10的所有数据。与以前一样,基本列式文件仍使用提交进行版本控制。 因此,如果只看一眼基本文件,那么存储布局看起来就像是写时复制表的副本。
  • 定期压缩过程会从增量日志中合并这些更改,并生成基础文件的新版本,就像示例中10:05发生的情况一样。
  • 有两种查询同一存储的方式:读优化(RO)表和近实时(RT)表,具体取决于我们选择查询性能还是数据新鲜度。
  • 对于RO表来说,提交数据在何时可用于查询将有些许不同。 请注意,以10:10运行的(在RO表上的)此类查询将不会看到10:05之后的数据,而在RT表上的查询总会看到最新的数据。
  • 何时触发压缩以及压缩什么是解决这些难题的关键。 通过实施压缩策略,在该策略中,与较旧的分区相比,我们会积极地压缩最新的分区,从而确保RO表能够以一致的方式看到几分钟内发布的数据。

读时合并存储上的目的是直接在DFS上启用近实时处理,而不是将数据复制到专用系统,后者可能无法处理大数据量。 该存储还有一些其他方面的好处,例如通过避免数据的同步合并来减少写放大,即批量数据中每1字节数据需要的写入数据量。

示例2:

对于MOR表,快照查询(SNAPSHOT Query)读取的是Base文件与Log合并后的最新结果;而增量查询读取指定commit之间的Parquet以及Log文件,然后再对Log文件进行Block级别的过滤(根据Commit时间),合并重复key后返回结果。

2.5 视图

Hudi支持以下存储数据的视图

  • 读优化视图 : 在此视图上的查询将查看给定提交或压缩操作中数据集的最新快照。 该视图仅将最新文件切片中的基本/列文件暴露给查询,并保证与非Hudi列式数据集相比,具有相同的列式查询性能。
  • 增量视图 : 对该视图的查询只能看到从某个提交/压缩后写入数据集的新数据。该视图有效地提供了更改流,来支持增量数据管道。
  • 实时视图 : 在此视图上的查询将查看某个增量提交操作中数据集的最新快照。该视图通过动态合并最新的基本文件(例如parquet)和增量文件(例如avro)来提供近实时数据集(几分钟的延迟)。

3.Hudi的应用场景

3.1 CDC数据入湖

这个场景主要是DB数据入湖入仓,把原来T + 1的数据新鲜度提升到分钟级别。数据新鲜度通过目前比较火的以Debezium、Maxwell为代表的CDC(change Data Capture)技术实现。以Streaming近实时的方式同步到数仓中。在传统的Hive数仓中想保证实时是非常困难的,尤其是文件更新,湖表实时写入更新,基本不可能实现。

CDC技术对数仓本身存储是有要求的,首先是更新效率得足够高,能够支持以Streaming方式写入,并且能够非常高效的更新。尤其是CDC log在更新过程中还可能会乱序,如何保证这种乱序更新的ACID语义,是有很高要求的,当前能满足乱序更新的湖格式只有Hudi能做到,而且Hudi还考虑到了更新的效率问题,是目前比较先进的架构。

图中方案3相比上面的方案,比较适合体量比较大(每天增量能达到亿级别)、数据平台比较健全的公司,中间有一套统一的数据同步方案(汇总不同源表数据同步至消息队列),消息队列承担了数据的容错、容灾、缓存功能。同时,这套方案的扩展性也更好。通过Kafka的topic subscribe方式,可以比较灵活地分发数据。通过以上三种方式入湖Hudi,以某数据中台为例已经有6000多张源表写入Hudi,日增几十亿数据入湖。

3.2 分钟级实时数仓

构造分钟级别的实时数仓,分钟级别的端到端数据新鲜度,同时又非常开放的OLAP查询引擎可以适配。其实是对Kappa架构或者是原先Streaming数仓架构的一套新解法。在没有这套架构之前,实时分析会跳过Hudi直接把数据双写到OLAP系统中,比如ClickHouse、ES、MongoDB等。当数仓存储已经可以支持高效率分级别更新,能够对接OLAP引擎,那么这套架构就被大大简化,首先不用双写,一份数据就可以保证only one truth语义,避免双写带来数据完整性的问题。其次因为湖格式本身是非常开放的,在查询端引擎可以有更多选择,比如Hudi就支持Presto、Trino、Spark、StarRocks,以及云厂商的Redshift引擎,会有非常高的灵活度。多层数据可见性也从T+1 小时或天,缩短到分钟级别。

3.3 流式计算PV/UV

Apache Hudi 的Payload是一种可扩展的数据处理机制,通过不同的Payload我们可以实现复杂场景的定制化数据写入方式,大大增加了数据处理的灵活性。Hudi Payload 在写入和读取 Hudi 表时对数据进行去重、过滤、合并等操作的工具类,通过使用参数"hoodie.datasource.write.payload.class"指定我们需要使用的Payload class。为了实现 pv/uv计算,我们实现了 RecordCountAvroPayload ,它可以在对数据去重的时候,将重复数据的数量记录下来,这里的重复指的是HoodieKey(primary key + partition path)相同。以往处理方式是通过Flink + window 聚合实现,该方式有延迟数据丢弃和state爆掉风险,Hudi Payload机制则没有这些风险。

3.4 多流拼接(大宽表)

上图是一个典型的非常复杂的业务落地,消息流1由Kafka写入Hudi商品销售明细表,消息流2由Kafka写入Hudi用户基本属性表,然后结合Hudi商品标签表和Hve用户扩展属性表进行实时和离线拼接大宽表。

在实现多流拼接功能前有三个前置条件需要满足:

  • 基于乐观锁的Timeline
  • 基于marker的早期冲突检测
  • 启用occ(乐观并发控制)

这里主要描述基于时间线服务器的标记机制,该机制优化了存储标记的相关延迟。Hudi 中的时间线服务器用作提供文件系统和时间线视图。新的基于时间线服务器的标记机制将标记创建和其他标记相关操作从各个执行器委托给时间线服务器进行集中处理。时间线服务器在内存中为相应的标记请求维护创建的标记,时间线服务器通过定期将内存标记刷新到存储中有限数量的底层文件来实现一致性。通过这种方式,即使数据文件数量庞大,也可以显著减少与标记相关的实际文件操作次数和延迟,从而提高写入性能。

4.Hudi的优缺点

优势

  • 高效处理大规模数据集;
  • 支持实时数据更新和查询;
  • 实现了增量写入机制,提高了数据访问效率;
  • Hudi 可以与流处理管道集成;
  • Hudi 提供了时间旅行功能,允许回溯数据的历史版本。

劣势

  • 在读写数据时需要付出额外的代价;
  • 操作比较复杂,需要使用专业的编程语言和工具。

5.Hudi和Iceberg的对比

Iceberg和Hudi都是数据湖技术,从社区活跃度上来看,Iceberg有超越Hudi的趋势。他们有以下共同点:

  • 都是构建于存储格式之上的数据组织方式
  • 提供ACID能力,提供一定的事务、并行执行能力
  • 提供行级别数据修改能力。
  • 提供一定的Schema扩展能力,例如:新增、修改、删除列操作。
  • 支持数据合并,处理小文件。
  • 支持Time travel 查询快照数据。
  • 支持批量和实时数据读写

Iceberg与Hudi之间不同点在于以下几点:

  • Iceberg支持Parquet、avro、orc数据格式,Hudi支持Parquet和Avro格式。
  • 两者数据存储和查询机制不同
  • Iceberg只支持一种表存储模式,就是有metadata file、manifest file和data file组成存储结构,查询时首先查找Metadata元数据进而过滤找到对应的 SnapShot对应的manifest files ,再找到对应的数据文件。Hudi支持两种表存储模式:Copy On Write(写时合并) 和Merge On Read(读时合并),查询时直接读取对应的快照数据。
  • 对于处理小文件合并时,Iceberg只支持API方式手动处理合并小文件,Hudi对于小文件合并处理可以根据配置自动的执行。
  • Spark与Iceberg和Hudi整合时,Iceberg对SparkSQL的支持目前来看更好。Spark与Hudi整合更多的是Spark DataFrame API 操作。
  • 关于Schema方面,Iceberg Schema与计算引擎是解耦的,不依赖任何的计算引擎,而Hudi的Schema依赖于计算引擎Schema。

我们来看下当前github上这两种技术的发展现状,当前iceberg的fork为1.9k,star为5.1k。hudi的fork 2.5k,star为4.9k。相比来看,iceberg有追上hudi的趋势。

6.各厂商基于Hudi的湖仓架构

6.1 字节跳动

通用Hudi湖仓方案如下:

尽管 Hudi 解决方案已经能够实现一份存储同时包含实时和离线两种场景,但由于数据的分钟级可见,它依然存在一定的优化空间,无法作为实时数仓存储的标准方案。字节在其基础上进行了方案优化。

为解决实时性问题,字节内部在数据湖上自研了基于内存的服务,形成了一套高吞吐、高并发、秒级延迟可见的实时数据湖方案。整体架构如下:

架构底层为数据持久化层。复用 Hudi 的能力实现数据存储。文件分布和 Hudi 一致,通过列存的 base 文件与行存的 log 文件进行数据存储,基于时间戳维护数据版本。通过 filegroup 的方式对文件进行分组,相同逐渐的数据存储在同一个文件组内。后期结合数据构建索引能力,能够比较大幅度提升数据入湖和查询的性能。

架构的第二层是元数据层。对数据湖的元数据进行管理,包括表、分区以及 instant、timeline、snapshot 等这些数据湖特有的元数据。在这一层不光实现了元数据的管理,还能够解决多并发写入的冲突检查和解决,保障 ACID 能力。

架构的第三层是服务层。主要包含两个组件:BTS 和 TMS。BTS 是基于内存构建的服务层,通过内存加速数据读写操作,解决实时场景下数据生产消费的时效性问题。TMS 是聚焦在表优化的服务,会异步做一些 log 文件和 base 文件的compaction/小文件合并优化等操作。

6.2 Shopee

Shopee 内部在使用过程中基于开源的 Apache Hudi 定制了自己的版本,以实现企业级的应用和一些内部业务需求的新特性。通过引入 Hudi 的 Data lake 方案,Shopee 的 Data Mart、推荐、ShopeeVideo 等产品的数据处理流程实现了流批一体、增量处理的特性,很大程度上简化了这一流程,并提升了性能。

Shopee选择使用Hudi有三个原因:

  • 生态支持丰富:Hudi与Shopee 业务需求的契合,数据集大部分来源于业务系统,都带有唯一性标识信息,所以 Hudi 的设计更加符合气数据特性。Hudi对各个大数据生态的兼容。Hudi 对流式场景有着良好的支持。
  • 插件化的能力:Shopee平台提供 Flink 和 Spark 作为通用计算引擎,作为数据集成和数仓建设负载的承载者,同时也使用 Presto 承载数据探索的功能。Hudi 对这三者都支持。
  • 业务特性匹配:在数据集成过程中,用户的 schema 变化是一个非常常见的需要。ODS 的数据变化可能导致下游的计算任务出错。同时,在增量处理时,需要时间处理的语义。支持主键数据的存储和Shpee业务数据库更加契合。

Shopee实时数据集成:

目前 Shopee 内部有大量的业务数据来自业务数据库,它们采用类似 CDC 的技术获取数据库中的变更数据,给业务方构建支持批处理和近实时增量处理的 ODS 层数据。当一个业务方的数据需要接入时,会在进行增量实时集成之前先做一次全量 Bootstrap,构建基础表,然后基于新接入的 CDC 数据进行实时构建。构建的过程中,一般根据用户需求选择构建的 COW 表或者 MOR 表。

Shopee主要使用 Hudi 的核心特性以及在此之上的扩展改造,分别满足了三个主要的用户需求场景:实时数据集成、增量视图和增量计算。并为用户带来了低延时(约 10 分钟)、降低计算资源消耗、降低存储消耗等收益。

6.3 VIVO

当前Hudi主要还是应用在准实时场景:上游从Kafka以append模式接入ods的cow表,下游部分dw层业务根据流量大小选择不同类型的索引表,比如bucket index的mor表,在数据去重后进行dw构建,从而提供统一数据服务层给下游的实时和离线的业务,同时ods层和dw层统一以insert overwrite的方式进行分区级别的容灾保障,Timeline上写入一个replacecommit的instant,不会引发下游流量骤增,如下图所示:

VIVO分别在流批场景、小文件治理、生命周期管理等方向做了相关优化,上线后的收益主要体现在四个方向:

  • 部分实时链路可以进行合并,降低了计算和存储资源成本;
  • 基于watermark有效识别分区写入的完成度,接入湖仓的后续离线任务平均SLA提前时间不低于60分钟;
  • 部分流转批后的任务上线后执行时间减少约40%(比如原先执行需要150秒的任务可以缩短到100秒左右完成 ;
  • 离线增量更新场景,部分任务相较于原先Hive任务可以下降30%以上的计算资源。

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hudi(Hadoop Upsert Delete and Incremental)是一个构建在Hadoop上的开源数据湖架构,它提供了类似于数据库的upsert、delete、incremental等操作,同时支持流处理和批处理。HudiFlink的集成可以实现数据湖的实时计算和增量处理。 在HudiFlink的集成案例中,我们可以使用Flink作为流处理引擎,实现实时数据的读取和写入。具体步骤如下: 首先,我们需要将输入数据源和输出数据源与Flink进行集成。Flink可以读取来自不同数据源的数据,例如Kafka、Hive、HBase等。在我们的案例中,我们需要将Hudi作为输出数据源,因此需要实现一个自定义的Flink Sink函数,用于将Flink的输出数据写入Hudi。 其次,我们需要在Flink中编写业务逻辑,用于对输入数据进行实时计算和增量处理。Flink提供了丰富的API和算子,可以方便地进行数据转换、聚合、过滤等操作。在我们的案例中,我们可以使用Flink的Map和Filter算子,对输入数据进行转换和筛选,然后将结果数据写入Hudi。 最后,我们需要在Flink中配置和管理Hudi的相关参数。Hudi需要使用一些配置信息,例如数据存储路径、数据表的主键、分区字段等。我们可以通过Flink的配置文件或命令行参数,将这些配置信息传递给Hudi。 通过以上步骤,我们可以实现HudiFlink的集成。当输入数据流进入Flink时,Flink可以对数据进行实时计算和增量处理,并将结果数据写入Hudi。这样就可以实现对数据湖中的数据进行实时查询和分析。 通过HudiFlink的集成,我们可以充分发挥两者的优势,实现高效、实时的数据处理和分析。使用Hudi可以保证数据湖的数据一致性和可更新性,而使用Flink可以实现实时计算和增量处理。这样的集成方案可以在企业中广泛应用,为数据团队提供更好的数据湖架构解决方案

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值