去年4月Databricks在Spark+AI summit上公布了Delta Lake项目,于此同时在Apache社区也有两个非常类似的项目Apache Iceberg和Apache Hudi在锐意开发中,这3个项目不管是在定位还是在功能方面都非常的类似,在大数据发展到现阶段为什么会涌现出这3个类似的项目呢,他们有什么差别呢?本文将从几个方面来介绍为什么我们需要这样一种技术,以及在这3个项目中为何我选择Apache Iceberg。
Delta Lake将其定义为:
Delta Lake is an open-source storage layer that brings ACIDtransactions to Apache Spark and big data workloads.
而Apache Iceberg将其定义为:
Apache Iceberg is an open table format for huge analytic datasets.
首先,这类技术它的定位是在计算引擎之下,又在存储之上。其次,它是一种数据存储格式,Delta Lake称其为'storage layer',而Iceberg则称其为'table format'。在我看来,这类技术是介于计算引擎和数据存储格式中间的数据组织格式 - 通过特定的方式将数据和元数据组织起来,因此称之为数据组织格式更为合理,而Iceberg将其定义为表格式也直观地反映出了它的定位和功能,下文将此类技术统称为'表格式”。
说完了什么是表格式,接下来我们将从两个方面来介绍为什么需要表格式。
从Hadoop诞生到现在,数据的存储格式经历了几代的发展,从最初的txt file,到后来的sequence file,rcfile,再到现在的ORC,Parquet等列式存储文件,数据的存储格式发生了翻天覆地的变化,更好的性能、更高的压缩比。然而数据组织方式的发展却相当缓慢。
Hive提出了分区的概念 - 利用某几个column作为分区值来组织数据,能够有效地过滤掉无需读取的数据,这种分区在物理存储上反映出来的就是按照文件夹进行分区(组织)数据。利用文件夹来组织与HDFS的文件系统结构有天然的亲和性,因此这一方式也一直被沿用下来,但是这种数据的组织方式真的没有改进的空间了吗?
随着大数据和云计算的结合,越来越多的底层存储系统从HDFS这样的分布式文件系统换成了云上的对象存储系统,而这种利用文件夹来组织数据的方式在对象存储上遇到了极大的挑战。
那么是否能有一种新的数据组织方式对于对象存储等云存储有更好的亲和性呢?
也是从Hive开始在大数据领域提出了metastore的集中式服务来来提供元数据管理的能力,集中式的元数据服务能够更好地管理整个数仓的元数据信息,但也带来了几个问题:
为此,是否能够将数据和元数据有效地组织在一起来避免上面的问题呢?
摘抄至Iceberg官网:
Apache Iceberg is an open table format for huge analytic datasets. Iceberg adds tables to Presto and Spark that use a high-performance format that works just like a SQL table.
Iceberg是一个通用的表格式(数据组织格式),它可以适配Presto,Spark等引擎提供高性能的读写和元数据管理功能。那Iceberg有什么优势呢?
ACID是现如今表格式的基本能力,Delta Lake、Hudi和Iceberg都提供了ACID能力,由ACID能力所衍生出来的row level update/delete更是这些表格式最吸引人的特性。
Iceberg提供了锁的机制来提供ACID的能力,在每次元数据更新时它会从Hive metastore中获取锁并进行更新。同时Iceberg保证了线性一致性(Serializable isolation),确保表的修改操作是原子性的,读操作永远不会读到部分或是没有commit的数据。Iceberg提供了乐观锁的机制降低锁的影响,并且使用冲突回退和重试机制来解决并发写所造成的冲突问题。
基于ACID的能力,Iceberg提供了类似于MVCC的读写分离能力:
相比于Hudi,Delta Lake,Iceberg提供了更为完整的表格式的能力、类型的定义和操作的抽象,并与上层数据处理引擎和底层数据存储格式的解耦。
相比于Hudi,Delta Lake,Iceberg在设计之初并没有绑定某种特定的存储引擎,同时避免了与上层引擎之间的相互调用,使得Iceberg可以非常容易地扩展到对于不同引擎的支持。
Iceberg支持in-place table evolution,用户可以像SQL那样修改表的schema,或者修改分区方式。Iceberg无需用户重写表数据或者是迁移到新表上。
Iceberg支持如下这些schema修改操作:
同时Iceberg确保schema evolution是独立且没有副作用的。
Iceberg可以在已有的表上更新分区信息,因为查询语句并不直接引用分区值。同时Iceberg提供了隐式分区能力,因此用户无须利用分区信息来刻意构造一些query使得查询能够加速。相反,Iceberg可以根据用户的query来自动地进行partition pruning,从而过滤掉不需要的数据。
另外,在Iceberg中partition evolution是一个元数据操作,因此并不需要进行文件的重写。
既然说到了Iceberg的隐式分区功能,接下来就让我们来看一下什么是隐式分区,以及隐式分区带来的好处有哪些。
为了展示Hive和Iceberg在分区实现上的不同点,让我们首先来看一下这样一张表logs
吧。
在Hive中,分区是显式的,并且对用户呈现为column的形式,因此logs
表就会有一列称为event_date
。当我们向表插入数据时,我们必须提供event_date
列,如下所示:
INSERT INTO logs PARTITION (event_date)
SELECT level, message, event_time, format_time(event_time, 'YYYY-MM-dd')
FROM unstructured_log_source
同样的,当我们读取logs
表的时候,在event_time这个过滤条件之外我们也必须指定event_date
这样一个过滤条件来进行partition pruning。
SELECT level, count(1) as count FROM logs
WHERE event_time BETWEEN '2018-12-01 10:00:00' AND '2018-12-01 12:00:00'
AND event_date = '2018-12-01'
如果我们没有指定event_date
这样一个过滤条件,那么Hive就会扫描全表来匹配event_time
这个过滤条件。这是因为Hive并不知道event_time
这一列和event_date
是相关的。
这就是显式分区,这样的分区方式有什么问题呢?
与Hive不同的是,Iceberg通过column的值来自动地计算分区值,而无需用户生成,Iceberg负责将event_time
转换成event_date
,并且跟踪两者的映射关系。
正因为Iceberg无须用户来维护“分区列”,因此它可以隐藏分区。每次写入和读取可以正确地生成分区值并有效地进行分区过滤,用户甚至无需知道有event_date
这样一列的存在。
更重要的是,由于有了隐式分区这样的功能,query不再依赖于表的物理组织方式,从而Iceberg表可以根据数据的大小及聚合程度动态地修改分区策略而无需重写表。
当然Iceberg还有许多其他的优势,比如对象存储友好的数据组织方式,在数据存储格式之上的统一的向量化读取(基于Arrow实现),完备的算子下推等等关于表结构的核心能力,就不在这一一赘述了。
说了那么多Iceberg的优势,那Iceberg后面的发展是什么呢,还有什么能力是缺失的吗?
当然Iceberg还有许多的特性功能需要添加,尤其是围绕生态系统的建立和周边能力的打造上还需要更多的发展。
本文从表格式这样一种技术的出现、发展来介绍表格式其存在的价值和意义,同时也着重介绍了Iceberg这样一个表格式的技术它的优势以及未来的发展,我相信未来“表格式”这种技术定会在大数据领域被广泛采用,而Iceberg作为一种优秀的实践也必会被大量的采用。
联系客服