当前位置:Gxlcms > 数据库问题 > 巨杉数据库SequoiaDB】巨杉Tech | SequoiaDB 分布式事务实现原理简介

巨杉数据库SequoiaDB】巨杉Tech | SequoiaDB 分布式事务实现原理简介

时间:2021-07-01 10:21:17 帮助过:10人阅读

当事务协调器节点从所有事务管理器节点获得的相应消息都为“同意”时:

1. 事务协调器节点向所有事务管理器节点发出“正式提交”的请求。

2. 事务管理器节点正式完成操作,并释放在整个事务期间内占用的资源。

3. 事务管理器节点向事务协调器节点发送“完成”消息。

4. 事务协调器节点受到所有事务管理器节点反馈的“完成”消息后,完成事务。

技术图片技术图片?失败的情况

如果任一事务管理器节点在第一阶段返回的响应消息为“中止”,或者事务协调器节点在第一阶段的询问超时之前无法获取所有事务管理器节点的响应消息时:

1. 事务协调器节点向所有事务管理器节点发出“回滚操作”的请求。

2. 事务管理器节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。

3. 事务管理器节点向事务协调器节点发送“回滚完成”消息。

4. 事务协调器节点受到所有事务管理器节点反馈的“回滚完成”消息后,取消事务。

有时第二阶段也被称作完成阶段,因为无论结果怎样,事务协调器都必须在此阶段结束当前事务。

事务协调器和事务管理器之间的通信流程的示意图:

技术图片技术图片

两阶段提交算法的最大缺点就在于:它的执行过程中间,节点都处于阻塞状态。即节点之间在等待对方的相应消息时,它什么也做不了。特别是,当一个节点在已经占有了某项资源的情况下,为了等待其他节点的响应消息而陷入阻塞状态时,当第三个节点尝试访问该节点占有的资源时,这个节点也将连带陷入阻塞状态。

另外,事务协调器节点指示事务管理器节点进行提交等操作时,如有事务管理器节点出现了崩溃等情况而导致事务协调器始终无法获取所有事务管理器的响应信息,这时事务协调器将只能依赖事务协调器自身的超时机制来生效。但往往超时机制生效时,事务协调器都会指示事务管理器进行回滚操作。这样的策略显得比较保守。

 

3.2 快照隔离

快照隔离(Snapshot Isolation)技术是实现多版本并发控制的技术之一。此技术策略的前提就是每条数据都要支持版本化,事务对数据的每次写操作成功提交后(更新、插入、删除)都会生成该数据的一个新版本。这里有一个概念,就是写操作成功提交之后,才会生成数据的新版本。在写操作没有成功提交之前,对数据的任何修改,都不算生效的。

什么是快照Snapshot呢?简单来说就是在某个特定时刻T1,数据库里面所有数据最新版本的集合。举个例子,比如数据库里面只有3条记录,它们在时间戳T1的时候,状态如下:

 技术图片技术图片?

即 row1[version 10],row2[version = 1], row3[version=19] 就形成了数据库在T1时刻的快照。过了几分钟之后,到了时间T2,如果在T1和T2之间没有写操作成功提交,那么数据库的状态没有变化,即T1时候的快照和T2时候的快照是相等的。再过了几分钟之后,到了时间T3,在T2和T3之间,有一条对row2的更新操作、一条对row3的删除操作、一条row4的插入操作成功提交了,数据库中的数据状态变成了: 

技术图片技术图片

即 row1[version 10],row 2[version = 2], row3[version=20],row4[version=1] 就构成了数据库在T3时间的快照。因为每条记录的版本变更是不一样的,所以需要注意数据版本的变更情况。

另外,请注意在数据多版本的要求下,删除操作并不是真的删掉row3,而是生成了一个row3的新版本。在实际实现中,数据库不一定是按上面示例的一样把值赋值成null,也可能用一个特殊的标志位标识这是一个“删除”的版本。

快照永远和特定的时间相关,脱离时间谈论快照是没有意义的。如果在一段时间内,数据库没有任何写操作成功提交,那么这段时间内,数据库在任意时间的快照都是相等的。所以,我们可以认为,每一个有包含写操作的事务成功提交,都会形成数据库的一个不同的快照。在很多数据库实现中,version直接使用时间戳,而不是上面例子中的数字。

每个事务在启动时,都会记录当时的时间作为启动时间戳Start-Timestamp。该事务只能读取启动时间戳那个时刻的数据快照。然后每个事务在提交时,会记录当时时间作为提交时间戳Commit-Timestamp,当该事务成功提交后,会形成一个Commit-Timestamp的数据快照。后续启动的事务才能看到该事务写的数据(如果该事务有写操作)。

 

技术图片技术图片

上图中,三条横线代表三个事务。事务T2是看不到事务T1写的任何数据的,因为事务T2启动时,事务T1还没有提交。而事务T3可以看到事务T1和事务T2写的数据,因为它启动的时候,事务T1和事务T2都提交了。

快照隔离(Snapshot Isolation)需要通过锁机制来防止写冲突,对于读操作,不加锁。如果多个事务同时写一个数据,锁机制保证最多只有一个事务能提交成功。由于对读操作不加锁,Snapshot Isolation的性能会显著提高。

 

4

SequoiaDB 分布式事务实现

4.1 基本概念和定义

为了实现分布式事务,巨杉数据库通过采用全局时间来实现全局事务对跨数据分片的事务的协调和管理。基于此需求,为了确定全局时间,巨杉数据库定义了时间戳的相关概念与定义,引入了时间戳管理机制。具体的定义如下:

  • LLT(Local Logical Timestamp):每个节点(CATALOG、COORD、DATA)维护自己的本地逻辑时间(最小单位:microsecond)

  • ULT(Universal Logical Timestamp): 定义CATALOG主节点的本地时间为全局逻辑时间(最小单位:microsecond)

  • LRT(Local Real Timestamp):本地UTC时间

为了保证整个集群全局时间的一致与准确,协调节点(COORD)和数据节点(DATA)需要定时与编目节点(CATALOG)的主节点进行时间同步。而同步时间定义了以下规则:

1. CATALOG主节点的LLT(即ULT)通过所有机器的CPU Tick计算

2. 其它节点的LLT通过与CATALOG主节点进行同步ULT来维护

3. 同步的间隔为ULTSyncInterval(默认:60秒)

4. 同步结果需要使用差小于全局容忍误差ULTTolerance(默认: 1ms)

5. ULTTolerance根据时间差同步、网络状态进行动态调整

全局时间的定义及规则确认之后,则可以将其用于分布式事务的实现当中。分布式事务采用二段提交机制实现,结合二段提交的原理,定义了以下几类事务时间:

  • TBT(Transaction Begin Timestamp):事务开始时间

  • TPCT(Transaction Pre-Commit Timestamp):事务的预提交(precommit)时间

  • TCP(Transaction Commit Timestamp):事务的提交时间

其中,同一个事务的TBT和TPCT之间需要有一个事务时间间隔,此间隔取当时ULTTolerance。事务时间间隔也可以定义为不同节点发起的事务时间之间的最小可以容忍的误差。即如果两个不同节点的事务时间之间相关小于事务时间间隔,即认为这两个事务时间有误差的情况下相等。

 

4.2 二段提交实现

巨杉数据库对于分布式事务采用的是经典二段提交(2PC)方式实现的。其采用全局时间来实现全局事务的统一协调管理,使分布式集群中的不同节点进行事务的统一操作。在整个事务操作过程中,客户端发起的事务分为三个部分:

第一部分:事务开始。在这一部分的操作中,客户端向数据库服务器发起“事务开始”的请求。数据库服务器结合其本地逻辑时间生成一个事务开始时间,并记录在案。

第二部分:事务的增删改查操作。此部分是整个事务原子包的系列操作,它包含增删查改四类基本数据操作。在执行事务原子包里面第一条SQL语句时,分布式集群需要判断和校验协调节点和数据节点之间的时间差值。如果此差值大于延时容忍值,则要求COORD节点、DATA节点向CATALOG主节点发起时间同步,然后再重新发起SQL操作。如果时间差在容忍范围内,则直接执行。第一条事务操作执行成功后,说明时间比对成功,接下来的操作则直接执行。

第三部分:事务完成。此部分为事务的结束部分。在此部分中,整个事务执行完成,开始发起事务提交的操作。此操作进入事务的二段提交阶段,即先预提交,预提交成功之后再提交一次,整个提交流程才完成。

巨杉数据库事务实现的具体流程如下图:

 技术图片技术图片?

4.3 并发控制技术

巨杉数据库对于多版本控制(MVCC)技术是通过采用事务锁、内存老版本以及磁盘回滚段重建老版本的设计来实现。此架构设计的理论基础是通过对内存结构的合理利用,存储数据和索引的老版本信息,从而实现数据的快速的并发访问。

此架构的基本原则是:充分利用内存结构缓存老版本以提高读的访问速度,同时结合事务可视性条件和MVCC来满足全局事务的不同隔离级别(RC/RR)的访问要求。在MVCC的实现中,巨杉数据库也平衡兼顾运行时的效率和多版本存储空间的使用,以及回收的开销。

在多版本控制技术的事务锁实现中,RR(可重复读)配置下的读操作可以在使用完记录之后立即释放锁,不需要一直持有,直到事务提交或者回滚。但是写事务操作则需要一直持有插入、更改和删除的锁,直到事务完成提交或者回滚。巨杉数据库锁的实现是采用悲观锁机制,与传统关系型数据库的采用的主流锁机制类似。

在多版控制技术的实现中,除了引入悲观锁的机制以外,巨杉数据库还采用了内存老版本机制提升数据库并发访问及操作的能力。内存老版本是通过在记录锁上附加有一个存储原版本数据和索引相关的结构,于内存中存储了老版本的数据。

所有事务写操作(修改,删除,插入)会在该结构中保存一个事务开始前的记录的拷贝,还包含所有改动过索引的原始版本。当读者试图获取记录锁时,如果记录正在被修改,读者取锁失败时将通过回调函数获得该锁的老版本结构,从而获取上次提交后的数据。在事务提交时,释放记录锁之后异步回收存储老版本记录和索引的空间,用户可以选择打开异步删除涉及到的待删除数据。同时在该锁或记录被下一个写操作用到时,他们都会被同步回收。其中老版本的结构如下:

 

 技术图片技术图片?

巨杉数据库在实现多版本并发控制技术时,除了采用事务锁和内存老版本机制外,还采用了磁盘回滚段对并发控制策略进行了完善与补充。众所周知,内存是高速存储设备,但是其存在存储空间比较小以及断电数据丢失的问题。针对此问题,磁盘回滚段机制通过将内存中的“老版本数据”持久化到磁盘上,保证数据库在掉电等异常情况下不会影响事务的正常操作。

回滚段使用系统集合空间,名为”SYSRBS”。另外,其内部会使用1个集合,命名格式为”SYSRBSXXXX”,其中XXXX为循环编号,范围为0~4096。同时,回滚段使用第一个集合(即:SYSRBS0000)存储RBS的元数据,包括当前RBS集合和最后空闲RBS集合。巨杉数据库会在启动时检查是否支持MVCC,如果支持,则会检查”SYSRBS”集合空间是否存在,不存在的话则会创建此集合空间,同时创建 SYSRBSCL0000 和 SYSRBSCL0001 集合。如果回滚段的集合空间和集合均存在,则会从 SYSRBSCL0000 中读取元数据信息,根据当前RBS集合和最后空闲RBS集合信息创建下一下 SYSRBSCLXXXX。

为了更进一步提高读取速度,巨杉数据库将磁盘回滚段与内存老版本相结合,最新的老版本还是挂在记录锁的 oldversionContainer 上,其它更老的版本放磁盘上。这样满足大多数据短事务只用读内存的老版本,无需再读磁盘,从而提供了读取速度。考虑到主节点异常的情况,多版本控制需要将记录老版本数据的回滚段也同步至备节点,当备节点升为主节点后,可以通过回滚段重建老版本。

当事务ID小于全局最小事务ID(lowTranID)时,数据库后台的异步线程负责回收老版本记录和索引节点内存。内存老版本清理时要将其保存的老版本写入RBS。而磁盘老版本的清理则是从最后空闲集合(lastFreeCL)开始,逐个对比表的最大事务ID(MaxGTID),如果小于全局最小事务ID,则可以删除这个表(即SYSRBSCLXXXX)。

 

5

总结

巨杉数据库通过采用事务锁、内存老版本以及磁盘回滚段重建老版本的设计来实现了多版本并发控制技术。此设计通过对内存结构的合理利用,存储数据和索引的老版本信息,从而实现多版本数据的快速的并发访问。

巨杉数据库SequoiaDB】巨杉Tech | SequoiaDB 分布式事务实现原理简介

标签:简单   反馈   大量   判断   成功   wrapper   失败   实现   串行化   

人气教程排行