DMDSC 关键技术

DMDSC 是一个共享存储的数据库集群系统。多个数据库实例同时访问、修改同一个数据库,必然会带来全局并发问题。DMDSC 集群基于 DM 单节点数据库管理系统,改造了 Buffer 缓冲区、事务系统、封锁系统和日志系统等,以适应数据共享集群并发访问控制要求。同时,引入缓存交换技术,提升数据在节点间的传递效率。

4.1 事务管理

多版本并发控制(MVCC)可以确保数据库的读操作与写操作不会相互阻塞,大幅度提升数据库的并发度以及使用体验,大多数主流商用数据库管理系统都实现了 MVCC。DM 的多版本并发控制实现策略是:数据页中只保留物理记录的最新版本数据,通过回滚记录维护数据的历史版本,通过活动事务视图(V$TRX_VIEW 和 V$DSC_TRX_VIEW)判断事务可见性,确定获取哪一个版本的数据。

每一条物理记录中包含了两个字段:TID 和 RPTR。TID 保存修改记录的事务号,RPTR 保存回滚段中上一个版本回滚记录的物理地址。插入、删除和更新物理记录时,RPTR 指向操作生成的回滚记录的物理地址。

回滚记录与物理记录一样,也包含了 TID 和 RPTR 这两个字段。TID 保存产生回滚记录时物理记录上的 TID 值(也就是上一个版本的事务号),RPTR 保存回滚段中上一个版本回滚记录的物理地址。

每一条记录(物理记录或回滚记录)代表一个版本。如下图所示:

图 4.1 各版本之间的关系.png

图4.1 各版本之间的关系

如何找到对当前事务可见的特定版本数据,进行可见性判断,是 DM 实现多版本并发控制的关键。根据事务隔离级别的不同,在事务启动时(串行化),或者语句执行时(读提交),收集这一时刻所有活动事务,并记录系统中即将产生的事务号 NEXT_TID。DM 多版本并发控制可见性原则:

  1. 物理记录 TID 等于当前事务号,说明是本事务修改的物理记录,物理记录可见
  2. 物理记录 TID 不在活动事务表中,并且 TID 小于 NEXT_TID,物理记录可见
  3. 物理记录的 TID 包含在活动事务表中,或者 TID>=NEXT_TID,物理记录不可见

为了在 DMDSC 集群中实现与单节点相同的多版本并发控制(MVCC)策略,每个事务需要知道所有节点当前活动的事务信息,根据事务隔离级的不同,在事务启动时(串行化),或者语句执行时(读提交),收集这一时刻所有节点上的活动事务,以及系统中即将产生的事务号 NEXT_TID,记录到事务的活动事务视图中。DMDSC 集群将事务信息全局化,由控制节点统一管理集群中所有节点的全局事务视图(Global Transaction View,简称 GTV);与之对应的是每个节点维护一个本地事务视图(Local Transaction View,简称 LTV),在事务启动、收集活动事务信息时通知全局事务视图,并获取相应的信息。

4.2 封锁管理

数据库管理系统一般采用行锁进行并发访问控制,避免多个用户同时修改相同数据;通过表锁、字典锁控制 DDL 和 DML 操作的并发访问,保证对象定义的有效性和数据访问的正确性。DM 则采用了独特的封锁机制,使用 TID 锁和对象锁进行并发访问控制,有效减少封锁冲突、提升系统并发性能。

TID 锁以事务号为封锁对象,每个事务启动时,自动以独占(X)方式对当前事务号进行封锁,由于事务号是全局唯一的,因此这把 TID 锁不存在冲突,总是可以封锁成功。同时,在 4.1 事务管理中,介绍了物理记录上包含一个 TID 字段,记录了修改数据的事务号。执行 INSERT、DELETE、UPDATE 操作修改物理记录时,设置事务号到 TID 字段的动作,就相当于隐式地对物理记录上了一把 X 方式的 TID 锁。因此,通过事务启动时创建的 TID 锁,以及写入物理记录的 TID 值,DM 中所有修改物理记录的操作都不再需要额外的行锁,避免了大量行锁对系统资源的消耗,有效减少封锁冲突。特别是在 DMDSC 集群中,需要进行全局封锁,封锁的代价比单节点更高,通过 TID 锁可以有效减少封锁引发的性能损失。

对象锁则通过对象 ID 进行封锁,将对数据字典的封锁和表锁合并为对象锁,以达到减少封锁冲突、提升系统并发性能的目的。

与事务管理类似,DMDSC 集群将封锁管理拆分为全局封锁服务(Global Locking Services,简称 GLS)和本地封锁服务(Local Locking Services,简称 LLS)两部分。整个系统中,只有控制节点拥有一个 GLS。控制节点的 GLS 统一处理集群中所有节点的封锁请求、维护全局封锁信息、进行死锁检测,确保事务并发访问的正确性。每个节点都有一个 LLS。各节点的 LLS 负责与 GLS 协调、通讯,完成事务的封锁请求,DMDSC 集群中所有封锁请求都需要通过 LLS 向 GLS 发起,并在获得 GLS 授权后,才能进行后续操作。

4.3 闩管理

闩(Latch)是数据库管理系统的一种内部数据结构,通常用来协调、管理 Buffer 缓冲区、字典缓存和数据库文件等资源的并发访问。与锁(Lock)在事务生命周期中一直保持不同,闩(Latch)通常只保持极短的一段时间,比如修改 Buffer 中数据页内容后,马上会释放。闩(Latch)的封锁类型也比较简单,就是共享(Share)和独占(Exclusive)两种类型。

为了适用 DMDSC 集群,我们同样将闩划分为全局闩服务(Global Latch Services,简称 GLS)和本地闩服务(Local Latch Services,简称 LLS)两个部分。但是,为了与全局封锁服务 GLS 和本地封锁服务 LLS 的名字简称区分开来,我们以使用最为频繁的 Buffer 来命名全局闩服务。因此,全局闩服务也称为全局缓冲区服务(Global Buffer Services),简称 GBS;本地闩服务也称为本地缓冲区服务(Local Buffer Services),简称 LBS。

整个系统中,每一个节点上都部署一个 GBS 和一个 LBS。GBS 服务协调节点间的 Latch 封锁请求、以及 Latch 权限回收。GBS 与 GTV/GLS 由控制节点统一管理不同,GBS 不是集中式管理,而是由 DMDSC 集群中的所有节点共同管理,Buffer 对象会根据数据页号(Page No)对数据页进行划分,分给某一个节点的 GBS 服务处理。LBS 服务与 LLS/LTV 一样,部署在每一个节点,LBS 服务根据用户请求,向 GBS 发起 Latch 封锁,或者根据 GBS 请求,回收本地的 Latch 封锁。

为了避免两个或多个节点同时修改同一个数据页导致数据损坏,或者数据页修改过程中别的节点读取到无效内容,DMDSC 集群中数据页的封锁流程做了一些改变。与单节点相比,增加了全局 Latch 封锁、释放两个步骤。同时在获取全局 Latch 授权后,仍然需要进行正常的本地 Latch 封锁,有效避免了节点内的访问冲突。

4.4 缓存交换

根据目前的硬件发展状况来看,网络的传输速度比磁盘的读、写速度更快,因此,DMDSC 集群引入了缓存交换(Buffer Swap)技术,节点间的数据页尽可能通过网络传递,避免通过磁盘的写入、再读出方式在节点间传递数据,从而减少数据库的 IO 等待时间,提升系统的响应速度。

缓存交换的实现基础是 GBS/LBS 服务,在 GBS/LBS 中维护了 Buffer 数据页的相关信息。包括:1. 闩的封锁权限(LATCH);2. 哪些站点访问过此数据页(Access MAP);3. 最新数据保存在哪一个节点(Fresh EP)中;4. 以及最新数据页的 LSN 值(Fresh LSN)等信息。这些信息作为 LBS 封锁、GBS 授权和 GBS 权限回收请求的附加信息进行传递,因此并不会带来额外的通讯开销。

下面以两节点 DMDSC 集群(EP0/EP1)访问数据页 P1 为例子。初始页 P1 位于共享存储上,P1 的 GBS 控制结构位于节点 EP1 上。初始页 P1 还没有被任何一个节点访问过,初始页 P1 的 LSN 为 10000。通过几种常见场景分析,逐步深入,解析缓存交换的原理。

  • 场景 1

节点 EP0 访问数据页 P1。

  1. 节点 EP0 的本地 LBS 向 EP1 的 GBS 请求数据页 P1 的 S LATCH 权限
  2. 节点 EP1 的 GBS 修改 P1 控制结构,记录访问节点 EP0 的封锁模式为 S LATCH(数据分布节点为 EP0),并响应 EP0 的 LBS 请求
  3. 节点 EP0 的 LBS 获得 GBS 授权后,记录获得的授权模式是 S_LATCH,P1 数据不在其他节点的 Buffer 中,发起本地 IO 请求,从磁盘读取数据。IO 完成后,修改 LBS 控制结构,记录数据页上的 LSN 信息

图 4.2 本地 IO.png

图4.2 本地IO
  • 场景 2

节点 EP1 访问数据页 P1。

  1. 节点 EP1 本地 LBS 向 EP1 的 GBS 请求数据页 P1 的 S LATCH 权限
  2. 节点 EP1 的 GBS 修改控制结构,记录访问节点 EP1 的封锁模式为 S LATCH(数据分布节点为 EP0/EP1),并响应 EP1 的 LBS 请求
  3. 节点 EP1 的 LBS 获得 GBS 授权后,记录获得的授权模式是 S LATCH,根据数据分布情况,EP1 向 EP0 发起 P1 的读请求,通过内部网络从 EP0 获取数据,而不是重新从磁盘读取 P1 数据

图 4.3 远程 IO.png

图4.3 远程IO
  • 场景 3

节点 EP0 修改数据页 P1。

  1. 节点 EP0 本地 LBS 向 EP1 的 GBS 请求数据页 P1 的 X LATCH 权限(附加 LSN 信息)
  2. 节点 EP1 的 GBS 修改控制结构的 LSN 值,从 EP1 的 LBS 回收 P1 的权限
  3. 修改访问节点 EP0 的封锁模式为 S + X LATCH,并响应 EP0 的 LBS 请求
  4. 节点 EP0 的 LBS 获得 GBS 授权后,记录获得的授权模式是 S + X LATCH
  5. 节点 EP0 修改数据页 P1,LSN 修改为 11000

这个过程中,只有全局 Latch 请求,数据页并没有在节点间传递。

图 4.4 GBS 管理.png

图4.4 GBS管理

修改之后,数据页 P1 的 LSN 修改为 11000。如下所示:

图 4.5 数据修改.png

图4.5 数据修改
  • 场景 4

节点 EP1 修改数据页 P1。

1.节点 EP1 本地 LBS 向 EP1 的 GBS 请求数据页 P1 的 X LATCH 权限

2.节点 EP1 的 GBS 发现 P1 被 EP0 以 S + X 方式封锁,向 EP0 发起回收 P1 权限的请求

3.节点 EP0 释放 P1 的全局 LATCH,响应 GBS,并且在响应消息中附加了最新的 PAGE LSN 值

4.节点 EP1 的 GBS 收到 EP0 的响应后,修改 GBS 控制结构,记录最新数据保存在 EP0,最新的 LSN 值信息,记录 EP1 获得的授权模式是 S + X LATCH(此时,数据分布节点仍然是 EP0/EP1),并授权 EP1 的 LBS

5.节点 EP1 的 LBS 收到授权信息后,记录获得的授权模式是 S + X LATCH,并根据数据分布情况,向节点 EP0 发起数据页 P1 的读请求

6.节点 EP1 修改数据页 P1,LSN 修改为 12000

图 4.6 GBS 管理.png

图4.6 GBS管理

修改之后,数据页 P1 的 LSN 修改为 12000。如下所示:

图 4.7 数据修改.png

图4.7 数据修改

这个过程中,数据页 P1 的最新数据从 EP0 传递到了 EP1,但并没有产生磁盘 IO。

4.5 重做日志管理

REDO 日志包含了所有物理数据页的修改内容,Insert/delete/update 等 DML 操作、Create Table 等 DDL 操作,最终都会转化为对物理数据页的修改,这些修改都会反映到 REDO 日志中。一般说来,一条 SQL 语句在系统内部会转化为多个相互独立的物理事务来完成,物理事务提交时产生 REDO 日志,并最终写入联机 REDO 日志文件中。

一个物理事务包含一个或者多个 REDO 记录(Redo Record,简称 RREC),每条 REDO 记录都对应一个修改物理数据页的动作。根据记录内容的不同,RREC 可以分为两类:物理 RREC 和逻辑 RREC。物理 RREC 记录的是数据页的变化情况,内容包括:操作类型、修改数据页地址、页内偏移、数据页上的修改内容、长度信息(变长类型的 REDO 记录才有)。逻辑 RREC 记录的是一些数据库逻辑操作步骤,主要包括:事务启动、事务提交、事务回滚、字典封锁、事务封锁、B 树封锁、字典淘汰等,一般只在配置为 Primary 模式时才产生逻辑 RREC。

图 4.8 PTX 和 RREC 结构图.png

图4.8 PTX和RREC结构图

DMDSC 集群中,各个节点拥有独立的日志文件,Redo 日志的 LSN 值也是顺序递增的,Redo 日志只会写入当前数据库实例的联机日志文件,与集群系统中的其他数据库实例没有关系。考虑到所有节点都可以修改数据,同一个数据页可能由不同节点先后修改,为了体现修改的先后顺序,确保故障恢复时能够按照操作的顺序将数据正确恢复。DMDSC 集群要求对同一个数据页的修改,产生的 LSN 值是全局递增的,各个节点对同一数据页的修改在日志系统中是严格有序的。但是,针对不同数据页的修改并不要求 LSN 是全局递增的,也就是说只有多个节点修改相同数据页时,才会产生全局 LSN 同步问题。并且 LSN 全局同步,是在缓存交换时附带完成的,并不会增加系统的额外开销。

与单节点系统相比,DMDSC 的日志系统存在以下差异:

1.本地 REDO 日志系统中,LSN 值保证是递增的,后提交物理事务的 LSN 值一定更大;但顺序提交的两个物理事务产生的 LSN 值,不能保证一定是连续的。

2.全局 REDO 日志系统中,LSN 值不再严格保证唯一性。不同节点可能存在 LSN 值相等的重做日志记录。

3.故障重启时,控制节点需要重做所有节点的 REDO 日志,重做过程中会根据 LSN 排序,从小到大依次重做。

4.联机 REDO 日志文件需要保存在共享存储中。

4.6 回滚记录管理

DMDSC 集群的多版本并发控制(MVCC)实现策略是,通过回滚记录获取数据的历史版本,通过活动事务视图判断事务可见性、确定获取指定版本数据。因此,回滚记录也必须进行全局维护,有可能在节点间进行传递。与单节点一样,DMDSC 集群中只有一个回滚表空间,回滚记录保存在回滚页中,回滚页与保存用户记录的数据页一样,由 Buffer 系统管理,并通过缓存交换机制实现全局数据共享。

为了减少并发冲突,提高系统性能,DMDSC 集群中为每个节点分配了一个单独的回滚段(Segment),虽然这些回滚段位于同一个回滚表空间中,但是各个节点的回滚页申请、释放,并不会产生全局冲突。

与重做日志不同,DMDSC 集群故障重启时,各个活动节点扫描各自的回滚段,控制节点增加扫描故障节点回滚段,收集未提交事务进行回滚,收集已提交事务进行 Purge 操作。

微信扫码
分享文档
扫一扫
联系客服