GaussDB事务介绍

107 阅读5分钟

GaussDB事务是数据库的核心功能之一,其主要目的是保障数据库系统在并发处理、系统故障等场景下的数据一致性和完整性。数据库系统中,不同事务之间会存在多种并发执行操作,例如读读并发、读写并发、写写并发,都涉及到事务、语句的执行顺序以及数据对象的共享和保护问题,如果处理不正确就可能会引发数据的一致性问题。

数据一致性的常见问题包括:写读冲突引发的脏读(Dirty Read)、读写冲突引发的不可重复读(Non-repeatable Read)和幻读(Phantom Read)、写写冲突引发的丢失更新(Lost Update)。

为了有效应对这些挑战,GaussDB数据库系统采用了三种关键技术来保障事务的正确执行和数据的一致性:并发控制机制、多版本并发控制(MVCC)机制以及快照机制。下面我们将对这三种机制进行详细介绍,并深入探讨华为云GaussDB在这三方面的实现路径。

一、并发控制机制

数据库的并发控制机制有多种实现方式,例如:悲观并发控制方式、乐观并发控制方式、多版本并发控制方式。

悲观并发控制:事务访问数据前先加锁,事务结束后释放锁,属于事前控制,避免冲突发生。悲观并发控制比较适合事务冲突较多的场景。

乐观并发控制:将数据拷贝到私有工作区,全部处理结束后,再集中检查是否满足调度隔离级别,如果不满足则回滚,属于事后控制,冲突发生后再处理。乐观并发控制比较适合事务冲突较少、执行时间较短的场景。

多版本并发控制(MVCC):一个数据项保存了多个物理版本,供不同的事务使用,事务的读操作无需等待其他事务的写操作,事务的写操作无需等待其他事务的读操作,通过空间复用的多版本信息缓解读写冲突。

二、MVCC实现方式

MVCC有两种主要实现方式:

方式一:数据记录的多个版本均存储在数据文件里,事务和可见性相关信息也包含在每个版本的数据记录中。这种MVCC实现更新和删除操作执行代价较小,后期对已被删除无效记录回收代价较高。

方式二:数据文件中只保留最新版本,事务信息都被集中管理,历史版本被存储于UNDO中,记录自身可以不包含事务和可见性信息,通过统一的事务管理区域来查询记录对应的事务状态。这种MVCC实现方式更新和删除操作执行代价稍高,后期对已被删除无效记录回收代价极低。

三、快照实现方式

快照主要有两种实现技术方式:

方式1:基于运行事务号的活跃事务列表实现方式

在这里插入图片描述

图1 活跃事务列表示意图

如图1所示,数据库进程中维护一个全局数组,其中的成员为正在执行的事务信息,包括事务的事务号,该数组即为活跃事务列表。在每个事务开始时,复制一份该数组的内容,当事务执行过程中扫描到某一个元组时,需要通过判断该元组中记录的事务号所对应的事务对于查询事务的可见性,来决定该元组是否对查询可见。

使用事务活跃列表方式的快照,性能和事务规模产生耦合,只适用小并发场景:

1)当并发连接增大时,活跃事务列表快照也会相应变大,导致系统性能严重劣化。

假设当前有一万个活跃事务,为构造一个快照,系统需要拷贝这一万个事务,如果每个事务ID是8个字节,那么需要拷贝80KB的数据。另外,在分布式系统下,计算节点通过网络访问活跃事务列表快照,产生巨大网络开销,进而影响性能。

2)当事务活跃列表比较大时,无法使用原子操作,系统在事务启动时获取事务快照和事务结束时清理事务状态快照时,都需要对活跃事务列表进行加锁操作。也就是说,无论对其读取(读-写操作)、还是修改(写-写并发操作),都需要加锁互斥,会产生大量的锁等待,高并发下活跃事务列表会成为加锁的热点和性能瓶颈。

方式2:基于提交时间戳的实现方式

每个数据记录都对应了一个事务提交时刻的时间戳。当一个新的查询开始的时候,系统会生成一个快照时间戳,取当前系统的最大时间戳加1作为该快照时间戳,并通过比较快照时间戳和数据记录中对应的提交时间戳,来做可见性判断。