云数仓与数据湖元数据 ACID 介绍与对比
项目开发之外抽空调研ACID功能的一个总结记录,仅讨论功能,后续抽空会再补一个设计实现层面的介绍和对比(zz 2022.3.4)
背景
ACID 逐渐成为 云数据仓库(cloud data warehouse) 和 数据湖(data lake)关键功能(ACID 在数仓场景关注和讨论度不高,但却不可缺少,并成为了诸多开源元数据项目的核心卖点)。ACID 的基本思想是在事务的概念上,用户对于数据的操作满足原子性(要么成功要么失败),隔离性(并发操作互不影响),一致性(数据永远符合完整性约束,且对数据的修改在事务完成后立刻对用户可见),持久性(数据不易失)。
在云数据仓库的范畴下,类似于 Hive、BigQuery、Snowflake、RedShift、MaxCompute 支持了数据上传、修改、查询的ACID语义。
在数据湖元数据存储系统(meta data system of data lake)的范畴下,DeltaLake, Iceberg,Hudi,同样支持了各自的ACID语义。AWS Glue 没有对ACID语义的直接支持。
本文在ACID功能特性(_特指终端用户角度看到的功能_)上尝试对现有产品的ACID能力归类成不同维度进行介绍,并对比MaxCompute与各类云数仓和数据湖元数据存储系统。具体基于以下维度:
- 并发控制的协议类型。
- Time Travel类型。
- 支持的隔离级别类型。
- 支持事务的类型。
- Batch 数据读写模型。
- Stream 数据读写模型。
ACID 功能简介
大数据OLAP场景下的ACID功能与传统OLTP场景下有较大区别,主要出发点有:
(1) 支持UPDATE/ DELETE/ MERGE INTO 从而支持特定业务场景.
(2) 基于增强数据质量,为Batch / Stream 读写模式定义清楚提交的模型,并且支持 Time Travel。
并发控制的协议类型
并发控制协议类型,指的是使用哪类并发控制算法来协调并发事务。并发控制协议类型可以分为 2PL,OCC。
2PL 指引擎基于两阶段锁协议(悲观锁),在访问数据前加锁,互斥等待资源释放。Hive 使用的是2PL。
OCC 指不基于锁和互斥等待,在事务提交时校验是否提交是否合法,从而选择事务提交或中止。
当数据元组有多个共存的历史版本,打上事务操作的beginTs和endTs后,协议又可以分为 MV + OCC 和 MV + 2PL,结合两者的统称MVCC。多版本共存使得读不受写的影响,引擎可以基于历史上的快照数据进行长时间的计算,不用担心脏读提交中的数据。
对于开源的系统,我们很容易知道并发控制的实现协议。对于闭源的系统,我们只能通过文档描述来推测。SnowFlake ResourceLocking,Redshift deadlock 暗示了并发控制基于 2PL。SnowFlake 支持Time travel 暗示了使用了多版本机制。
MaxCompute 在stream tunnel 上传过程中会使用悲观锁锁住相关分区。在其他DML过程中使用了基于时间戳的乐观并发控制。可以看做 MV + OCC + 2PL。
Time Travel 类型
Time Travel意为访问历史上的一个具体时间点的数据。我们称 Offline Time Travel 指支持将表恢复到历史上的一个时间点或CLONE 一份在历史某个时间点上的数据,不支持直接查询。 Online Time Travel 指满足 Offline Time Travel 要求基础上,使用一个时间点,去查询一个表的状态,支持 SQL AFTER/BEFORE 语法。Restorable 指支持恢复已经删除的表。
事务类型
事务类型分为隐式事务(implicit transaction)和显式事务(explicit transaction)。隐式事务为单个语句写入作为一次事务提交。显式事务指在支持隐式事务的基础上,支持SQL BEGIN/COMMIT,支持事务中写入多条DML。
隔离级别类型
隔离级别是通过读写时的异常现象(phenomena)定义的行为。一般支持事务的系统都支持在在事务中读多张表。大多数系统只支持在事务中写单表。
多表写(Multi-table Atomic Write)指可以在一个事务中更新多张表,并保证原子性。
在大数据OLAP产品的术语上,Read Committed 和 Snapshot Isolation 之间存在模糊性。不少数据库使用多版本机制,基于不可变的数据文件,维护 表或分区到对应的文件列表或者数据元组 的映射(后文称作DataSet)元数据。这些数据库在一个典型的查询流程中:1.先通过每个表名和分区名找到对应的DataSet。2.基于稳定的DataSet对应的不可变文件进行计算。因为DataSet对应者不可变的文件集合快照,不受后续读写的影响。现有业界的不少产品(delta lake,iceberg,hudi)将这种隔离性称为 Snapshot Isolation。这种 SI 并非按照一个时间点获得的全局意义的快照,而是单表内的快照。
Batch 数据读写模型
从 SQL 作为数据处理的标准用户接口(如HiveQL)的角度,各个云数仓产品在 batch 场景提供了类似的功能。
写数据类:DDL和DML 在Table、Partition 对象CRUD的基础上, 支持 INSERT、UPDATE、DELETE、MERGE INTO 。
存储管理类:MAJOR/MINOR COMPACT、PURGE
读数据类:SELECT
数据湖元数据存储产品没有直接提供SQL接口,而是以API的形式提供。在与引擎集成后,功能上基本等价与SQL。
Stream 数据读写模型
流式数据读写没有标准的SQL接口,往往以API的形式,或与流式处理系统集成配置的方式提供。
BigQuery Storage Write API 提供:
exactly once :指一次写入不会变成两次。在支持事务语义的系统中一般都可以提供(通过底层的锁或者OCC机制)。
流级别事务:指流式数据写入在用户commit前一定不可见,符合原子性。当用户创建多个流同时写入,一次性commit多个流时,称为跨流事务或多流事务。
单流写入模式:可以分为 committed、pending 、buffered。
Hive Stream Ingest 提供单流级别事务能力。用户使用顺序为 openTxn、write 、commit or abort。
Redshift 物化视图支持了stream ingest,需要手动刷新物化视图后才能看到最新数据。非物化视图表不支持流式数据写入,需要从S3中转或者写SQL INSERT。
DeltaLake、Iceberg、Hudi 的流式数据处理能力都主要通过spark streaming向外提供,提供每次复杂或者每次全量覆盖的简单能力。
SnowFlake 使用 snowpipe 解决流式导入数据场景,基于底层的snowflake trasaction机制实现。
MaxCompute tunnel 支持 批量数据通道(tunnel) 和 流式数据通道(stream tunnel) 两类模式。
批量数据通道提供单流写入的事务语义, 提供createSession、write、commit or abort。
流式数据通道不再向用户提供commit接口,提供createSession、write、flush。流式数据通道单个 session 内的多个write 不支持原子的提交,并且在session创建后写入过程中加锁拒绝其他写请求,以满足最高可能的行级写入性能。
可以看出,在流式数据读写的ACID能力上都没有超过DML的事务。流式数据的每次写入,都可以看做一个不读数据的单表事务提交过程。流式数据的事务相较于 SQL DML 事务隔离性更低,只需要满足写时的原子性,因为流式API不涉及到事务中对数据的读。
目前还没有产品讨论或提供在事务中包含多表或者多数据源时流式数据写入和读取的隔离性。流式数据处理从ACID层面没有更细致的分类。
根据功能特性分类的结果汇总
\ 表示不支持。
N/A 表示未知。
| Open source | Protocol | Time Travel | Transaction | Isolation Level | Multi-table Atomic Write |
---|---|---|---|---|---|---|
Hive | Y | 2PL | \ | Implicit | Read Committed | Not Supported |
BigQuery | N | N/A | Online/Restorable | Explicit | Snapshot Isolation | Supported |
Snowflake | N | MV + 2PL | Online/Restorable | Explicit | Read Committed | Supported |
RedShift | N | 2PL | \ | Explicit | Serializable | Supported |
MaxCompute | N | MV + OCC + 2PL | Offline/Restorable | implicit | Snapshot Isolation | Not Supported |
DeltaLake | Y | MV + OCC | Online | implicit | Snapshot Isolation | Not Supported |
Iceberg | Y | MV + OCC | Online | implicit | Snapshot Isolation | Not Supported |
Hudi | Y | MV + OCC | Online | implicit | Snapshot Isolation | Not Supported |
AWS Glue | N | \ | \ | \ | \ | \ |