【连载】如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(3)

【连载】如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(3),第1张

【连载】如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(3)

前文回顾:

1.如何掌握openGauss数据库核心技术?秘诀一:拿捏SQL引擎(1)

2.如何掌握openGauss数据库核心技术?秘诀一:拿捏SQL引擎(2)

3.如何掌握openGauss数据库核心技术?秘诀一:拿捏SQL引擎(3)

4.如何掌握openGauss数据库核心技术?秘诀一:拿捏SQL引擎(4)

5.如何掌握openGauss数据库核心技术?秘诀二:拿捏执行器技术(1)

6.如何掌握openGauss数据库核心技术?秘诀二:拿捏执行器技术(2)

7.如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(1)

8.如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(2)

目录

  • openGauss数据库SQL引擎

  • openGauss数据库执行器技术

  • openGauss存储技术

一、openGauss存储概览

二、openGauss行存储引擎

Ⅰ、行存储引擎总体架构

Ⅱ、行存储的基本模型与页面组织结构

Ⅲ、行存储的多版本管理以及DML *** 作

Ⅳ、基于CSN的MVCC机制

Ⅴ、行存储的空间回收

Ⅵ、行存储的共享缓存管理

Ⅶ、并行日志系统设计

Ⅷ、持久化及故障恢复系统设计

三、openGauss列存储引擎

四、openGauss内存引擎

  • openGauss事务机制

  • openGauss数据库安全

openGauss存储技术

二.openGauss行存储引擎

行存储的共享缓存管理

06

前面提到,行存储是一个基于磁盘的存储引擎。为了避免IO的高昂开销,存储引擎会缓存一部分页面在内存中,便于随时对其进行检索和更改。存储引擎会对缓存的页面进行筛选、替换和淘汰,保证留存在缓存的页面能够提高整个引擎的执行效率。

行存储中也有着种类较多的缓存,除去正常数据页面的缓存之外,还存在用于缓存各类表的元信息的Relation Cache(数据表缓存),以及用于加速数据库系统信息以及系统表 *** 作的Catalog Cache(系统表缓存)。这些种类的缓存都以page(页面)的形式归由共享缓冲区结构管理。

共享缓冲区由大量的页面槽位构成,槽位本身有对应的描述结构体,以及用于管理处于这个 *** 作的并发 *** 作的页面级别锁,并配有一个空闲链表来进行空闲空间管理。如图19所示。

图19  共享缓冲区

行存储引擎中 *** 作对事务的读写请求,都会被先传递至共享缓冲区。对一个页面的请求会现在缓冲区内进行搜索,如果未命中,则获取一个空的槽位(可能需要淘汰掉已经在缓冲区中不常用的页面),再与文件系统进行交互将所需页面读到槽位中,加锁并使用。根据业务的特征和负载、以及共享缓冲区的大小,已经在缓冲区内的数据页面会被反复命中,避免了与磁盘的IO开销,从而加速整个事务处理流程。

对页面的更改也会放在缓存中并被标为脏页面。此时后台写线程(background writer)会定期对脏页面进行清理和刷盘 *** 作,把空间返还给缓冲区。另一方面,Checkpoint,也就是检查点 *** 作,在进行时也会将所有的页面刷盘,确保数据的持久化。这里需要注意的一个概念是,当一个事务提交后,这个事务执行过程中更改的页面并不一定被刷盘至磁盘,事务本身的持久化机制实际上是由事务强制刷盘的WAL,也就是xlog,来保证的。在Checkpoint *** 作后,因为相关页面都已经持久化至磁盘,因此Checkpoint时间点之前的xlog,就可以被回收了。这个机制会在后续的章节继续展开。

共享缓冲区实际上是内存与持久化存储中协调管理调度的核心机制,对数据库管理系统的效率有着很大的影响。为了进一步提升缓冲区中页面的命中率,一些可能会影响缓冲区内页面与业务关联性的 *** 作,都会使用一个专门单独开辟的缓冲区,Ring Buffer(环状缓冲区)。批量的读、批量的写、以及Vacuum的页面清理,都属于这类 *** 作。

并行日志系统设计

07

数据库的日志系统非常关键,它是数据持久化的关键保证。传统数据库一般都采用串行刷日志的设计,因为日志有顺序依赖关系,例如:一个是事务产生的REDO/UNDO日志是有前后依赖关系的。openGauss的日志系统采用多个LOG WRITER(日志写盘线程)线程并行写的机制,充分发挥SSD的多通道IO能力。如图20所示。

 图20  并行刷日志示意图

关键设计:

§ 整个事务的wal日志不能拆分到多个事务日志共享缓冲区,必须写到一个事务日志共享缓冲区。

§ 故障恢复wal,并行恢复,必须按照LSN大小顺序恢复。

§ 每个事务结束前需要保证对应的事务日志LSN已经刷盘完成。

§ 事务分配事务日志共享缓冲区考虑NUMA架构适配。

持久化及故障恢复系统设计

08

数据库的日志系统非常关键,它是数据持久化的关键保证。以其基于事务ID的多版本管理以及历史版本的累积及清理方式为基础,行存储引擎主要以Redo日志(也就是上文提到的XLOG)作为主要的持久化手段,配以增量的检查点(Checkpoint)以及日志的并行回放,支持数据库实例的快速故障恢复。

1. 事务的Redo日志机制

Redo日志在事务对数据进行修改时产生,用来记录事务修改后的数据、或是事务对数据做的具体 *** 作。比如,简单的INSERT/UPDATE/DELETE *** 作会产生如图21所示的Redo日志。

图21  Redo日志

一些非事务直接修改的关键 *** 作也会记录到Redo日志,比如申请新的页面、显式的事务提交、检查点(Checkpoint)等。记录Redo日志的原则,就是在数据库发生故障后,可以从最后一个检查点开始,通过Redo日志的回放,恢复到与数据库实例故障前的一致状态。

Redo日志除了应用于数据恢复,数据的备份、还原以及数据库主备实例之间的主备同步、不同数据库实例/集群间的同步都需要依赖Redo日志的机制。为了保障数据的一致性,在事务修改的相关页面刷盘之前,需要先把对应的Redo日志刷盘,也就是WAL(Write Ahead Log)的原则。

因为事务的提交以及 *** 作之间的顺序对于数据一致性是至关重要的,因此Redo日志也必须将此顺序记录下来。每条Redo日志都配有一个日志编号,即Log Sequence Number (LSN)。在行存储的系统中,LSN为一个递增的64位无符号整数。系统中各类机制,如后面要说到的检查点,以及主备实例之间的同步机制、仲裁机制,都需要依靠系统中推进的LSN或是恢复出来的LSN作为重要的标记或判断依据。

2. 全量与增量检查点

在上述对事务日志以及共享缓冲区的描述中,有一个关键的信息,那就是事务日志的持久化与事务提交是同步的,但事务内对页面相关修改的持久化与事务提交不是同步的;也就是说,事务提交需要这个事物相关的Redo日志被强制刷盘,但是并不强制要求相关的页面也被强制刷盘。当一个数据库实例故障重启后,实例在启动过程中,之前没有能够及时刷盘的改动需要使用事务日志进行恢复。但是日志回放的代价是很高的,性能也相对比较慢。为了避免每次数据库都需要从头恢复事务日志,数据库自身会定期创建检查点,用户也可以通过命令手动创建检查点。

创建检查点的过程中,存储引擎会将数据缓冲区中脏页写到磁盘中,并记录日志文件和控制文件。记录信息中rec LSN代表着此次检查点中,在此LSN之前的日志对应的所有改动均已被持久化,下次的数据恢复可以直接从此LSN开始;同时在此LSN之前的事务日志,在其他用途(主备实例同步、数据备份等)时,也可以被回收重新使用。

由于检查点本身需要将缓冲区内所有的脏页面刷盘(全量检查点),因此每次检查点从性能角度会对数据库实例所在物理环境引入大量的IO,磁盘的峰值往往意味着性能的波动。同时因为存在大量的IO开销,因此检查点的打点不能过于频繁,rec LSN推进较慢,那么重启数据库时也就会存在较多的Redo日志需要回放,存在重启恢复时间过长的问题。为了解决这一问题,行存储引擎引入了增量检查点的概念。

增量检查点机制下,会维护一个脏页面队列(dirty page queue)。脏页是按照LSN递增的顺序放到队列中的,定期由一个专门刷脏页面的后台线程pagewriter(页面刷盘线程)进行定期定量的刷脏页下盘 *** 作。如图22所示。

图22  脏页面队列

队列中维护一个rec LSN,记录目前已经被刷盘的脏页对应的LSN大小,即在队列中脏页对应的事务提交、其相对的事务日志下盘后,此rec LSN标记会被更新。在触发增量检查点时,并不需要等待脏页刷盘,而是可以使用当前脏页队列的rec LSN作为检查点的rec LSN记录。增量Checkpoint的存在使得整个系统中的IO更加平滑,并且系统的故障恢复时间更短,可用性更高。

3. 并行回放

Redo日志的回放指的是将Redo日志中记录的改动重新应用到系统/页面中的过程,这个过程通常发生在实例故障恢复亦或是主备实例之间的数据同步过程中的备机实例上(即主实例的改动,备机实例也需要回放完成,以达到与主实例状态一致的效果)。当前数据库所在物理实例往往有较多的CPU核,而日志回放却往往还是单线程进行运作,在日志回放的过程中数据库实例无法充分利用物理环境资源。

为了能够充分利用CPU多核的特点,显著加快数据库异常后恢复及备机实例日志回放的速度,行存储引擎采用了多线程并行方式回放日志,如图23如示。

图23  多线程并行方式回放日志

整个并行回放系统的设计采用生产者-消费者模型,分配模块负责解析、分配日志到回放模块,回放模块负责消费、回放日志。

为了达成这一设计,实现中采用了带阻塞功能的无锁SPSC(Single Producer Single Consumer)队列。分配线程作为生产者将解析后的日志放入回放线程的列队中,回放线程从队列中消费日志进行回放。如图24所示。

图24  无锁SPSC队列

为了提升整体并行回放机制的可靠性,会在对一个页面的回放动作中,对事务日志中的LSN和页面结构中的last_LSN(详见前面章节中描述的HeapPageHeader(堆页面头)结构体)进行校验,以保证回放过程中数据库系统的一致性。

未完待续.......


若您对本系列文章感兴趣,敬请关注我们的公众号,我们将在每周二、周四进行更新。

更多数据库行业相关内容,欢迎光临 2021 数据技术嘉年华 :https://www.modb.pro/dtc2021(扫描下方二维码免费领取线上大会门票)。

END

推荐阅读:267页!2020年度数据库技术年刊

推荐下载:2020数据技术嘉年华PPT下载


2020数据技术嘉年华近50个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2020DTC”获得!

你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓

点击下图查看更多 ↓

云和恩墨大讲堂 | 一个分享交流的地方

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看” 

你的喜欢会被看到❤

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5672059.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存