对Delta Table的所有数据修改操作,都会由MetaService统一进行事务管理,满足ACID特性,应用MVCC模型来保障读写快照隔离,采用OCC模型(乐观并发控制协议,Optimistic Concurrency Control)进行乐观事务并发控制。
冲突检测规则
下表为作业并发提交场景下,对同一个非分区表或分区的并发数据操作先后结束的冲突规则说明。
作业类型 | INSERT OVERWRITE / TRUNCATE (后结束) | INSERT INTO (后结束) | UPDATE / DELETE (后结束) | MINOR COMPACT (后结束) | MAJOR COMPACT (后结束) |
INSERT OVERWRITE / TRUNCAT(先结束) | 先、后结束的作业都会执行成功。 后结束的结果会覆盖先结束的结果。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 |
INSERT INTO (先结束) | 先、后结束的作业都会执行成功。 后结束的结果会覆盖先结束的结果。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先,后结束的作业执行成功。 后结束的作业Compact成功。 | 先结束的作业执行成功。 后结束的作业会报错。 |
UPDATE / DELETE (先结束) | 先、后结束的作业都会执行成功。 后结束的结果会覆盖先结束的结果。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先,后结束的作业执行成功。 后结束的作业Compact成功。 | 先结束的作业执行成功。 后结束的作业会报错。 |
MINOR COMPACT (先结束) | 先,后结束的作业执行成功。 后结束的结果会覆盖先结束的结果。 | 先,后结束的作业执行成功。 后结束的作业只会追加自身的新数据。 | 先,后结束的作业执行成功。 后结束的作业只会追加自身的新数据。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先,后结束的作业执行成功。 后结束的作业Compact成功。 |
MAJOR COMPACT (先结束) | 先,后结束的作业执行成功。 后结束的结果会覆盖先结束的结果。 | 先,后结束的作业执行成功。 后结束的作业只会追加自身的新数据。 | 先,后结束的作业执行成功。 后结束的作业只会追加自身的新数据。 | 先结束的作业执行成功。 后结束的作业会报错。 | 先结束的作业执行成功。 后结束的作业会报错。 |
并发冲突优化
通过上面冲突规则表格可知,目前并不支持行级别或者文件级别的事务并发控制,而是以每次批处理数据操作作为一个单独的事务来管理。对于部分高频的操作,会结合它的语义,在保障正确性的前提下,单独设计优化了事务冲突逻辑,来更好支持并发控制。
比如对于Clustering操作和Insert into并发执行,即使事务Start和Commit时间出现交叉也不会冲突失败,因为Clustering操作虽然改变了数据组织方式,但没有改变数据本身的状态,和其他数据更新操作并没有影响一致性的冲突,因此允许并发执行。这部分后续还会持续优化,扩大应用场景。
对于冲突检测失败的处理,在保证正确性的前提下会尽量先做meta级别的重试优化,不用重新读写数据,提升用户体验的同时,也能节省资源消耗。
最后一步是原子性提交元数据更新,保证数据一致性。
目前只支持单表事务管理。
数据文件版本管理
每次事务操作会生成一批新的数据文件,这些数据文件会绑定对应的事务版本,主要包含两个属性:
时间版本:Timestamp类型,等效于事务Commit时间,只有由用户触发并且存在逻辑数据变更的操作才会产生新的时间版本,Clustering和Compaction操作只是对物理数据进行了重新组织优化,并没有实际新增或者修改数据,因此不会产生新的时间版本,这样做的好处是用户使用时间版本进行增量查询时,Clustering和Compaction产生的数据文件不会作为新增数据被查询输出,满足用户实际的业务场景。
ID版本:自增的整型,任何数据操作的事务,都会产生一个增量的ID版本,包括引擎内部执行的Clustering和Compaction操作,主要用于内部的事务管理需要。ID版本也会对用户透出,并且也可用于增量查询。