首页 > IT职业 > IT职场 > Apache Hudi和Presto的前世今生
upserts、
deletes和增量查询等原语将流式能力带入了批处理。这些特性使得统一服务层可提供更快、更新鲜的数据。Hudi表可存储在Hadoop兼容的分布式文件系统或者云上对象存储中,并且很好的集成了
Presto,
Apache Hive,
Apache Spark 和
Apache Impala。Hudi开创了一种新的模型(数据组织形式),该模型将文件写入到一个更受管理的存储层,该存储层可以与主流查询引擎进行互操作,同时在项目演变方面有了一些有趣的经验。
| Trade-off | CopyOnWrite | MergeOnRead |
|---|---|---|
| 数据延迟 | 更高 | 更低 |
| 更新开销 (I/O) | 高(重写整个parquet文件) | 更低 (写入增量日志文件) |
| Parquet文件大小 | 更小(高update (I/0) 开销) | 更大 (低updaet开销) |
| 写放大 | 更低 (决定与Compaction策略) |
|
| Trade-off | 快照 | 读优化 |
|---|---|---|
| 数据延迟 | 更低 | 更高 |
| 查询延迟 | COW: 与parquet表相同。 MOR: 更高 (合并基础/列式文件和行存增量文件) | 与COW快照查询有相同列式查询性能 |
@UseFileSplitsFromInputFormat。任何注册的Hive表(如果有此注解)都将通过调用相应的inputformat的
getSplits()方法(而不是Presto Hive原生切片加载逻辑)来获取切片。通过Presto查询的Hudi表,只需简单调用
HoodieParquetInputFormat.getSplits(). 集成非常简单只,需将相应的Hudi jar包放到
<presto_install>/plugin/hive-hadoop2/目录下。它支持查询COW Hudi表,并读取MOR Hudi表的优化查询(只从压缩的基本parquet文件中获取数据)。在Uber,这种简单的集成已经支持每天超过100000次的Presto查询,这些查询来自使用Hudi管理的HDFS中的100PB的数据(原始数据和模型表)。inputformat.getSplits()是个简单的集成,但是可能会导致对NameNode的大量RPC调用,以前的集成方法有几个缺点。loadPartition()调用),
HoodieParquetInputFormat.getSplits()将被调用。这导致了冗余的Hudi表元数据Listing,其实可以被属于从查询扫描的表的所有分区复用。BackgroundHiveSplitLoader构造函数中实例化
HoodieTableMetadata一次。然后我们利用Hudi Api过滤分区文件,而不是调用
HoodieParquetInputFormat.getSplits(),这大大减少了该路径中NameNode调用次数。DirectoryLister接口中添加了一个新的API,它将接受
PathFilter对象。对于Hudi表,我们提供了这个PathFilter对象
HoodieROTablePathFilter,它将负责过滤为查询Hudi表而预先列出的文件,并获得与Uber内部解决方案相同的结果。InputFormat类来实现,该类提供了处理切片的方法,并引入了一个新的
RecordReader类,该类可以扫描切片以获取记录。对于使用Hive查询MOR Hudi表,在Hudi中已经有类似类可用:InputFormat -
org.apache.hudi.hadoop.realtime.HoodieParquetRealtimeInputFormatInputSplit -
org.apache.hudi.hadoop.realtime.HoodieRealtimeFileSplitRecordReader -
org.apache.hudi.hadoop.realtime.HoodieRealtimeRecordReader 在Presto中支持这一点需要理解Presto如何从Hive表中获取记录,并在该层中进行必要的修改。因为Presto使用其原生的
ParquetPageSource而不是InputFormat的记录读取器,Presto将只显示基本Parquet文件,而不显示来自Hudi日志文件的实时更新,后者是avro数据(本质上与普通的读优化Hudi查询相同)。HiveSplit的一个额外的字段。但这并不起作用,因为复杂的切片不可序列化,而且还会复制基本切片数据。CustomSplitConverter接口。它接受一个自定义切片并返回一个易于序列化的String->String Map,其中包含来自自定义切片的额外数据。为了实现这点,我们还将此Map作为一个附加字段添加到Presto的HiveSplit中。我们创建了
HudiRealtimeSplitConverter来实现用于Hudi实时查询的
CustomSplitConverter接口。HoodieRealtimeFileSplit。
CustomSplitConverter接口还有另一个方法,它接受普通的FileSplit和额外的split信息映射,并返回实际复杂的FileSplit,在本例中是
HudiRealtimeFileSplit。HoodieParquetRealtimeInputFormat中的
HoodieRealtimeRecordReader读取重新创建的
HoodieRealtimeFileSplit。Presto需要使用新的记录读取器来正确处理
HudiRealtimeFileSplit中的额外信息。为此,我们引入了与第一个注释类似的另一个注解
@UseRecordReaderFromInputFormat。这指示Presto使用Hive记录光标(使用
InputFormat的记录读取器)而不是
PageSource。Hive记录光标可以理解重新创建的自定义切片,并基于自定义切片设置其他信息/配置。JobConf中设置一些配置来支持增量查询,例如-query mode设置为
INCREMENTAL、启动提交时间和要使用的最大提交数。在Spark中有一个特定的实现来支持增量查询—
IncrementalRelation。为了在Presto中支持这一点,我们需要一种识别增量查询的方法。如果Presto不向hadoop Configuration对象传递会话配置,那么最初的想法是在metastore中将同一个表注册为增量表。然后使用查询谓词获取其他详细信息,如开始提交时间、最大提交时间等。listStatus操作以获得文件系统的当前视图。在Uber,HDFS基础设施为Listing做了大量优化,但对于包含数千个分区的大型数据集以及每个分区在云/对象存储上有数千个文件的大型数据集来说,这可能是一个昂贵的操作。上面的RFC工作旨在消除Listing操作,提供更好的查询性能和更快的查找,只需将Hudi的时间轴元数据逐渐压缩到表状态的快照中。HoodieIndex在分区或非分区数据集中提供记录id到文件id的映射,实现有BloomFilters/Key ranges(用于临时数据)和Apache HBase(用于随机更新)支持。许多用户发现Apache HBase(或任何类似的key-value-store-backed索引)很昂贵,并且增加了运维开销。该工作试图提出一种新的索引格式,用于记录级别的索引,这是在Hudi中实现的。Hudi将存储和维护记录级索引(有HFile、RocksDB等可插拔存储实现支持)。这将被writer(摄取)和reader(摄取/查询)使用,并将显著提高upsert性能,而不是基于join的方法,或者是用于支持随机更新工作负载的布隆索引。这是查询引擎在列出文件之前修剪文件时可以利用这些信息的另一个领域。我们也在考虑一种在查询时利用Presto中的元数据的方法。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69984138/viewspace-2723228/ ,如需转载,请注明出处,否则将追究法律责任。