“数据湖”、“湖仓一体”及“流批一体”等概念,是近年来大数据领域热度最高的词汇,在各大互联网公司掀起了一波波的热潮,各家公司纷纷推出了自己的技术方案,其中作为全链路数字化技术与服务提供商的袋鼠云,在探索数据湖架构的早期,就调研并选用了Iceberg作为基础框架,在落地过程中深度使用了Iceberg并进行了部分改造,在这个过程中,我们积累出了一些经验和探索实践,希望通过本篇文章与大家分享,也欢迎大家一起共同讨论。
为什么选择Iceberg
Iceberg作为Apache基金会下的一个顶级项目,是业界公认的开源数据湖实现方案之一,考虑到任何概念的提出本质上是源于底层软硬件技术或架构上取得了新的突破,我们首先站在技术演进的角度对Iceberg的出现契机和应用场景进行分析。
大数据存储技术现状
2006年Hadoop框架横空出世,改变了企业对数据的存储、处理和分析的认知,加速了大数据的发展,形成了完善的生态圈。工程师们将庞杂的历史数据存在分布式文件系统HDFS中,通过Hive、Spark等进行加速计算处理。至今为止,HDFS已然成为广泛应用的大数据基础组件。
在这个大数据技术发展过程中,也面临着一些问题。在Hive中,将表绑定为HDFS上的一个目录,通过HiveMetaStore记录其绑定的存储位置,计算引擎查询数据时请求主节点获取文件并读取,这天然缺少事务保证:某个用户写入的文件其他用户立即可见,没有隔离性;即便先写入到隐藏文件中,待事务提交后再全部改名可见,因为一批文件的改名不是原子操作,这只能保证分区级别的原子性。随着对象存储的广泛应用,通过主节点去获取全部文件有比较大的性能损耗,因为对象存储的“List”性能较差。
经过以上分析,我们发现Hive中这种设计的缺陷在于缺乏对表数据文件的管理维护:对于表中不同时刻包含的数据文件,都要即时访问HDFS主节点获取,这样子就造成了比较大的资源浪费。
而数据湖却能很好的解决这一问题,数据湖是一个集中各种形式和来源数据的存储区域,存储内容虽然种类繁多却管理有序,对数据文件的组织维护能够高效地帮助我们对接各类底层存储和上层计算。
数据湖技术选型——Iceberg
知道问题的关键在于“对表数据文件的管理维护”,基于此就可以开展技术选型了。在2020年末,技术团队做了众多技术方案的调研,包括包括Delta Lake、Hudi、Iceberg,我们最终选用了Iceberg。
而选择Iceberg的原因,正是基于袋鼠云的技术栈的具体情况做了充足考虑:袋鼠云中的离线计算、实时计算、智能标签等应用,在计算层需要依托Spark、Flink、Trino等多种引擎为客户解决不同的业务诉求,在底层则可能需要对接客户自建云、公有云等混合存储。这就要求所选择的技术方案必须能满足对接多种类型的需求。
Iceberg具备接口开放、易于拓展的优点,十分符合我们的选型要求。在存储层HDFS上增加一个中间层Iceberg以跟踪数据文件,不必改变其他层的架构设计,就可以享受到Iceberg对数据文件管理带来的极速体验与美妙特性。下图展示了袋鼠云基于Iceberg框架的数据湖架构设计:
基于前述关键点,我们介绍下Iceberg的设计,参考下图所示:
Iceberg在数据文件的基础上增加了文件清单和文件快照等索引,通过这些索引我们就能跟踪到每张表在当前时刻有哪些数据文件,这就解决了前文提到的Hive中的设计缺陷:某个用户写入的临时文件不会被其他用户读取到,因为这些文件没有被快照记录;每个事务修改跟踪的数据文件时,需要向锁服务进行申请,成功获取到锁许可之后可以更新快照内容,一次快照修改可以增加多个文件,这样就保证原子性;预先记录好目录下的每个数据文件可以避免对HDFS主节点的多次访问,对云存储友好。
Iceberg在袋鼠云中的应用实践
行级更新
在Hive中想要对历史数据进行订正,需要用增量数据合并历史数据后替换历史数据,这种方式的代价是比较大的,即便是很少的更新也需要对全表或者整个分区进行扫描。
利用Iceberg这种合并和覆写可以被推迟,如下图所示:
在Iceberg中,可以写入一份标记删除的数据文件并再写入更新后的数据文件,这样的好处是订正历史数据时用户在数栈平台的操作等待时间会很短,在查询的时候再对这个标记删除文件中的数据进行更新,准确查找到更新之后的数据。而实际对数据文件内容合并的耗时操作推迟在用户休息的时候,保证了后续操作的性能。
查询加速
在HDFS上,数据文件通常采用Parquet、ORC等存储格式,这些存储格式中记录了诸如列最大值/最小值/空值等详细的元数据信息,因此在进行查询的过程中,Iceberg充分利用了存储格式提供的元数据信息进行文件过滤。
用户在数栈平台写入数据时,在文件清单中汇总了每个文件中保存数据每一列的最大值/最小值/空值信息。在查询数据时,对查询条件和汇总信息进行交集判断,对于没有交集的文件就不需要再去读取了,这样就能够极大的减少需要读取的文件数量。
考虑到数据文件的分布是在写入时决定的,在写入数据顺序不规律的情况下,文件中的最大值/最小值范围跨度会很大,这样并集判断过滤的效果就没有那么明显了,这时候在数栈平台上按照一定规则对数据进行重排列,使得具有相似特征的数据落入到同一个数据文件里,这样提取出来的最大值/最小值信息就会在更接近的范围里,查询过滤性能会有更大提升。
自动治理
在Iceberg的写入过程中,为了支持快速写入和数据跟踪等功能,其代价是会在每次操作引入不同数量的小文件,这些小文件会随着时间的前进而不断拖延系统的效率,必须要通过合并操作进行删除才能继续保证系统的高效。
Iceberg本身提供了文件合并、快照清理等工具,但这需要用户手动去启动任务才能触发,对于使用者来说是额外心智负担。
如上图所示,袋鼠云在产品设计上为用户屏蔽了这种运维上的复杂度,用户只需要对表进行基本参数的设置就可以享受新框架优化后带来的快速和便捷,而更复杂的文件治理任务的启动和资源配置都交由后台程序监控完成。
袋鼠云基于Iceberg的改造
除了对Iceberg本身提供的能力进行应用,袋鼠云还根据生产场景的要求对Iceberg做了一定的改造。
列更新
在袋鼠云标签引擎中经常有需要根据原子指标生成派生指标的场景,在后台程序中就是为一张大宽表增加新的字段并且填入数据。在过去,我们依赖OverWrite操作在HDFS上重写新的表数据,然而这种操作都需要将全部字段数据进行写入,非常消耗存储和时间的(想象一下一张表有几百个字段,每次都需要重新写入)。
基于Iceberg袋鼠云设计了一种优化方案,如上图所示:保留原来的数据文件,列更新时将新的字段数据和表的主键字段数据一起写入到新的数据文件。这样,在写入过程中需要写入的数据量就大大减少了,而在读取过程中,再将新字段和原有的字段做一次合并,这样就能够保证数据的准确性。同时我们还会在查询时只读取包含查询字段的文件以提高查询性能。
当然,在多次添加新字段之后,每次查询中包含的合并操作就多了,性能就会随之下降,这就需要结合前述的文件合并功能,定时进行数据合并,这样更新累计的副作用就可以消除了。
批流一体
批流一体在存储上要解决的很重要的问题是:离线数仓依赖HDFS存储,HDFS能够提供大规模的存储,成本低廉,然而其实时性比较差;实时数仓依赖Kafka存储,Kafka能够存储的数据量有限,但是能够提供非常好的实时性。两条技术链路带来了理解和使用上的困难,能否提供统一的存储是批流一体架构落地的关键。
在袋鼠云中,我们提出了一种基于Iceberg的屏蔽能力,构建的针对这两种组件的统一存储方案:底层存储混合使用Iceberg和Kafka,但对使用者只暴露一张完整的数据表,在Iceberg中记录Kafka的切换位点(偏移量),读取时根据当前数据的时间信息选择读取Kafka或者Iceberg数据源。如下图所示:
具体步骤有:
1)在创建表时,设置Iceberg存储和Kafka存储相关的元数据信息。
2)写入数据时,向两种存储介质一起写入。在Iceberg每次生成新快照时,将最后一条数据对应的Kafka偏移量写入快照信息里。用户可以选择性开始Kafka事务保证。
3)读取数据时,在最近一段时间内的数据都通过Kafka进行消费,在读取完Kafka的数据后根据偏移量切换到对Iceberg记录的HDFS文件进行访问,读取历史数据。
这样就能符合了袋鼠云用户使用不同处理速度去处理不同阶段数据的需求。
写在最后
以上就是袋鼠云基于Iceberg在数据湖的一些探索和实践,目前这种框架已应用于我们的数据湖产品DataLake——提供面向湖仓一体的数据湖管理分析服务。基于统一的元数据抽象构建一致性的数据访问,提供海量数据的存储管理和实时分析处理能力,可以帮助企业快速构建湖仓一体化平台,完成数字化基础建设。
未来我们还会对数据湖和湖仓一体架构做更多的探索和应用,敬请期待。
袋鼠云在大数据领域深耕7年,拥有丰富的大数据平台建设经验和成熟的产品体系,想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网:https://www.dtstack.com/?src=bbs
同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术群」,交流最新开源技术信息,群号码:30537511,项目地址:https://github.com/DTStack