1. 首页 > 科技 > 数码资讯

Hudi 1.0 新功能预览

Hudi 是一个高效的事务型数据湖仓平台,其核心特色是一个开放性的表格式定义和一套全面的事务数据库核心层。这一核心层不仅支持索引功能,还能高效地处理并发事务,并具备强大的变更数据捕获能力。在数据管道中,Hudi 能够从上游数据源如 Kafka 接收数据,并利用 Spark 和 Flink 等执行引擎进行数据导入与处理。平台还提供自动文件大小调整、增量处理和变更捕获等功能,以优化数据的清理与转换。此外,Hudi 具备丰富的表服务能力,如数据清理和聚类,确保数据管理的高效性。Hudi 已与众多数据生态系统组件广泛集成,包括目录同步和多种查询引擎,以实现数据处理的多样化和灵活性。

上图是 Hudi 的架构分层图,展示了其作为数据湖仓平台的三个核心层级。最底层用绿色表示的是开放的存储层,负责底层数据的存储,使用诸如 Parquet、Avro 和 ORC 等开源文件格式。其上一层是事务性数据库核心层,该层定义了数据表格式、数据表服务、索引机制以及并发控制,确保了数据的一致性和高效处理。最顶层是开放平台服务层,提供了一套开发的 API,支持与各类集成生态技术的读写操作,并实现了平台的功能性,包括元数据服务、数据入湖工具和与不同查询引擎的集成。这些层级共同构成了 Hudi 的平台架构,使得用户和开发人员能够直接与平台服务及工具交互,而机器则通过底层的读写支持与数据库核心层交互。在 Hudi 1.0 版本中,这些架构层级经过了新的性能和功能优化,以满足现代数据管理的需求。

Hudi 1.0 的构想源于对 Hudi 成长历程的回顾。Hudi 最初旨在解决大规模数据摄取、增量数据处理和快速创建的问题,并需要与 Presto、Spark、Flink、Trino 等查询引擎集成。虽然这些引擎在列式数据查询方面表现出色,但它们的整合过程却充满挑战。

作为湖仓领域的先锋,Hudi 曾被称为事务性数据湖。在生态系统的早期阶段,Hudi 做出了一些保守的设计选择,例如为不同的查询引擎开发了各自的连接器。在过去的五年中,Hudi 社区蓬勃发展,同时也暴露出更多元化的需求,特别是在事务性操作、快速更新和删除功能方面。因此,Hudi 团队认识到有必要对现有设计进行深层次的重新思考和优化,以适应不断变化的数据处理需求。

Hudi 1.0 的五大发展方向体现了对当前数据湖架构的深度思考和对未来规划的远见:

在对比数据库的经典设计架构与 Hudi 的架构时,我们可以看到 Hudi 在数据湖仓领域实现了一个类似数据库的功能层次。最顶层的客户端模块是用户与系统交互的接口,负责处理 SQL 层的请求。在此之下,Hudi 集成了不同查询引擎的查询解析和优化功能,目前主要依赖各引擎自身的优化,但未来可能引入 Hudi 内部的优化机制。

蓝色的模块代表与外部系统的集成,而中间的方块则展示了 Hudi 实现的事务性管理机制,这与传统数据库中的锁管理、日志管理等模块相对应。已经实现的组件用绿色方块表示,而像缓存管理这样的未来愿景则用其他颜色表示,这表明了 Hudi 1.0 版本的发展方向。

接下来,将介绍 Hudi 1.0 的一些关键功能。Hudi 1.0 版本的设计理念可以在其RFC(Request for Comments)文档中找到,该文档详细介绍了版本的主要设计方向和预期特性。

接下来将重点讨论几个关键功能,首先是 Hudi 的 LSM tree 时间线。Hudi 的时间线本质上是一个不可变的事务日志,记录了表上所有已完成交易的详细信息。这个事务日志通常会随着每次提交而线性增长。Hudi 0.x 版本维护了两个时间线:活跃时间线和归档时间线。活跃时间线用于快速检索最新信息,而归档时间线则用于满足特定场景下的历史数据查询需求。由于归档数据采用了不同的存储机制,访问这些数据的成本相对较高。

为了优化 Hudi 时间线的存储效率,我们考虑采用 LSM tree 这种经过验证的高效数据结构,它特别适合处理大规模写入操作。在 Hudi 1.0 中,我们重新实现了写入时间线的机制,现在每次写入都会记录其起始和结束时间。此外,我们将现有的线性存储结构转换成了 LSM tree 结构,这允许进行更高效的压缩操作。

LSM tree 的优势在于其树形分层结构,能够在顶层(如内存或缓存)快速检索信息,同时在更长的时间线上,可以通过压缩多个事务到更大的 parquet 文件中,来提高读取效率和存储效率。这种结构不仅优化了数据的快速访问,还提升了整体存储的紧凑性和性能。

接下来对 LSM Tree 时间线进行了一系列测试,其中包括模拟了 100 万次提交的交易日志。在无需加载所有元数据的情况下,仅访问开始时间和结束时间以及事务中涉及的文件,我们实现了在 367ms 内加载整个时间线。这一性能提升得益于将时间线数据存储为 parquet 文件,这不仅减少了读取所需的元数据量,还提供了更高的读取灵活性,从而显著提高了加载效率。

接下来探讨另一个关键功能:函数索引。Hudi 的当前版本已经集成了一个多模式索引子系统,支持文件索引、列统计和布隆过滤器等功能,且这些索引可以异步构建。在 Hudi 1.0 中,我们希望进一步增强多模式索引的通用性。受到数据库索引机制的启发,我们考虑了基于 R 树的空间索引和基于 Lucene 的搜索索引等高级功能。例如,PostgreSQL 能够在表达式上创建索引,这启发了我们实现函数索引的思路。函数索引的引入将使 Hudi 的索引功能更加灵活和强大,从而提高查询效率和处理复杂查询的能力。

函数索引的一个典型用例是在处理包含组织 ID 和时间戳的事件流数据时。通常,我们希望根据组织 ID 进行分区,然后进一步根据时间戳细分。例如,如果有1,000 个组织的一整年数据,我们可能会创建 365,000 个分区。然而,这种做法可能会导致数据倾斜和大量小文件的问题,这既影响了存储效率,也降低了查询性能。

为了解决这个问题,Hudi 1.0 引入了函数索引。我们仅根据组织 ID 进行物理分区,然后为时间戳定义一个函数,比如将 Unix 时间戳转换为小时,并记录每个小时的最大值和最小值。这样就可以在索引中实现高效的>

函数索引的使用可以通过一个简单的示例来解释。在左侧的 SQL 示例中,使用 city 来分区,同时还有一个时间戳字段。我们不需要针对时间戳进一步分区,而是可以使用 create index 的语法来生成一个新的索引,该索引将时间戳转换为小时。一旦生成了这个索引,随后的 SELECT 语句就可以利用时间戳进行高效的数据跳过。

在右侧的两个 Spark DAG(有向无环图)演示中,展示了在有函数索引和没有函数索引的情况下,数据跳过是如何实现的。使用函数索引,Spark 查询可以更有效地跳过不相关数据,从而提高查询性能和减少资源消耗。这种索引策略不仅简化了数据分区,还提升了整体的数据处理效率。

另一个重要的功能改进是 Hudi 新开发的文件组读取器和写入器。Hudi 自创建之初就设计了一个基于主键的概念。在 MOR(Merge-On-Read)表类型中,我们实现了一个合并操作,从第一天起就支持快照查询,即实时地将日志数据合并到基础文件中。这一机制确保了即使在数据不断写入和更新时,也能高效地执行查询操作,提供了对历史和最新数据的统一视图。

对于 Hudi 中的合并操作,我们发现了潜在的优化空间。具体来说,我们可以在记录日志的同时,记录下日志所需更新的基础文件的位置信息。这样,在进行合并操作时,能够直接定位到文件的具体位置,从而高效地执行合并。

此外,Hudi 1.0 增加了对部分更新(partial update)的优先支持。传统的日志文件默认记录整条更新语句,但在许多情况下,只需记录更新的字段。通过仅记录更新的字段及其值和位置,能够极大优化合并过程。

设计文件组读取器和写入器的另一个好处是,它使得与各种查询引擎的集成变得更加简便。这种设计统一了接口,使得扩展对不同引擎的支持变得更加方便,从而提升了 Hudi 的整体灵活性和可扩展性。

针对基于位置的合并操作,我们进行了一系列基准测试。这些测试涉及了两个不同规模的合并表,一个包含 500GB、7.5 亿条记录,另一个包含 1TB、15 亿条记录。每条记录大约 1KB 大小,表包含 1000 个分区,每个文件大约 256MB。

在测试中,我们首先批量加载数据,然后执行删除和更新操作,更新表中 50% 的记录。通过使用文件组读取器并利用位置信息进行合并操作,我们观察到了 12% 到 20% 的性能提升。这一提升随着数据量的增加而变得更加显著。对于具体的性能数据和详细分析,可以参考 Hudi 的 PR 10167。

在部分更新(partial update)的测试中,我们观察到了更为显著的性能提升。上图中展示了更新操作的结果对比。当使用全量更新,即整条记录的所有字段与仅更新部分字段时,更新的延迟降低了 1.4 倍。同时,写入的文件大小减少了 70 倍,这是因为我们节省了大量未更新的数据。由于写入更为高效,节省了空间,合并操作也变得更为高效,我们观察到了 5.7 倍的性能提升。这些优化不仅提高了更新操作的效率,还显著减少了存储空间的占用。

最后一个重点功能是非阻塞并发控制。这个设计基于一个常见场景:一个每分钟写入的进程和每小时执行一次的 GDPR 删除作业。如果采用乐观锁机制,删除作业可能会频繁遇到冲突,因为删除操作是随机的,这会导致删除作业在大多数情况下都需要重试,从而浪费资源。

Hudi 从一开始就采用了 MVCC(多版本并发控制)机制。在写入侧,允许不加阻塞地写入,而在使用 MOR 模式时,在合并侧执行异步合并操作。此外,我们可以利用合并的机会进行类聚操作,以优化存储。这种设计确保了在处理并发写入和删除操作时,系统的效率和资源利用率得到提高。

为了解决多个写入器并发控制的问题,Hudi 支持乐观锁的使用,也引入了早期冲突检测机制。此外,Hudi 探索了更通用的非阻塞多版本并发控制机制。在 Hudi 1.0 中,我们实现了一个基于 MOR 写入过程的非阻塞并发控制。

当 MOR 写入操作在不同写入器上生成不同的日志文件时,Hudi 最初不会阻塞写入过程。通过使用全局单调递增的时间戳来记录每个写入的开始和结束时间,我们可以在合并或快照读取阶段解决潜在的冲突。这种方法允许在写入时保持非阻塞状态,从而提高了写入效率,同时确保了数据的最终一致性。

今天的重点内容已经介绍完毕。关于 Hudi 1.0,这里再提供一些额外信息。Hudi 1.0 的技术文档已经发表,可以在相应的链接中查阅。此外,相关的RFC 文档和设计文档也已公开,供社区参考。Hudi 1.0 beta1 的 jar 包也已经发布。这些资源将为希望深入了解 Hudi 1.0 的用户和开发者提供帮助。

最后,展示一下 Hudi 社区的活跃情况。社区非常欢迎新成员的加入,这里提供了丰富的文档链接和资源,以便大家更好地了解和参与 Hudi 项目。此外,欢迎关注 Hudi 的公众号来获取最新信息,也欢迎加入我们的社区,共同推动 Hudi 的发展。

本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://www.jmbhsh.com/shumazixun/35022.html

联系我们

QQ号:***

微信号:***

工作日:9:30-18:30,节假日休息