深入解析Apache Hudi内核文件标记机制


Posted in Servers onMarch 31, 2022

1. 摘要

Hudi 支持在写入时自动清理未成功提交的数据。Apache Hudi 在写入时引入标记机制来有效跟踪写入存储的数据文件。 在本博客中,我们将深入探讨现有直接标记文件机制的设计,并解释了其在云存储(如 AWS S3、Aliyun OSS)上针对非常大批量写入的性能问题。 并且演示如何通过引入基于时间轴服务器的标记来提高写入性能。

2. 为何引入Markers机制

Hudi中的marker是一个表示存储中存在对应的数据文件的标签,Hudi使用它在故障和回滚场景中自动清理未提交的数据。

每个标记条目由三部分组成

  • 数据文件名
  • 标记扩展名 (.marker)
  • 创建文件的 I/O 操作(CREATE - 插入、MERGE - 更新/删除或 APPEND - 两者之一)。

例如标记91245ce3-bb82-4f9f-969e-343364159174-0_140-579-0_20210820173605.parquet.marker.CREATE指示相应的数据文件是91245ce3-bb82-4f9f-969e-343364159174-0_140-579-0_20210820173605.parquet 
并且 I/O 类型是 CREATE。

在写入每个数据文件之前,Hudi 写入客户端首先在存储中创建一个标记,该标记会被持久化,在提交成功后会被写入客户端显式删除。

标记对于写客户端有效地执行不同的操作很有用,标记主要有如下两个作用

删除重复/部分数据文件:通过 Spark 写入 Hudi 时会有多个 Executor 进行并发写入。一个 Executor 可能失败,留下部分数据文件写入,在这种情况下 Spark 会重试 Task ,当启用speculative execution时,可以有多次attempts成功将相同的数据写入不同的文件,但最终只有一次attempt会交给 Spark Driver程序进程进行提交。标记有助于有效识别写入的部分数据文件,其中包含与后来成功写入的数据文件相比的重复数据,并在写入和提交完成之前清理这些重复的数据文件。

回滚失败的提交:写入时可能在中间失败,留下部分写入的数据文件。在这种情况下,标记条目会在提交失败时保留在存储中。在接下来的写操作中,写客户端首先回滚失败的提交,通过标记识别这些提交中写入的数据文件并删除它们。

接下来我们将深入研究现有的标记机制,阐述其性能问题,并演示新的基于时间轴服务器的标记机制来解决该问题。

3. 现有的直接标记机制及其局限性

现有的标记机制简单地创建与每个数据文件相对应的新标记文件,标记文件名如前面所述。 每个 marker 文件被写入在相同的目录层次结构中,即提交即时和分区路径,在Hudi表的基本路径下的临时文件夹.hoodie/.temp下。 例如,下图显示了向 Hudi 表写入数据时创建的标记文件和相应数据文件的示例。 在获取或删除所有marker文件路径时,该机制首先列出临时文件夹.hoodie/.temp/<commit_instant>下的所有路径,然后进行操作。

深入解析Apache Hudi内核文件标记机制

虽然扫描整个表以查找未提交的数据文件效率更高,但随着要写入的数据文件数量的增加,要创建的标记文件的数量也会增加。 这可能会为 AWS S3 等云存储带来性能瓶颈。 在 AWS S3 中,每个文件创建和删除调用都会触发一个 HTTP 请求,并且对存储桶中每个前缀每秒可以处理的请求数有速率限制。 当并发写入的数据文件数量和 marker 文件数量巨大时,marker 文件的操作会成为写入性能的显着性能瓶颈。而在像 HDFS 这样的存储上,用户可能几乎不会注意到这一点,其中文件系统元数据被有效地缓存在内存中。

4. 基于时间线服务器的标记机制提高写入性能

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

深入解析Apache Hudi内核文件标记机制

为了提高处理标记创建请求的效率,我们设计了在时间线服务器上批量处理标记请求。 每个标记创建请求在 Javalin 时间线服务器中异步处理,并在处理前排队。 对于每个批处理间隔,例如 20 毫秒,调度线程从队列中拉出待处理的请求并将它们发送到工作线程进行处理。 每个工作线程处理标记创建请求,并通过重写存储标记的底层文件。有多个工作线程并发运行,考虑到文件覆盖的时间比批处理时间长,每个工作线程写入一个不被其他线程触及的独占文件以保证一致性和正确性。 批处理间隔和工作线程数都可以通过写入选项进行配置。

深入解析Apache Hudi内核文件标记机制

请注意工作线程始终通过将请求中的标记名称与时间线服务器上维护的所有标记的内存副本进行比较来检查标记是否已经创建。 存储标记的底层文件仅在第一个标记请求(延迟加载)时读取。 请求的响应只有在新标记刷新到文件后才会返回,以便在时间线服务器故障的情况下,时间线服务器可以恢复已经创建的标记。 这些确保存储和内存中副本之间的一致性,并提高处理标记请求的性能。

5. 标记相关的写入选项

我们在 0.9.0 版本中引入了以下与标记相关的新写入选项,以配置标记机制。

  • hoodie.write.markers.type,要使用的标记类型。支持两种模式: direct,每个数据文件对应的单独标记文件由编写器直接创建; timeline_server_based,标记操作全部在时间线服务中处理作为代理。 为了提高效率新的标记条目被批处理并存储在有限数量的基础文件中。默认值为direct
  • hoodie.markers.timeline_server_based.batch.num_threads,用于在时间轴服务器上批处理标记创建请求的线程数。默认值为20。
  • hoodie.markers.timeline_server_based.batch.interval_ms,标记创建批处理的批处理间隔(以毫秒为单位)。默认值为50。

6. 性能

我们通过使用 Amazon EMR 和 Spark 和 S3 批量插入大规模数据集来评估directtimeline_server_based的标记机制的写入性能。 输入数据大约为 100GB。 我们通过设置最大 parquet 文件大小为 1MB 和并行度为 240 来配置写入操作以并发生成大量数据文件。 正如我们之前提到的,而直接标记机制的延迟对于较小数量的增量写入是可以接受的,对于产生更多数据文件的大批量插入/写入,开销会急剧增加。

如下图所示,由于是批处理,基于时间线服务器的标记机制生成的存储标记的文件要少得多,从而导致标记相关的 I/O 操作的时间要少得多,因此与直接相比,写入完成时间减少了 31%。 标记文件机制。

深入解析Apache Hudi内核文件标记机制

7. 总结

我们发现由于 AWS S3 等云存储上文件创建和删除调用的速率限制,现有的直接标记文件机制会导致性能瓶颈。 为了解决这个问题我们引入了一种利用时间线服务器的新标记机制,它将标记创建和其他与标记相关的操作从各个 Executor 委托给时间线服务器,并使用批处理来提高性能。使用 Spark 和 S3 在 Amazon EMR 上进行的性能评估表明,与标记相关的 I/O 延迟和整体写入时间有所减少。

以上就是深入解析Apache Hudi内核文件标记机制的详细内容,更多关于Apache Hudi内核文件标记的资料请关注三水点靠木其它相关文章!

Servers 相关文章推荐
Nginx已编译的nginx-添加新模块
Apr 01 Servers
Nginx反向代理学习实例教程
Oct 24 Servers
nginx实现动静分离的方法示例
Nov 07 Servers
nginx内存池源码解析
Nov 20 Servers
Nginx性能优化之Gzip压缩设置详解(最大程度提高页面打开速度)
Feb 12 Servers
关于Nginx中虚拟主机的一些冷门知识小结
Mar 03 Servers
Consul在linux环境的集群部署
Apr 08 Servers
nginx 配置指令之location使用详解
May 25 Servers
利用nginx搭建RTMP视频点播、直播、HLS服务器
May 25 Servers
Nginx安装配置详解
Jun 25 Servers
教你nginx跳转配置的四种方式
Jul 07 Servers
nginx访问报403错误的几种情况详解
Jul 23 Servers
Apache Hudi数据布局黑科技降低一半查询时间
Apache Hudi集成Spark SQL操作hide表
Nginx工作模式及代理配置的使用细节
nginx常用配置conf的示例代码详解
Mar 21 #Servers
Nginx设置HTTPS的方法步骤 443证书配置方法
nginx共享内存的机制详解
Nginx的基本概念和原理
You might like
基于php权限分配的实现代码
2013/04/28 PHP
PHP return语句另类用法不止是在函数中
2014/09/17 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
CI框架(CodeIgniter)实现的导入、导出数据操作示例
2018/05/24 PHP
异步加载script的代码
2011/01/12 Javascript
JavaScript实现俄罗斯方块游戏过程分析及源码分享
2015/03/23 Javascript
浅谈javascript事件取消和阻止冒泡
2015/05/26 Javascript
jQuery实现的简单折叠菜单(折叠面板)效果代码
2015/09/16 Javascript
浅谈AngularJS中ng-class的使用方法
2016/11/11 Javascript
微信小程序-详解数据缓存
2016/11/24 Javascript
JS使用面向对象技术实现的tab选项卡效果示例
2017/02/28 Javascript
微信小程序实现移动端滑动分页效果(ajax)
2017/06/13 Javascript
vue中for循环更改数据的实例代码(数据变化但页面数据未变)
2017/09/15 Javascript
React Form组件的实现封装杂谈
2018/05/07 Javascript
Vue与Node.js通过socket.io通信的示例代码
2018/07/25 Javascript
微信小程序使用 vant Dialog组件的正确方式
2020/02/21 Javascript
Vue中使用better-scroll实现轮播图组件
2020/03/07 Javascript
JavaScript数组排序功能简单实现
2020/05/14 Javascript
Antd下拉选择,自动匹配功能的实现
2020/10/24 Javascript
ant design中upload组件上传大文件,显示进度条进度的实例
2020/10/29 Javascript
python使用PyGame模块播放声音的方法
2015/05/20 Python
python 接口返回的json字符串实例
2018/03/27 Python
详解python中的线程与线程池
2019/05/10 Python
Python格式化字符串f-string概览(小结)
2019/06/18 Python
python之yield和Generator深入解析
2019/09/18 Python
如何给Python代码进行加密
2020/01/10 Python
HTML5是否真的可以取代Flash
2010/02/10 HTML / CSS
天猫精选:上天猫,就够了
2016/09/21 全球购物
如何配置、使用和清除Smarty缓存
2015/12/23 面试题
大一新生学期自我评价
2014/04/09 职场文书
毕业生求职信
2014/06/10 职场文书
2015年社区文体活动总结
2015/03/25 职场文书
给朋友的道歉短信
2015/05/12 职场文书
详解Spring事件发布与监听机制
2021/06/30 Java/Android
Java中生成微信小程序太阳码的实现方案
2022/06/01 Java/Android