写点什么

openGauss 数据库源码解析系列文章——存储引擎源码解析(一)

作者:openGauss
  • 2022 年 1 月 05 日
  • 本文字数:3593 字

    阅读完需:约 12 分钟

openGauss数据库源码解析系列文章——存储引擎源码解析(一)

OLTP、OLAP 业务各自对数据库的存储引擎提出了不同的要求,而 openGauss 能够支持多个存储引擎来满足来自不同场景的业务诉求。本篇将从存储引擎整体架构及代码概览磁盘引擎两方面展开介绍,其中磁盘引擎从整体框架及代码概览、行存储统一访存接口两点展开讨论。

一、存储引擎整体架构及代码概览

从整个数据库服务的组成构架来看,存储引擎向上对接 SQL 引擎,为 SQL 引擎提供或接收标准化的数据格式(元组或向量数组);向下对接存储介质,按照特定的数据组织方式,以页面、列存储单元(CU,compression unit)或其他形式为单位,通过存储介质提供的特定接口,对存储介质中的数据完成读、写操作。在此基础之上,存储引擎通过日志系统提供数据的持久化和可靠性能力;通过并发控制(事务)系统保证同时执行的、多个读写操作之间的原子性、一致性和隔离性;通过索引系统提供对特定数据的加速寻址和查询能力;通过主备复制系统提供整个数据库服务的高可用能力。



|图 1  openGauss 存储引擎整体构架示意图|

图 1 是 openGauss 存储引擎整体构架的示意图。总体上,根据存储介质和并发控制机制,存储引擎分为磁盘引擎和内存引擎两大类。磁盘引擎主要面向通用的、大容量的业务场景,内存引擎主要面向容量可控的、追求极致性能的业务场景。在磁盘引擎中,为了满足不同业务场景对于数据不同的访问和使用模式,openGauss 进一步提供了 astore(append-store,追加写优化格式)、cstore(column store,列存储格式)以及可拓展的数据元组和数据页面组织格式。在内存引擎中,openGauss 当前提供基于 Masstree 结构组织的 mstore(memory-store,内存优化格式)数据组织格式。

上述几种引擎和存储格式的介绍如表 1 所示。

表 1  openGauss 存储引擎种类

 openGauss 存储引擎具有如下几个特点。

(1)统一的日志系统。

在 openGauss 的存储引擎中,磁盘引擎和内存引擎共用同一套日志系统,以保证在数据库故障恢复场景下,各个引擎内和各个引擎间的数据持久性和一致性。基于上述统一的日志系统,openGauss 支持主、备机(主、备数据库服务进程)之间的流式日志复制,并通过 Quorum 复制协议,在保证复制一致性的前提下,尽可能降低日志同步对主机业务的影响。

(2)多种并发控制和事务系统。

在 openGauss 的存储引擎中,有两种并发控制和事务系统:适合高并发、高冲突、追求确定性结果的悲观并发控制机制;适合低冲突、短平快、低时延的乐观并发控制机制。

在磁盘引擎中,采用读写冲突优化的悲观并发控制机制:对于读、写并发操作,采用多版本并发控制(MVCC,multi-version concurrency control);对于写、写并发操作,采用基于两阶段锁协议(2PL,two-phase locking)的悲观并发控制(PCC,pessimistic concurrency control)。

在内存引擎中,采用乐观并发控制来尽可能降低并发控制系统对业务的阻塞,以获得极致的事务处理性能和时延。

(3)表级存储格式/存储引擎和跨格式事务。

在 openGauss 的存储引擎中,支持在建表语句中指定目标表的存储格式和存储引擎,即行存储 astore、列存储 cstore、内存 mstore 和后续扩展的其他存储格式或存储引擎。因此,在同一个数据库中,为了适配不同的业务场景,用户可以创建不同存储格式或不同存储引擎的表。进一步,当前 openGauss 在同一个事务内,支持对同一引擎不同存储格式的表的读写查询,这将极大地简化不同存储格式表中数据一致性、同步性和实时性的运维难度。后续 openGauss 版本计划支持跨引擎事务,这将使得 openGauss 数据库在面对多样化的业务场景时显得更为游刃有余。

(4)统一的行存储访存接口。

在 openGauss 的磁盘引擎中,行存储类存储格式是最传统也是使用场景最广泛的存储格式。针对不同的业务场景,行存储格式需要进行不同的优化和设计。为了便于后续新型行存储格式的扩展,在 openGauss 中提供了统一的行存储访存接口层,为上层 SQL 引擎屏蔽了底层不同的行存储数据组织形式。

对于不同的行存储数据格式,它们向上对接统一的行存储访存接口,向下共享缓冲区管理、事务并发控制、日志系统、持久化和故障恢复、主备系统、索引机制。同时,不同的行存储数据格式内部又实现了不同的元组和页面格式,以及在此之上的访存接口、元组多版本、页面多版本、空闲空间管理回收等不同功能。

openGauss 存储引擎的代码主要位于“src/gausskernel/storage/”目录下,具体目录结构如下:


--src    --gausskernel        --storage            --access            --buffer            --bulkload            --cmgr            --cstore            --dfs            --file            --freespace            --ipc            --large_object            --lmgr            --mot            --page            --remote            --replication            --smgr
复制代码

每个子目录都是一个相对独立的模块,和本章内容相关的如表 2 所示。

表 2  存储引擎子目录

 除了以上的这些模块之外,storage 目录下剩余的子目录分别属于:外表批量导入模块(bulkload 子目录)、外表服务器连接模块(dfs 子目录)、进程间通信模块(ipc 子目录)、大对象模块(large_object 子目录)、锁管理模块(lmgr 子目录)。

openGauss 存储引擎相关的后台线程实现代码包含在“src/gausskernel/process/postmaster”目录下,简要介绍如表 3。在后序介绍具体相关模块消息序列时会详细介绍这些线程的工作原理和执行流程。

表 3  存储引擎后台线程

二、磁盘引擎

磁盘引擎是数据库系统中最常用的存储引擎,openGauss 提供不同存储格式的磁盘引擎来支持大容量(数据量大于内存空间)场景下的 OLTP、OLAP 和 HTAP(hybrid transactions and analytics processing,混合交易和分析处理)业务。本节主要介绍 openGauss 数据库内核中磁盘引擎的实现方式。

(一)磁盘引擎整体框架及代码概览

磁盘引擎的整体框架如图 1 中所示。根据与上层 SQL 引擎之间交互的数据结构类型,可以分为行存储格式和列存储格式。这两种数据格式共用相同的事务并发控制、日志系统、持久化和故障恢复、主备系统。

在此基础之上,行存储格式内部设计为可以支持多种不同子格式的可扩展架构。不同行存储子格式之间共用相同的行存储统一访存接口(table access method)、共享缓冲区、索引机制等。当前仅支持追加写优化的 astore 子格式,后续计划支持写优化的 ustore 子格式以及面向其他场景优化的其他子格式。另一方面,在 openGauss 行存储格式中,对同一行数据的写-写查询冲突通过两阶段锁协议来实现并发控制(参见第 5 章中关于行级锁的介绍),对同一行数据的读-写查询冲突通过行级多版本技术来实现互不阻塞的、高效的并发控制。对于不同的行存储子格式,可能采用不同的行级多版本实现方式,从而也会引入不同的、清理历史版本的空闲空间管理和回收机制。

磁盘引擎的主要功能模块和代码分布如表 4 所示。

表 4  磁盘引擎功能模块

在上述模块基础之上,openGauss 磁盘引擎还包括 CU 压缩、外表、批量导入等功能,代码分布在“src/gausskernel/storage/cstore/compression”、“src/gausskernel/storage/access/dfs”、“src/gausskernel/storage/bulkload”等目录下。

openGauss 磁盘引擎的关键技术整体来说包括:

(1)基于事务提交逻辑时间戳的快照隔离机制以及多版本并发控制技术。

(2)基于事务号(xid,全称 transaction identifier)的行级多版本管理技术。

(3)基于大内存设计的共享缓冲区管理和淘汰算法。

(4)平滑无性能波动的增量检查点(checkpoint)技术。

(5)基于并行回放的快速故障实例恢复技术。

(6)支持事务语义的 DML 操作和 DDL 操作。

(7)面向 OLAP 场景的 cstore 列存储格式。当表中列数比较多、但是访问的列数比较少时可以大大减少不必要的列的 I/O 开销。

(8)面向 OLAP 场景的 cstore 列存储批量访存接口。向上支持以向量数组为粒度的批量数据访存接口,结合向量化执行引擎提升 CPU 缓存命中率和系统吞吐率。

(9)面向 OLAP 场景的 cstore 列存储高效压缩算法。基于同一列比较相似的数据特征,在大数据量下获得很高的压缩效果,减少系统的 I/O 开销。

(二)行存储统一访存接口

如上所述,在 openGauss 中,提供行存储统一访存接口层,来屏蔽不同行存储子格式内部实现机制对 SQL 引擎的影响。该行存储统一访存接口层被称为 Table Access Method 层。根据 SQL 引擎对行存储表的访存方式,将访存接口分为 5 类,如表 5 所示。每一类接口的具体操作如表 6 至表 10 所示。

表 5  Table Access Method 定义的访存接口


表 6  Tuple AM、Slot AM 类访存接口



表 7  TableScan AM 类访存接口- 表 8  DQL AM 类访存接口


表 9  DML AM 类访存接口 - 表 10  DDL AM 类访存接口


对于每一个行存储子格式,需要提供上述这五类访存接口的各自实现方式,并注册到 g_tableam_routines 全局行存储访存接口数组中。SQL 引擎在调用某个访存接口时,根据 Relation 结构体中表的子格式类型(rd_tam_type 成员),来调用对应的子格式访存接口。

由于内容较多,关于磁盘引擎方面的其他内容将在下篇图文中进行分享,敬请期待!

用户头像

openGauss

关注

还未添加个人签名 2020.11.13 加入

openGauss是一款高性能、高安全、高可靠的企业级开源关系型数据库。

评论

发布
暂无评论
openGauss数据库源码解析系列文章——存储引擎源码解析(一)