草庐IT

Iceberg在袋鼠云的探索及实践

数栈DTinsight 2023-03-28 原文

“数据湖”、“湖仓一体”及“流批一体”等概念,是近年来大数据领域热度最高的词汇,在各大互联网公司掀起了一波波的热潮,各家公司纷纷推出了自己的技术方案,其中作为全链路数字化技术与服务提供商的袋鼠云,在探索数据湖架构的早期,就调研并选用了Iceberg作为基础框架,在落地过程中深度使用了Iceberg并进行了部分改造,在这个过程中,我们积累出了一些经验和探索实践,希望通过本篇文章与大家分享,也欢迎大家一起共同讨论。

一、为什么选择Iceberg

Iceberg作为Apache基金会下的一个顶级项目,是业界公认的开源数据湖实现方案之一,考虑到任何概念的提出本质上是源于底层软硬件技术或架构上取得了新的突破,我们首先站在技术演进的角度对Iceberg的出现契机和应用场景进行分析。

01 大数据存储技术现状

2006年Hadoop框架横空出世,改变了企业对数据的存储、处理和分析的认知,加速了大数据的发展,形成了完善的生态圈。工程师们将庞杂的历史数据存在分布式文件系统HDFS中,通过Hive、Spark等进行加速计算处理。至今为止,HDFS已然成为广泛应用的大数据基础组件。

在这个大数据技术发展过程中,也面临着一些问题。在Hive中,将表绑定为HDFS上的一个目录,通过HiveMetaStore记录其绑定的存储位置,计算引擎查询数据时请求主节点获取文件并读取,这天然缺少事务保证:某个用户写入的文件其他用户立即可见,没有隔离性;即便先写入到隐藏文件中,待事务提交后再全部改名可见,因为一批文件的改名不是原子操作,这只能保证分区级别的原子性。随着对象存储的广泛应用,通过主节点去获取全部文件有比较大的性能损耗,因为对象存储的“List”性能较差。

经过以上分析,我们发现Hive中这种设计的缺陷在于缺乏对表数据文件的管理维护:对于表中不同时刻包含的数据文件,都要即时访问HDFS主节点获取,这样子就造成了比较大的资源浪费。

而数据湖却能很好的解决这一问题,数据湖是一个集中各种形式和来源数据的存储区域,存储内容虽然种类繁多却管理有序,对数据文件的组织维护能够高效地帮助我们对接各类底层存储和上层计算。

02 数据湖技术选型——Iceberg

我们知道问题的关键在于“对表数据文件的管理维护”,基于此就可以开展技术选型了。在2020年末,技术团队做了众多技术方案的调研,包括包括Delta LakeHudiIceberg,我们最终选用了Iceberg。

而选择Iceberg的原因,正是基于袋鼠云的技术栈的具体情况做了充足考虑:袋鼠云中的离线计算、实时计算、智能标签等应用,在计算层需要依托Spark、Flink、Trino等多种引擎为客户解决不同的业务诉求,在底层则可能需要对接客户自建云、公有云等混合存储。这就要求所选择的技术方案必须能满足对接多种类型的需求。

Iceberg具备接口开放、易于拓展的优点,十分符合我们的选型要求。在存储层HDFS上增加一个中间层Iceberg以跟踪数据文件,不必改变其他层的架构设计,就可以享受到Iceberg对数据文件管理带来的极速体验与美妙特性。下图展示了袋鼠云基于Iceberg框架的数据湖架构设计:

基于前述关键点,我们介绍下Iceberg的设计,参考下图所示:

Iceberg在数据文件的基础上增加了文件清单和文件快照等索引,通过这些索引我们就能跟踪到每张表在当前时刻有哪些数据文件,这就解决了前文提到的Hive中的设计缺陷:某个用户写入的临时文件不会被其他用户读取到,因为这些文件没有被快照记录;每个事务修改跟踪的数据文件时,需要向锁服务进行申请,成功获取到锁许可之后可以更新快照内容,一次快照修改可以增加多个文件,这样就保证原子性;预先记录好目录下的每个数据文件可以避免对HDFS主节点的多次访问,对云存储友好。

二、Iceberg在袋鼠云中的应用实践

01 行级更新

在Hive中想要对历史数据进行订正,需要用增量数据合并历史数据后替换历史数据,这种方式的代价是比较大的,即便是很少的更新也需要对全表或者整个分区进行扫描。

利用Iceberg这种合并和覆写可以被推迟,如下图所示:

在Iceberg中,可以写入一份标记删除的数据文件并再写入更新后的数据文件,这样的好处是订正历史数据时用户在数栈平台的操作等待时间会很短,在查询的时候再对这个标记删除文件中的数据进行更新,准确查找到更新之后的数据。而实际对数据文件内容合并的耗时操作推迟在用户休息的时候,保证了后续操作的性能。

02 查询加速

在HDFS上,数据文件通常采用Parquet、ORC等存储格式,这些存储格式中记录了诸如列最大值/最小值/空值等详细的元数据信息,因此在进行查询的过程中,Iceberg充分利用了存储格式提供的元数据信息进行文件过滤。

用户在数栈平台写入数据时,在文件清单中汇总了每个文件中保存数据每一列的最大值/最小值/空值信息。在查询数据时,对查询条件和汇总信息进行交集判断,对于没有交集的文件就不需要再去读取了,这样就能够极大的减少需要读取的文件数量。

考虑到数据文件的分布是在写入时决定的,在写入数据顺序不规律的情况下,文件中的最大值/最小值范围跨度会很大,这样并集判断过滤的效果就没有那么明显了,这时候在数栈平台上按照一定规则对数据进行重排列,使得具有相似特征的数据落入到同一个数据文件里,这样提取出来的最大值/最小值信息就会在更接近的范围里,查询过滤性能会有更大提升。

03 自动治理

在Iceberg的写入过程中,为了支持快速写入和数据跟踪等功能,其代价是会在每次操作引入不同数量的小文件,这些小文件会随着时间的前进而不断拖延系统的效率,必须要通过合并操作进行删除才能继续保证系统的高效。

Iceberg本身提供了文件合并、快照清理等工具,但这需要用户手动去启动任务才能触发,对于使用者来说是额外心智负担。

如上图所示,袋鼠云在产品设计上为用户屏蔽了这种运维上的复杂度,用户只需要对表进行基本参数的设置就可以享受新框架优化后带来的快速和便捷,而更复杂的文件治理任务的启动和资源配置都交由后台程序监控完成。

三、袋鼠云基于Iceberg的改造

除了对Iceberg本身提供的能力进行应用,袋鼠云还根据生产场景的要求对Iceberg做了一定的改造。

01 列更新

在袋鼠云标签引擎中经常有需要根据原子指标生成派生指标的场景,在后台程序中就是为一张大宽表增加新的字段并且填入数据。在过去,我们依赖OverWrite操作在HDFS上重写新的表数据,然而这种操作都需要将全部字段数据进行写入,非常消耗存储和时间的(想象一下一张表有几百个字段,每次都需要重新写入)。

基于Iceberg袋鼠云设计了一种优化方案,如上图所示:保留原来的数据文件,列更新时将新的字段数据和表的主键字段数据一起写入到新的数据文件。这样,在写入过程中需要写入的数据量就大大减少了,而在读取过程中,再将新字段和原有的字段做一次合并,这样就能够保证数据的准确性。同时我们还会在查询时只读取包含查询字段的文件以提高查询性能。

当然,在多次添加新字段之后,每次查询中包含的合并操作就多了,性能就会随之下降,这就需要结合前述的文件合并功能,定时进行数据合并,这样更新累计的副作用就可以消除了。

02 批流一体

批流一体在存储上要解决的很重要的问题是:离线数仓依赖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——提供面向湖仓一体的数据湖管理分析服务。基于统一的元数据抽象构建一致性的数据访问,提供海量数据的存储管理和实时分析处理能力,可以帮助企业快速构建湖仓一体化平台,完成数字化基础建设。

未来我们还会对数据湖和湖仓一体架构做更多的探索和应用,敬请期待。

欢迎大家了解或咨询更多有关数据湖产品的信息
想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网:https://www.dtstack.com/?src=szbky

同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术qun」,交流最新开源技术信息,qun号码:30537511,项目地址:https://github.com/DTStack

有关Iceberg在袋鼠云的探索及实践的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  3. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  4. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  5. Ruby 最佳实践 : working with classes - 2

    参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin

  6. ruby - 存储外部 API 的密码 - 最佳实践 - 2

    如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。

  7. ruby-on-rails - 使用设计身份验证的 API 访问 - 最佳实践? - 2

    我正在使用Devise在Rails应用程序中,并希望通过API公开一些模型数据,但应该像应用程序一样限制对API的访问。$curlhttp://myapp.com/api/v1/sales/7.json{"error":"Youneedtosigninorsignupbeforecontinuing."}很明显。在这种情况下是否有访问API的最佳实践?我更喜欢一步验证+获取数据,但这只是为了让客户的工作更轻松。他们将使用JQuery在客户端提取数据。感谢您提供任何信息!凡妮莎 最佳答案 我建议您按照以下帖子中的选项2:使用APIke

  8. ruby-on-rails - 在多个页面上使用相同表单的 Rails 最佳实践 - 2

    我正在开发一个Rails2.3.1网站。在整个网站中,我需要一个用于在各种页面(主页、创建帖子页面、帖子列表页面、评论列表页面等)上创建帖子的表单——只要说这个表单需要在由各种Controller)。这些页面中的每一个都显示在相应的Controller/操作中检索到的各种其他信息。例如,主页列出了最新的10篇文章、从数据库中提取的内容等。因此,我已将帖子创建表单移动到它自己的部分中,并将该部分包含在所有必要的页面中。请注意,部分POST中的表单到/questions(路由到PostsController::create——这是默认的Rails行为)。我遇到的问题是当Posts表单没有正

  9. ruby-on-rails - Rails 'service objects' 最佳实践 - 类方法或实例化 - 2

    我正在按照我一直在研究的研讨会实现“服务对象”,我正在构建一个redditAPI应用程序。我需要对象返回一些东西,所以我不能只执行初始化程序中的所有内容。我有这两个选择:选项1:类需要实例化classSubListFromUserdefuser_subscribed_subs(client)@client=client@subreddits=sort_subs_by_name(user_subs_from_reddit)endprivatedefsort_subs_by_name(subreddits)subreddits.sort_by{|sr|sr[:name].downcase}

  10. 美团外卖搜索基于Elasticsearch的优化实践 - 2

    美团外卖搜索工程团队在Elasticsearch的优化实践中,基于Location-BasedService(LBS)业务场景对Elasticsearch的查询性能进行优化。该优化基于Run-LengthEncoding(RLE)设计了一款高效的倒排索引结构,使检索耗时(TP99)降低了84%。本文从问题分析、技术选型、优化方案等方面进行阐述,并给出最终灰度验证的结论。1.前言最近十年,Elasticsearch已经成为了最受欢迎的开源检索引擎,其作为离线数仓、近线检索、B端检索的经典基建,已沉淀了大量的实践案例及优化总结。然而在高并发、高可用、大数据量的C端场景,目前可参考的资料并不多。因此

随机推荐