openGauss源码解析(33)
openGauss源码解析:存储引擎源码解析(1)
第4章 存储引擎源码解析
OLTP、OLAP业务各自对数据库的存储引擎提出了不同的要求,而openGauss能够支持多个存储引擎来满足来自不同场景的业务诉求。本章将逐一介绍各种存储引擎和对应的源码。
4.1 存储引擎整体架构及代码概览
从整个数据库服务的组成构架来看,存储引擎向上对接SQL引擎,为SQL引擎提供或接收标准化的数据格式(元组或向量数组);向下对接存储介质,按照特定的数据组织方式,以页面、列存储单元(CU,compression unit)或其他形式为单位,通过存储介质提供的特定接口,对存储介质中的数据完成读、写操作。在此基础之上,存储引擎通过日志系统提供数据的持久化和可靠性能力;通过并发控制(事务)系统保证同时执行的、多个读写操作之间的原子性、一致性和隔离性;通过索引系统提供对特定数据的加速寻址和查询能力;通过主备复制系统提供整个数据库服务的高可用能力。
图4-1 openGauss存储引擎整体构架示意图
图4-1是openGauss存储引擎整体构架的示意图。总体上,根据存储介质和并发控制机制,存储引擎分为磁盘引擎和内存引擎两大类。磁盘引擎主要面向通用的、大容量的业务场景,内存引擎主要面向容量可控的、追求极致性能的业务场景。在磁盘引擎中,为了满足不同业务场景对于数据不同的访问和使用模式,openGauss进一步提供了astore(append-store,追加写优化格式)、cstore(column store,列存储格式)以及可拓展的数据元组和数据页面组织格式。在内存引擎中,openGauss当前提供基于Masstree结构组织的mstore(memory-store,内存优化格式)数据组织格式。
上述几种引擎和存储格式的介绍如表4-1所示。
表4-1 openGauss存储引擎种类
父类 (存储介质和并发控制) |
子类 (数据组织形式) |
说明 |
---|---|---|
磁盘引擎 (磁盘介质, 多版本和悲观并发控制(pessimistic concurrency control,PCC)) |
astore (追加写优化格式) |
主要面向通用的在线交易处理类业务应用场景,适合高并发、小数据量的单点或小范围数据读、写操作。astore为行存储格式,向上提供元组形式的读、写;向下以页面为单位通过可扩展的介质管理器对存储介质进行读、写操作;并通过页面粒度的共享缓冲区来优化读、写操作的效率。当前行存存储格式默认的介质管理器采用磁盘文件系统接口,后续可扩展支持块设备等其他类型的存储介质 |
cstore (列存储格式) |
面向联机分析处理类业务应用场景,适合大数据量的复杂查询和数据导入。cstore为列存存储格式,向上提供向量数组形式的读、写接口;向下以压缩单元为单位将数据保存在磁盘文件系统中(当前列存存储格式唯一支持的存储介质)。考虑到联机分析处理类业务通常以读操作为主,因此还提供了以压缩单元为粒度的只读共享缓冲区,以加速压缩单元的读操作性能 |
|
扩展存储格式 |
对于行存储类存储格式,openGauss提供了与上层SQL引擎对接的、统一的、可扩展的访存接口层(table access method)。该行存储统一访存接口层为SQL引擎提供元组形式的读、写接口,同时屏蔽了下层各种不同行存储类存储格式的内部实现,从而实现了SQL引擎与存储引擎(行存储类磁盘引擎)的解耦,大幅提升了不同存储格式之间的隔离性和开发效率 当前行存储类存储格式支持追加写优化的astore格式,后续会支持更新写优化的ustore格式等其他数据组织格式 |
|
内存引擎 (内存介质, 乐观并发控制(OCC,optimistic concurrency control)) |
mstore (内存存储格式) |
mstore内存引擎面向超低时延和超高吞吐量的OLTP场景。数据以元组粒度存储于内存介质中,得益于内存介质读、写操作的超低时延(与磁盘介质相比),内存引擎可以提供极致的OLTP业务性能。内存引擎通过openGauss的外表访存接口实现与SQL引擎的数据交互 |
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
每个子目录都是一个相对独立的模块,和本章内容相关的如表4-2所示。
表4-2 存储引擎子目录
模块名 |
子目录 |
说明 |
---|---|---|
访存模块 |
access子目录 |
主要包括:各种行存储格式中,元组格式;元组与页面之间的转换和访存管理;元组扫描、插入、删除和更新功能的接口实现;几类索引,包括B-Tree、hash、GIN(generalized inverted index,通用倒排索引)、GiST(generalized search tree,通用搜索树)、psort(列存储局部排序索引),的访存管理和接口实现;各类数据库操作对应的日志实现和恢复机制;以及事务模块实现 |
行存储共享缓冲区模块 |
buffer子目录 |
主要包括:行存储共享缓冲区的结构;物理页面和缓冲区页面的映射管理;缓存页面的加载和淘汰算法等 |
列存储只读共享缓冲区模块 |
cmgr子目录 |
主要包括:cstore列存储格式只读共享缓冲区的结构;压缩单元和缓冲区的映射管理;缓冲压缩单元的加载和淘汰算法等 |
列存储访存模块 |
cstore子目录 |
主要包含:cstore列存储格式中,向量数组与压缩单元之间的转换和访存管理;以及在此基础之上向量数组的扫描、插入、删除和更新功能的接口实现 |
文件操作和虚拟文件描述符模块 |
file子目录 |
主要包含:磁盘文件系统存储介质的文件和目录操作;虚拟文件描述符的实现和管理 |
行存储空闲空间管理模块 |
freespace子目录 |
主要包含:各种行存储格式中,页面空闲空间的管理 |
内存引擎模块 |
mot子目录 |
主要包含:内存引擎的实现 |
页面模块 |
page子目录 |
主要包含:各种行存储格式中,页面格式、页面校验、页面加密和页面压缩 |
备机页面修复模块 |
remote子目录 |
主要包含:从备机获取完整页面或压缩单元,用于修复主机损坏的页面或压缩单元 |
主备日志复制模块 |
replication子目录 |
主要包含:主备日志发送和接收线程的实现;流式日志同步功能的实现;Quorum复制协议的实现,逻辑日志的实现以及主备重建;主备心跳检测功能的实现 |
存储介质管理模块 |
smgr子目录 |
主要包含:存储介质管理层的实现;磁盘文件系统(当前默认的存储介质)的基本功能接口实现 |
除了以上的这些模块之外,storage目录下剩余的子目录分别属于:外表批量导入模块(bulkload子目录)、外表服务器连接模块(dfs子目录)、进程间通信模块(ipc子目录)、大对象模块(large_object子目录)、锁管理模块(lmgr子目录)。
openGauss存储引擎相关的后台线程实现代码包含在“src/gausskernel/process/postmaster”目录下,简要介绍如表4-3。在后序介绍具体相关模块消息序列时会详细介绍这些线程的工作原理和执行流程。
表4-3 存储引擎后台线程
线程名 |
文件名 |
说明 |
---|---|---|
ADIO线程 |
aiocompleter.cpp |
该线程主要负责异步-同步读写操作(ADIO,asynchronous-direct input-ouput)的后台预取和回写 |
autovacuum线程 |
autovacuum.cpp |
该线程主要负责磁盘引擎的后台空闲空间回收 |
bgwriter线程 |
bgwriter.cpp |
该线程主要负责行存储表的后台脏页写入磁盘(当内存数据页跟磁盘数据页内容不一致的时候,称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”) |
cbmwriter线程 |
cbmwriter.cpp |
该线程主要负责增量页面修改信息的后台异步提取和CBM(changed block map,修改页面位图)日志的记录 |
checkpointer线程 |
checkpointer.cpp |
该线程主要负责在后台定期推进数据库的故障恢复点 |
lwlockmonitor线程 |
lwlockmonitor.cpp |
该线程主要负责业务线程轻量级锁的死锁检测 |
pagewriter线程 |
pagewriter.cpp |
该线程主要负责行存储共享缓冲区的脏页写入磁盘 |
pgarch线程 |
pgarch.cpp |
该线程主要负责在后台定期执行日志归档命令 |
remoteservice线程 |
remoteservice.cpp |
该线程主要负责接收主机页面修复RPC(remote procedure call,远程函数调用)请求 |
startup线程 |
startup.cpp |
该线程为数据库故障恢复和回放日志的主线程 |
walwriter线程 |
walwriter.cpp |
该线程主要负责在后台异步写入磁盘日志 |