Lakehouse: 统一data warehousing和高级分析的新一代开放平台
论文原文地址 | 发表年:2021
译者:本篇中有三个持续演进的概念,Data Warehouse(数据仓库、数仓、数据仓)、Data Lake(数据湖)、Lakehouse(湖仓)。偶尔会交换使用它们的中英文名称。
TL;DR:本篇文章处于湖仓分离的两层架构广泛使用的时期,随着当时技术的不断演进以及二层架构的各种问题的持续暴露,作者提出了使用当前的一些现存新技术构建出一种湖仓一体架构的可行性方案。
介绍

本篇论文认为,我们当前所知的data warehosue架构将在未来几年衰落,并将被一种新的架构模式替代,我们称之为——Lakehouse(湖屋、湖仓一体)。其特征是:
- 开放的、直接访问的数据格式(如Apache Parquet和ORC)
- 为机器学习和数据科学负载提供一流支持
- 最先进的性能
data warehouse的历史起源于,通过从操作型数据库(OLTP)向中心化warehouse收集数据,帮助商业领导人获得分析见解,随后,它们可以被用来进行决策支持以及商业智能(BI)。这些warehouse中的数据被做成schema-on-write的,以确保数据模型对于下游的BI消费进行了优化。
十几年后,第一代系统开始面临多种挑战。首先,它们通常将计算和存储耦合在了同一个本地设备上,这强制企业为被管理的数据和用户负载的峰值做准备和付费,当数据集扩张,这会变得非常昂贵。其次,不仅仅是数据集增长迅速的问题,越来越多的数据集是完全非结构化的,比如视频、音频以及文本文档,data warehouse完全无法存储并查询它们。
为了解决这些问题,第二代数据分析平台开始将全部原始数据卸载到数据湖中(data lake):低成本存储系统,具有文件API,并以通用且通常是开放的文件格式存储数据(如Apache Parquet和ORC)。这种方法始于Hadoop运动(Hadoop movement),使用Hadoop文件系统(HDFS)作为廉价存储。数据湖是一个schema-on-read的架构,这允许我们以低成本灵活存储任何数据,但是另一方面,这也是将数据质量和数据管理问题规避到了下游。在这种结构中,数据湖中的一小部分数据子集稍后会被ETL到下游的warehouse中(如Teradata),用于最重要的决策支持和BI应用。开放的格式也使得数据湖可以直接被广大的其它分析引擎使用,如机器学习系统。
2015年起,云数据湖,比如S3、ADLS和GCS开始替代HDFS。它们具有惊人的可靠性(通常大于10个9)、地理复制,更重要的是成本极低。云架构中的余下部分,很大程度上和第二代系统相同,它们具有一个下游data warehouse(如Redshift、Snowflake)。这些二层的数据湖 + 数据仓库的架构在当前行业中占据主导地位(几乎所有的财富500强企业都在使用)。
当前的数据架构给我们带来了一些挑战。虽然数据湖和仓库的架构表面上由于分离了计算和存储而非常低成本,但这种二级架构对于用户而言非常复杂。
在第一代平台中,所有数据从操作性数据库系统直接ETL到一个warehouse中,而在当今系统,数据首先ETL到湖中,然后再ETL到仓库中,这带来了复杂性、延迟以及新的故障模式。更进一步地,企业的使用常见现在包含诸如机器学习这样的高级分析,无论是数据湖还是数据仓都不是理想的。具体地说,当前的数据架构通常面临四个问题:
可靠性:保持湖仓之间数据的一致性是困难且高成本的。需要持续的工程来在两个系统之间ETL数据,并且让其可以支持高性能决策分析和BI。每一个ETL步骤还可能存在失败或引入bug的风险,这会降低数据质量。
数据陈旧:数仓中的数据相比于湖中的数据是陈旧的,新数据通常需要数天被装载。与第一代系统相比,这是一个倒退,在第一代系统中,新的操作性数据会立即对查询可用。根据Dimensional Research和Fivetran的调查,86%的分析师使用过时的数据,60%的分析师说它们每月要等待多次工程资源。
对于高级分析的有限支持:企业希望使用他们的数仓数据以提出预测性问题,比如“我应该给哪一个客户折扣?”尽管对机器学习和数据管理的交互存在大量研究,但当前领先的机器学习系统(如TensorFlow、PyTorch和XGBoost)都无法很好的运行在数仓之上。不像BI查询只提取少量数据,这些系统需要使用复杂的非SQL代码处理大量数据集,通过ODBC/JDBC读取数据是低效的,并且也没有办法直接访问数仓内部的私有格式。对于这些场景,数仓供应商推荐将数据导出成文件,这进一步的加大了复杂性和陈旧性(且添加了第三个ETL步骤)。另外,用户可以使用在数据湖中以开放格式运行这些系统,然而,它们会因此丢失数仓丰富的管理特性,如ACID事务、数据版本和索引。
所有者的总成本:除了支付持续的ETL费用,用户还需要为拷贝到数仓的数据支付双倍的存储费用,商业的数仓将数据锁定在私有格式中,这增加了迁移数据或工作负载到其它系统的成本。
本篇论文中,我们讨论了如下的技术问题:是否可以将基于标准开放数据格式的数据湖转换成既可以提供高性能和管理特性的数据仓库;还能提供面向高级分析负载的快速,直接I/O的高性能系统?我们认为这种系统(我们称作湖仓)在行业上是可行的,并且已经在各种形式上展现出成功的证据。随着更多的商业应用开始依赖操作性数据以及高级分析,我们坚信湖仓是一个可以消除一些数据仓库顶级问题的令人信服的设计点。
特别是,由于最近的解决方案解决了以下关键问题,我们相信湖仓是时候出现了:
-
数据湖上的可靠数据管理:就像当下的数据湖一样,湖仓需要能够存储原始数据(raw data),同时支持ETL/ELT过程来整理这些数据,以提高它的质量来用于分析。传统上,数据湖将数据管理为半结构化的“一批文件”,使得无法提供关键的管理特性(如事务回滚到老的表版本、零拷贝克隆)以简化数据仓库中的ETL/ELT。然而,最近的系统家族如Delta Lake和Apache Iceberg提供数据湖的事务视图,允许了这些管理特性。当然,组织仍需要在编写ETL/ELT逻辑以整理湖仓数据集上下功夫,但是总体上ETL的步骤变少了,并且分析者可以简单高性能的在原始数据表上查询,如果它们想要的话,这非常像第一代分析平台。
-
机器学习和数据科学支持:ML系统支持从数据湖格式中直接读取,所以也可以直接高效的访问湖仓(译者:这里说的应该是支持开放标准文件格式的那些数据湖)。另外,很多ML系统已经提供了DataFrame抽象来管理数据,并且最近的系统已经设计了声明式的DataFrame API,这允许在ML工作负载下的数据访问执行查询优化。
-
SQL性能:湖仓需要在过去十几年间积累的大量的Parquet/ORC数据集上提供先进的性能(或者是一段很长的时间,或者是一些其它直接暴露给程序访问的标准格式),相比之下,经典的数据仓库接受SQL,并且能够自由地执行任何优化其底层内容,包括其私有的存储格式。但尽管如此,我们还是展示了一些技术,它们可以用来维护关于Parquet/ORC数据集的辅助数据,或优化现存格式的数据布局以达到有竞争力的性能。我们展示了在Parquet上的SQL引擎(Databricks的Delta引擎),其在TPC-DS上的性能领先于云数据仓库。
动机:数据仓库的挑战
数据仓库是许多商业过程的关键,但是它们依然经常会因为不正确的数据、不及时以及高成本这些问题使用户沮丧。我们认为这些挑战中至少有一部分使来自于一种“意外的复杂性”,这些复杂性来源于企业级数据平台被设计的方式,这是湖仓中需要消除的。
首先,被当今的企业数据用户报告的最多的问题通常是数据质量和可靠性问题,实现正确的数据管道已经是困难的了,但是今天的二层数据架构添加了额外的复杂性,更是加重了这一问题。举个例子,比如数据湖和数据仓系统,对于它们支持的数据类型、SQL方言等也许具有不同的语义,数据可能以不同的模式存储在湖和仓中(例如其中一个是非标准的);再比如递增的ETL/ELT作业的数量,它们跨越多个系统,增加了错误和bug的可能性。
第二,越来越多的企业应用需要最新数据,但是现在的架构对于进来的数据,有一个在数据仓之前独立的暂存区(湖),并且需要使用周期性的ETL/ELT作业去加载它,这进一步加大了数据的不及时性。理论上来说,组织应该实现更多的流式管道来更快的更新数据仓,但是这仍比批量任务更难执行。相比之下,第一代平台——数据仓的用户可以立即访问从处于同一环境的操作型数据库加载的原始数据以及派生数据。使用陈旧数据的业务应用几乎是无效的,而且即使是查询数据仓的人类分析者也报告陈旧数据是一个大问题。
第三,在很多行业中,较大比例的数据现在都是非结构化的,如图像、传感器数据、文档等。组织需要一个便于使用的系统来管理这些数据,但是SQL数据仓和它们的API无法轻易的支持。
最终,大多数组织现在都部署了机器学习和数据科学应用,但是现在的数据仓和数据湖不能很好的支持它们。就如同之前探讨的,这些应用应该使用非SQL代码处理大量的数据,所以它们不能通过ODBC/JDBC来高效运行。作为持续开发的高级分析系统,我们相信,将开放格式数据的直接访问给它们是支持它们的最高效方式。另外,ML和数据科学应用和经典应用一样,都面临着同样的数据管理问题(如数据质量、一致性和隔离性),所以,将DBMS特性引入它们的数据中有巨大的价值。
向湖仓迈进的现有步伐。多个当前的行业趋势进一步证明了客户对二层湖仓模型的不满。首先,近几年,所有的主流数据仓库都添加了对Parquet和ORC格式中的外部表的支持。这允许数据仓用户通过相同的SQL引擎查询数据湖,但是这没有让数据湖表更易于管理,也没有移除ETL的复杂性、数据不及时以及数据仓中数据的高级分析挑战。实际上,这些连接器通常性能不佳,因为SQL引擎绝大多部分是为它们内部数据格式优化的。另外,现在有广泛的直接运行在数据湖存储上的SQL引擎,比如Spark SQL、Presto、Hive以及AWS Athena。然而,这些引擎本身并不能解决所有数据湖的问题,也不能替代数据仓:数据湖仍然缺乏基本的如ACID这种的管理特性,也没有如索引这种能够匹配数据仓库性能的高效访问方式。
湖仓架构
我们将湖仓定义为一个这样的系统,它基于低成本且可直接访问的存储,且提供传统的分析型DBMS的管理功能以及性能特性,如ACID事务、数据版本、审计、索引、缓存以及查询优化。因此它也结合了数据湖和数据仓库的关键优点:前者(湖)的开放格式的低成本存储,可以由多种系统访问;后者(仓)的强大的管理功能和优化特性。关键问题是,是否可以以一种有效的方式来结合这些特性:具体的说,湖仓支持直接访问,意味着它们在数据独立性方面放弃了一些东西,而这却是关系型DBMS设计中的基石。
我们注意到,湖仓特别适用于具有计算和存储分离的云环境:不同的计算应用可以在完全独立的计算节点(如一个ML的GPU集群)上按需运行,同时直接访问相同的存储数据。然而,也可能在一个如HDFS的本地存储系统上实现湖仓。
在本节中,我们提出一个湖仓系统的可能的设计,基于三种最近的技术理念,它们已经以各种形式出现在行业中。我们一直在Databricks中,基于这种设计,同时通过Delta Lake、Delta Engine以及Databricks ML运行时项目来构建湖仓平台。其它设计也可能是可行的,就像我们在高层设计部分的其它具体技术选择(例如我们在Databricks当前的技术栈是在Parquet存储格式上构建的,但设计一个更好的格式是可能的)。我们讨论了几种替代品以及未来的研究方向。
实现一个湖仓系统
对于实现一个湖仓,我们提出的第一个关键想法就是要就有一个低成本的对象存储系统来存储数据(如亚马逊S3),并且使用一个如Parquet的标准文件格式,但需要在对象存储之上实现一个元数据层,用于定义哪一个对象是某个表版本的一部分,同时将大部分数据保存在低成本的对象存储中且大多数情况下允许从这个存储中使用标准文件格式直接访问。最近的多种系统,包括Apache Iceberg、Delta Lake已经以这种方式成功的向数据湖中添加了管理特性,比如,Delta Lake现在在Databricks将近一半的负载中被数千个客户使用。
即使元数据层添加了管理特性,它还是无法达到足够的SQL性能。数据仓库使用多种技术来获取卓越性能,比如在SSD这种快速设备上存储热点数据,维护统计数据,构建高效访问方法(如索引),联合优化数据格式和计算引擎。在基于现存文件格式的湖仓中,我们不可能更改文件格式,但是我们展示了在不变更数据文件的情况下实现的其它优化,包括缓存、辅助数据结构(如索引和统计)以及数据布局优化(3.3节)。
最后,由于声明式DataFrame接口的开发,湖仓既可以加速高级分析负载,也可以给它们更好的数据管理特性。许多ML库(如TensorFlow、Spark MLlib)已经支持读取如Parquet的湖文件格式。因此,将它们与湖仓整合的最简单方式就是查询元数据层来找出哪些Parquet文件是表当前的一部分,然后简单的将它们传递到ML库中。然而,大多数这些系统都提供了用于数据准备的DataFrame API,这创造了更多的优化机会。DataFrame从R和Pandas开流行,基本上是给用户一个表抽象,并且具有多种转换操作符,大多都能映射到关系代数上。像Spark SQL这种系统已经通过懒执行转换并将结果操作符计划传递给优化器来实现了这个API定义。因此,这些API可以利用湖仓中的新优化特性,比如缓存和辅助数据,来进一步加速ML。
图2展示了这些想法如何组成一个湖仓设计。在下三节中,我们将扩展这些技术概念的更多细节并且讨论相关的研究问题。

用于数据管理的元数据层
开启湖仓的第一个组件便是在数据湖存储之上的元数据层,它可以提高自身的抽象级别,以实现ACID事务和其它管理特性。如S3、HDFS这样的数据湖系统只提供一个底层的对象存储或文件系统接口,支持很简单的操作,举个例子,更新一个跨多文件的表是非原子的。组织很快就开始在这些系统上构建更丰富的数据管理层,从Hive ACID开始,它跟踪了哪些数据文件是一张给定版本的Hive表的一部分,它是使用OLTP数据库实现的,并且允许事务性的操作这个集合。在近几年中,新的系统提供了更多的能力和更优秀的扩展性,在2016年,Databricks开始开发Delta Lake,它在数据湖内部存储哪些对象是一张表的一部分的信息,它将其存储为一个使用Parquet格式的事务日志,使其能够扩展到每张表数十亿个对象。Apache Hudi,起源于Uber,是这个领域的另一个系统,专注于简化到数据湖的流式摄取,即使它不支持并发写。
使用这些系统的经验表明,它们通常提供与原始Parquet/ORC数据湖相比相似或更好的性能,同时添加了非常有用的管理特性,如事务、零拷贝克隆以及回到某张表过去版本的time travel。此外,对于那些已经有一个数据湖的企业非常容易适配:举个例子,Delta Lake可以使用零拷贝来将一个现存的Parquet文件目录转换成一个Delta Lake表,仅仅是通过增加了一个以引用所有文件条目开始的的事务日志。结果就是,组织正在迅速的适配这些元数据层:举个例子,在Databrick的近三年中,Delta Lake已经慢慢覆盖了半数的计算时间。
另外,元数据层是实现数据质量强制措施(data quality enforcement)特性的自然的位置。举个例子,Delta Lake实现了schema措施以确保上传到表中的数据符合其schema,以及允许表所有者在摄取的数据上设限制的限制API。Delta客户端库会自动拒绝违反这些预期的记录,或者将它们隔离岛一个特殊位置。用户会发现这些简单特性对于提升基于管道的数据湖的质量是非常有用的。
最后,元数据层是一个实现治理功能的自然位置,比如访问控制和审计日志。距离,一个元数据层可以在授予读取在云对象存储服务中的表中原始数据的权限之前,检查一个客户端是否被允许访问一个表,并且可以可靠的记录所有访问的日志。
未来方向以及其它设计:由于数据湖的元数据层是相当新的发展,有很多开放性问题和其它设计。比如,我们让Delta Lake在相同的对象存储中存储事务日志以简化管理,提供更高的可用性和读取带宽,然而,由于对象存储的高延迟,这限制了它可以提供的每秒事务速率。一个使用更快的存储系统来存储元数据的设计可能在某些场景下更合适。类似的,Delta Lake,Iceberg和Hudi只能在单表上提供事务,但是将它们扩展成跨表事务是可能的。优化日志文件的格式和管理对象的大小也是一个开放问题。
湖仓中的SQL性能
或许湖仓方式最大的技术问题就是如何在放弃相当一部分传统DBMS设计中的数据独立性的情况下提供卓越的性能。答案显然依赖于一系列因素,比如我们有什么硬件(比如我们可以在对象存储之上实现一个缓存层)以及我们是否可以修改对象存储的数据格式,不使用现存的标准格式(在这些格式上改进的新格式还在持续增加)。然而,无论具体的设计是怎样的,一个核心挑战是数据格式也是系统开放API的一部分,以允许快速访问,这和传统的DBMS有区别。
我们提出了多种和选择的数据格式无关的多种技术来实现SQL性能优化,因此可以应用在现存或未来的格式上。我们已经将这些技术在Databricks的Delta引擎中实现,并且较流行的云数据仓库具有有竞争力的性能,而且还有进一步优化性能的空间。这些格式独立的优化有:
缓存:当使用如Delta Lake这种事务元数据层的时候,对于湖仓系统来说从云对象存储上缓存数据到处理节点上更快的存储设备(SSD、RAM)是安全的。运行中的事务可以轻松的分辨出什么时候缓存文件仍然有效可读。另外,缓存可以以一种能够让引擎更高效运行查询的转码后的格式保存,以匹配任何的在传统的“封闭世界”的数据仓库引擎中执行的优化。举个例子,我们在Databricks中的缓存部分的解压缩了其装载的Parquet数据。
辅助数据:即使湖仓需要给直接I/O暴露基本表存储结构,但它也可以在辅助文件中维护其它数据以帮助优化查询,对于这些辅助文件,它有着完全的掌控。在Delta Lake和Delta引擎中,我们为表的每一个文件维护了列的最小和最大统计,这些统计和事务log使用相同的Parquet文件,当基础数据以某些特定列聚合的时候,我们可以应用数据跳过优化。。我们还实现了一个基于索引的布隆过滤器。你可以想象,我们在此实现了大范围的辅助数据结构,就像对原始数据索引一样。
数据布局:在访问性能上,数据布局举足轻重。即使我们已经固定了存储格式,但是仍然有很多布局决策可以让湖仓系统做优化。最明显的就是记录顺序:聚集在一起的那些记录也因此更容易被一起读取。在Delta Lake中,我们支持使用独立维度或如Z-order或Hilbert这种空间填充曲线来在多维度间提供局部性。你可以想象为,新的格式支持在每个文件中以不同的顺序放置列,为多组不同的记录选择不同的压缩策略,或其它策略。
这三种优化对于分析系统的典型访问模式来说出奇的好。在典型的工作负载中,大多数查询倾向于聚焦在数据的一个热点子集中,湖仓可以使用与数据仓库的封闭世界相同的、优化过的数据结构来缓存,以提供有竞争力的性能。对于在云对象存储中的冷数据,其性能的主要决定因素是每个查询读取的数据量。在这种情况下,数据布局优化(将共同访问的数据聚集)以及辅助数据结构如zone map(让引擎能迅速找到要读取的数据文件的范围)能够让湖仓系统以与一个封闭世界的专有数据仓库相同的方式来最小化I/O,即使运行在标准开放文件格式上。
性能结果:在DataBricks,我们在一个新的,被称作Delta引擎的Spark C++执行引擎中结合了这三种优化。为了评估湖仓架构的可行性,图3在TPC-DS上,在规模因子(scale factor)为30000的情况下,与四种广泛使用的云数据仓库做了比较,我们使用了在AWS、Azure和Google Cloud上的可比较集群,每个都有960个vCPU以及一个本地SSD。我们报告了运行全部99个查询的时间,以及在每一个服务计价模型上的总开销(Databricks允许用户选择spot和按需实例,所以我们都展示了)。与这些系统相比,Delta引擎以更低的价格点,提供了可比较的或更优的性能。

未来方向以及其它设计:设计一个高性能且可直接访问的湖仓系统在未来有着丰富的空间。一个清晰的方向是,我们还没有探索过设计一个能够在这种场景下更好的新的数据湖存储格式,比如,能够给湖仓系统实现数据布局或索引优化提供更多灵活性的数据格式,或者让其更适合现代硬件。当然,这种新格式可能需要一些时间来让处理引擎适配,限制能够从中读取的客户端数量,但是,设计一个对于下一代工作负载的高质量可直接访问的开放格式是一个重要的研究问题。
即使不修改数据格式,湖仓架构中依然有很多种类型的缓存策略、辅助文件结构以及数据布局策略能够探索。确定哪一个对于在云对象存储中的大量数据集最高效是一个开放问题。
最后,一个激动人心的研究方向是,确定何时以及如何使用无服务计算系统来响应查询,以及优化这种情况下的存储、元数据层以及查询引擎设计以最小化延迟。

浙公网安备 33010602011771号