openGauss数据库源码解析 | 存储引擎源码解析(8)

本文介绍了openGauss内核新增的ustore存储模式,它采用原地更新策略,通过分离有效数据和垃圾数据、多版本索引等技术提高垃圾回收效率和并发处理能力。文章详细讨论了多版本控制的不同设计选项及其优缺点,以及ustore在这些方面的改进和融合引擎架构设计原则。
摘要由CSDN通过智能技术生成

4.2.4  ustore

ustore属于In-place Update更新模式,中文意思为:原地更新,是openGauss内核新增的一种存储模式。openGauss内核当前使用的行引擎采用的是Append Update(追加更新)模式,该模式在INSERT、DELETE、HOT UPDATE(页面内更新)的场景下有较好的表现。但对于非HOT UPDATE场景,垃圾回收不够高效。

In-place Update存储模式提供“原地更新”能力,主要思路是将最新版本的“有效数据”和历史版本的“垃圾数据”分离存储。将最新版本的“有效数据”存储在数据页面上,而单独开辟一段undo(回滚)空间,用于统一管理历史版本的“垃圾数据”,因此数据空间不会由于频繁更新而膨胀,垃圾回收效率更高。通过NUMA-aware的undo子系统设计,使得undo子系统在多核平台上高效扩展。同时通过对元组和数据页面结构的重新设计,减少存储空间的占用。采用多版本索引技术,解决索引膨胀问题,彻底去除autovacuum(垃圾清理线程)机制,提升存储空间的回收复用效率。

1. 整体框架及代码概览

数据库中数据处理的本质是在保证ACID的基础上支持尽量高的并发查询。这种状况下,并发控制、页面多版本控制以及页面存储结构相互耦合在一起,数据库存储引擎需要进行整体设计从而在高并发的状况下保证各个事务处理看到类似串行执行的效果。

在整个技术体系中多版本控制用来提升读写并发能力,按照多版本排列方式可以分为两类。

(1)Oldest to New,即版本按照从最老到最新的方式进行链接,当一个事务访问该元组时,先看到这个元组最老的版本,同时使用对应的可见性判断机制,看是否是自己可见的版本,如果不是则沿着版本链条继续往后看较新的版本是不是自己需要的。
(2)Newest to Old,即版本按照从最新到最老的方式进行连接,当一个事务访问该元组时,先看到这个元组最新的版本,同时使用对应的可见性判断机制,看是否是自己可见的版本,如果不是则沿着版本链条继续往后看较老的版本是不是自己需要的。

在上面的描述中又引出一个设计点,如何组织新老数据,有如下几种方式。

(1) 将新数据和老数据放在同样的页面内,即每个数据页内放置着各个元组的新老数据,在需要进行不可见数据版本回收的时候需要遍历所有的页面。
(2) 将最新数据和老数据分离存储,在实际的数据页面内放置最新版本数据,所有的老版本数据都集中存储,新版本数据通过一个指针指向老版本所在的数据区域,当进行不可见老版本数据回收的时候只要扫描老版本集中存放的位置即可。
当新老数据分别存储的时候又引出第三个设计点,在对同一个页面或者元组反复读取时,是否要还原对应的页面在数据缓冲区中,这个设计点有如下几种方式。
(1) 访问旧元组所在的页面时,还原该页面,并将该页面的旧版本放入数据缓冲区中,节省一定时间内其他线程多次访问该版本页面带来的合成开销。弊端是占用更大的内存空间,同时缓冲区淘汰管理在原始LRU(Least Recently Used,最近最少使用算法)基础上同时要考虑页面版本。这种方式对应PCR(Page Consistency Read,页面一致性读),其本质的设计理念是空间换时间。
(2) 访问元组时,沿着版本链还原该元组,直到找到自己对应的版本。这种方式对于短时间访问冲突不高的场景能够降低内存使用,但如果短时间内高频访问一个页面内的元组,则每次都会遍历版本链造成访问效率低下。这种方式对应RCR(Row Consistency Read,行一致性读)。

按照上面的描述,整个多版本控制设计分为三个维度,如图4-10、表4-15所示。

图4-10  多版本控制设计维度

表4-15  多版本控制设计维度

维度

备选

版本存储方式

集中存储

分离存储

版本链组织方式

Oldest to New

Newest to Old

老版本管理方式

1、RCR

2、PCR

当前openGauss在版本存储方式、版本链组织方式上的设计选择是集中存储 + Oldest to New,在清理数据旧版本时需要遍历所有的页面找到不可见的元组版本然后清除。商用及开源的常见数据库的多版本控制设计三维度选择如表4-16所示。

表4-16  当前数据库多版本控制设计选择

数据库

架构设计选择

版本存储方式

版本链组织方式

老版本管理方式

常见数据库

分离存储

Newest to Old

PCR

集中存储

Oldest to New

RCR

分离存储

Oldest to New

RCR

不同的多版本控制设计都不能做到尽善尽美,都有些不足之处,相关的缺点如下。

(1)多核系统上扩展性较差,不支持多核处理器的NUMA感知;
(2)依赖于Vacuum进行老版本回收,后台线程定期清理;
(3)缺乏对索引多版本,全局索引、闪回等功能的支持;
(4)PCR管理方式,内存管理开销较大。

openGauss的ustore存储模式最大程度结合各种设计的优势,在多版本管理上的架构设计采取的组合如表4-17所示。

表4-17  ustore在多版本管理上的架构设计

维度

架构设计选择

版本存储方式

分离存储

版本链组织方式

Newest to old

老版本管理方式

PbRCR(Page Based RCR,基于页面的行一致性读)

同时为了事务能够跨存储格式查询,并复用现有备份、恢复、升级等能力,openGauss定义如下的融合引擎架构设计原则。

(1) 一套并发控制系统。
(2) 一套系统表管理系统。
(3) 一套日志管理系统。
(4) 一套锁管理系统。
(5) 一套恢复系统。

ustore架构如图4-11所示。

 图4-11  ustore架构示意图

ustore和astore共用事务管理、并发控制、缓冲区管理、检查点、故障恢复管理与介质管理器管理。ustore主要功能模块如表4-18所示。

表4-18  ustore主要功能模块

模块

说明

代码位置

ustore表存取管理

向上对接SQL引擎,提供对ustore表的行级查询、插入、删除、修改等操作接口,向下根据ustore表页间、页内结构,以及ustore表元组结构,完成对ustore表文件的遍历和增删改查操作

主要在“src/gausskernel/storage/access/ustore”目录(单表文件管理)下

ustore索引存取管理

向上对接SQL引擎,提供对索引表的行级查询、插入、删除等操作接口,向下根据索引表页间、页内结构,以及索引表元组结构,完成对指定索引键的查找和增删操作

抽象框架代码在“src/gausskernel/storage/access/ubtree”目录下

ustore表页面结构

包括ustore表元组在页面内的具体组织形式,在页面内插入元组操作、页面整理操作、页面初始化操作等

主要代码在“src/gausskernel/storage/access/ustore/knl_upage”目录中

ustore表元组结构

包括ustore表元组的结构、填充、解构、修改、字段查询、变形等操作

主要代码在“src/gausskernel/storage/access/ustore/knl_utuple.cpp”文件中

Undo记录结构

包括undo记录的结构、填充、编码、解码等操作

主要代码在“src/gausskernel/storage/access/ustore/undo”目录中

多版本索引

包括 ustore 专用多版本索引 ubtree 的页面结构、查询、修改、可见性检查、垃圾回收等模块

主要代码在“src/gausskernel/storage/access/ubtree”目录中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值