存储引擎源码解析 | 磁盘引擎(17)

4.2.9 持久化及故障恢复机制

1. 行存储持久化和检查点机制

如“4.2.8 日志系统”节中所述,通过采用WAL日志的方式可以在对性能影响较小的情况下保障用户事务对数据库修改的持久化。然而如果只是依赖日志来保障持久化的话,那么数据库服务(故障)重启之后将需要回放大量的日志数据量,这会导致很大的RTO,对业务的可用性影响极大。因此共享缓冲区中的脏页也需要异步地写入磁盘中,来减少宕机重启后所需要回放的日志数据量,降低系统的RTO时间。
如果数据库系统在事务提交之后、异步写入磁盘的脏页写入磁盘之前发生宕机,那么需要在数据库再次启动之后,首先把那些宕机之前还没有来得及写入磁盘的脏页上的修改所对应的日志进行回放,使得这些脏页可以恢复到宕机之前的内容。
基于如上原理,可以得出数据库持久化的一个关键是:在宕机重启的时候,通过某种机制确定从WAL的哪个lsn开始进行恢复;可以保证在该lsn之前的那些日志,它们涉及的数据页面修改已经在宕机之前完成写入磁盘。这个恢复起始的lsn,即是数据库的检查点。
在“4.2.6 行存储缓存机制”节介绍行存储缓存加载和淘汰机制中,已经知道参与脏页写入磁盘的主要有两类线程:bgwriter和pagewriter。前者负责脏页持久化的主体工作;后者负责数据库检查点lsn的推进。openGauss采用一个无锁的全局脏页队列数组来依次记录曾经被用户写操作置脏的那些数据页面。该队列数组成员为DirtyPageQueueSlot结构体,定义代码如下,其中:buffer为队列成员对应的buffer(该值为buffer id + 1),slot_state为该队列成员的状态。

volatile int buffer; pg_atomic_uint32 slot_state; } DirtyPageQueueSlot;