Hudi
Hudi是Hadoop Updates and Incrementals的缩写,用于管理HDFS上的大型分析数据集存储,主要目的是高效的减少入库延时。Hudi是一个开源Spark三方库,支持在Hadoop上执行upserts/insert/delete操作。Hudi数据集通过自定义的InputFormat与当前的Hadoop生态系统(Hive、parquet、spark)集成,使该框架对最终用户来说是无缝的。
Kudu
Kudu是cloudera开源的运行在hadoop平台上的列式存储系统,拥有Hadoop生态系统应用的常见技术特性,运行在一般的商用硬件上,支持水平扩展,高可用,目前是Apache Hadoop生态圈的新成员之一(incubating)。Kudu定位于应对快速变化数据的快速分析型数据仓库,希望靠系统自身能力,支撑起同时需要高吞吐率的顺序和随机读写的应用场景,提供一个介于HDFS和HBase的性能特点之间的一个系统,在随机读写和批量扫描之间找到一个平衡点,并保障稳定可预测的响应延迟。可与MapReduce, Spark和其它hadoop生态系统集成。
Delta Lake
Delta Lake是一个开源存储层,为数据湖带来了可靠性。Delta Lake提供了ACID事务、可伸缩的元数据处理以及统一的流和批数据处理。通过写和快照隔离之间的乐观并发控制(optimistic concurrency control),在写入数据期间提供一致性的读取,从而为构建在 HDFS 和云存储上的数据湖(data lakes)带来可靠性。Delta Lake 还提供内置数据版本控制,以便轻松回滚。
kudu、hudi和delta lake是目前比较热门的支持行级别数据增删改查的存储方案,通过存储机制、读数据、更新数据等方面进行比较。
存储机制
- hudi
hudi维护了一个时间轴,记录了在不同时刻对数据集进行的所有操作。
hudi拥有2种存储优化,读优化适合读多写少的场景,写优化适合读少写多的场景。
-
- 读优化(Copy On Write):在每次commit后都将最新的数据compaction成列式存储(parquet);
- 写优化(Merge On Read):对增量数据使用行式存储(avro),后台定期将它compaction成列式存储。
- kudu
kudu的存储机制和hudi的写优化方式有些相似。
kudu的最新数据保存在内存,称为MemRowSet(行式存储,基于primary key有序),
当MemRowSet写满(默认1G或者120s)后flush到磁盘,形成DiskRowSet(列式存储)。
DiskRowSet包含baseData与DeltaStores两部分,DeltaStores包含一个DeltMemStore和多个DeltaFile,
后续的更新数据存放在DeltMemStore中,增长到一定程度后flush成DeltaFile文件。
kudu会定期执行compaction操作,将DeltaFile中的更新合并到DiskRowSet,或者合并DiskRowSet,清除已删除的数据,并减少DiskRowSet的数量。
- delta lake
delta lake的存储机制和hudi的读优化方式相似。
delta lake的数据不会保存在内存中,而是直接写到新的数据文件中(parquet格式),同时在commit log中添加AddFile这种FileAction,快照新建/更新时读取事务日志,会加载新的数据文件信息。
读数据
- hudi
hudi也维护着一个索引,以此将key快速映射到对应的fileId。索引的实现是插件式的,默认是bloomFilter,也可以使用HBase。
hudi提供3种查询视图。
-
- 读优化视图:仅提供compaction后的列式存储的数据;
- 增量视图:仅提供一次compaction/commit前的增量数据;
- 实时视图:包括列式存储数据和写优化的行式存储数据。
- kudu
先根据要扫描数据的主键范围,定位到目标的tablets,然后读取tablets中的DiskRowSet。
在读取每个DiskRowSet时,先根据主键过滤要scan的范围,然后加载范围内的baseData,再找到对应的DeltaStores,
应用所有变更,最后union上MemRowSet中的内容,最后返回数据给client。
kudu提供range分区和hash分区两种分区方式,通过多种索引(主键范围索引、bloomfilter、主键索引),支持随机读取数据和高效的批量读取数据。
- delta lake
通过读取事务日志的checkpoint文件(parquet格式)和之后版本的commit文件(json格式),
建立当前最新的快照,该快照包含了当前版本所有数据文件的地址,然后使用spark读取数据。
更新数据
- hudi
hudi没有传统意义的更新,只有append和重写。
hudi写数据的时候需要指定以下3个key。
-
- RECORDKEY_FIELD_OPT_KEY:每条记录的唯一id,支持多个字段;
- PRECOMBINE_FIELD_OPT_KEY:在数据合并的时候使用到,当RECORDKEY_FIELD_OPT_KEY相同时,默认取PRECOMBINE_FIELD_OPT_KEY属性配置的字段最大值所对应的行;
- PARTITIONPATH_FIELD_OPT_KEY:用于存放数据的分区字段。
hudi更新数据和插入数据很相似(写法几乎一样),更新数据时,会根据以上三个字段对数据进行Merge。
- kudu
client向master发出请求,通过索引定位到具体的tablet,然后根据元数据连接tablet对应的tserver。
若数据在磁盘(DiskRowSet)上,则将更新信息写入DeltMemStore中,若数据在内存(MemRowSet)中,则将信息写入所在行的mutation链表中。
- delta lake
delta lake更新数据时会先定位待更新数据所在的文件,使用spark join获得结果数据集,将更新后的数据和文件中其他不需要更新的数据一起写入到新的文件里,同时在commit log中记录AddFile(新文件)和RemoveFile(旧文件)两种action。
kudu、hudi和delta lake对比
— | kudu | hudi | delta lake |
---|---|---|---|
行级别更新 | 支持 | 支持 | 支持 |
schema修改 | 支持 | 支持 | 支持 |
批流共享 | 支持 | 支持 | 支持 |
使用索引 | 是 | 是 | 否 |
多作业并发写 | 允许 | 不允许 | 允许 |
元数据位置 | master | 根目录文件夹 | 根目录文件夹 |
版本回滚 | 不支持 | 通过设置增量视图的INSTANTTIME范围,支持版本回滚 | 自带Time Travel功能,支持版本回滚 |
实时性 | kudu使用内存存储新增数据,实时性相对较高 | hudi有写优化存储方式,能达到1-5分钟延迟的近实时处理 | delta lake必须完成commit提交才能查询到新增数据,实时性差 |
支持hadoop文件系统 | 不支持,kudu通过raft管理自己的存储服务器 | 支持 | 支持 |
缺省列处理 | 默认为null | hudi在插入时必须指定所有字段,否则报错 | 默认为null |
并发读写 | 支持 | 不支持多客户端同时写 | 支持 |
兼容性 | 与impala集成支持sql,支持spark读写 | 支持spark、presto、hive、mapreduce,兼容性较好 | 深度依赖spark,目前有限支持hive、presto,有待完善 |
选择合适的存储方案
- kudu
- 不同于hudi和delta lake是作为数据湖的存储方案,kudu设计的初衷是作为hive和hbase的折中,因此它同时具有随机读写和批量分析的特性。
- kudu允许对不同列使用单独的编码和压缩格式,拥有强大的索引支持,搭配range分区和hash分区的合理划分,
对分区查看、扩容和数据高可用性的支持都非常好,适用于既有随机访问,也有批量数据扫描的复合场景。 - kudu可以和impala、spark集成,支持sql操作,除此之外,kudu能够充分发挥高性能存储设备的优势。
- 相比较其他两者,kudu不支持云存储,也不支持版本回滚和增量处理。
- hudi
- hudi的产生背景是为了解决Uber的增量更新问题,它提供了丰富的视图和存储优化方式,
可以适配批量访问场景,增量处理场景,以及近实时查询场景,无论是读多写少还是读少写多,hudi都能提供对应的优化方案,
用户可以根据自身场景灵活选择合适的配置。 - 三者之中,hudi的兼容性最好,它原生支持spark、presto、hive和mapreduce等大数据生态系统,并且读写底层文件实现了自己的InputFormat,更容易与其它系统做兼容。
- hudi目前还不支持通过sql操作数据,(19年12月)社区已经将其作为下一步的方向,但完成时间不确定。
- hudi不存在锁机制,因此不支持多客户端同时写一张表,这是需要注意的一点。
- delta lake
- delta lake深度绑定spark,支持版本回滚,在写入的时候对数据进行合并,因此对读取比较友好。
- delta lake有乐观锁机制,允许并发写操作。但目前源码中对冲突检测很严格,对多用户同时更新的场景支持并不好,适用于写少读多(或者only append写多更新少)的场景。
- delta lake开源版目前基本不支持sql操作数据(0.5版本支持hive和presto读数据),应该在spark3.0发布后才会支持delete、update和merge操作。
- 开源版目前还存在小文件合并问题(商业版有优化,但是因为涉及到Databricks的Runtime功能,所以不准备开源,因此得自己手动合并小文件)。
- 总体来说,delta lake是一个较为优秀的数据湖存储方案,但直接使用开源版本还需要用户稍微进行一些针对性的优化。