2025-05-29
文件系统
0

目录

一、openGauss中的事务持久性
二、WAL 日志:核心同步内容
主备复制中的 Undo 日志同步
1. WAL 日志包含 Undo 相关操作
2. 备库本地生成 Undo 日志
通过备库 Undo 日志判断事务状态的局限性
1. Undo 日志反映的是本地状态
2. 事务中间状态不完整
3. 备库只读限制
主备日志同步状态
同步机制对比表

一、openGauss中的事务持久性

  和业界几乎所有的数据库一样,openGauss通过将事务对于数据库的修改写入可以永久(长时间)保存的存储介质中,来保证事务的持久性。这个过程被称为事务的持久化过程。持久化过程是保证事务持久性所必不可少的环节,其效率对于数据库整体性能影响很大,常常成为数据库的性能瓶颈所在。

  最常用的存储介质是磁盘。对于磁盘来说,其每次读写操作都有一个“启动”代价,因此在单位时间内(每秒内),一个磁盘可以进行的读写操作次数(Input/Output Operations Per Second,简称IOPS)是有上限的。HDD磁盘的IOPS一般在1000次/秒以下,SSD磁盘的IOPS可以达到10000次/秒左右。另外一方面,如果多个磁盘读写请求的数据在磁盘上是相邻的,那么可以被合并为一次读写操作,这导致磁盘顺序读写的性能通常要远优于随机读写。

  一般来说,尤其是在OLTP场景下,用户对于数据库数据的修改是比较分散随机的。如果在持久化过程中,直接将这些分散的数据写入磁盘,那么这个随机写入的性能是比较差的。因此,数据库通常都采用预写日志(Write Ahead Log,简称WAL)来避免持久化过程中的随机IO,如图4(a)所示。所谓预写日志,是指在事务提交的时候,先将事务对于数据库的修改写入一个顺序追加的WAL日志文件中。由于WAL日志的写操作是顺序IO,因此其可以达到一个比较高的性能。另一方面,对于真正修改的物理数据文件,再等待合适的时机写入磁盘,以尽可能合并该数据文件上的IO操作。

  在一个事务完成日志的下盘操作(即写入磁盘)以后,该事务就可以完成提交动作。如果在此之后数据库发生宕机,那么数据库会首先从已经写入磁盘的WAL文件中恢复出该事务对于数据库的修改操作,从而保证事务一旦提交即具备持久性的特点。

  下面结合图4(b)中的例子,简单说明数据库故障恢复的原理。假设一个事务需要在表A(对应数据文件A)和表B(对应数据文件B)中各插入一行新的记录,在数据库内部,其执行的顺序如下:

  (1)记录修改数据文件A的日志,

  (2)记录修改数据文件B的日志,

  (3)在数据文件A中写入新的记录,

  (4)在数据文件B中写入新的记录。

  在上述过程中,如果在第(4)步执行时数据库发生宕机,那么该事务对于数据文件B的修改可能全部或部分丢失。当数据库再次启动以后,在其能够接受新的业务之前,需要将这些可能丢失的修改从日志中找回来(该操作被称为日志回放操作)。

  在日志回放过程中,数据库会根据日志记录的先后顺序,依次读取每个日志的内容,然后判断该日志记录的事务对数据库数据文件的修改是否和当前相关数据文件的内容一致。如果一致,说明上次数据库停机之前修改已经写入数据文件中,该日志修改无需回放;如果不一致,说明上次数据库停机之前修改还未写入数据文件中,上次数据库停机可能是异常宕机导致,该日志对应的事务操作需要重新在相关数据文件中再次执行,才能保证恢复成功。

  对于本例,在数据库恢复过程中,首先读取到在数据文件A中插入记录的日志,将数据文件A读取上来之后,发现数据文件A中已经包含该记录,因此该日志无需回放;然后读取到在数据文件B中插入记录的日志,将数据文件B读取上来之后,发现数据文件B中未包含新插入的记录,因此需要将日志中的记录再次写入到数据文件B中,从而完成恢复。最终,该事务对于数据库所有的修改都得以恢复出来,事务的持久性得到了保证。

network-asset-640-20250519224440-eokqneg.webp

  (a) WAL日志和数据页面的关系示意图

  (b)WAL日志和故障恢复示意图

  图4 WAL日志和事务持久性示意图

二、WAL 日志:核心同步内容

  WAL(Write-Ahead Logging)日志记录了数据库的物理变更(如数据页修改)和逻辑操作(如事务提交),是主备同步的基础。主备之间通过WAL 日志的传输和重放实现数据一致性:

  1. 主库:所有事务修改先记录到 WAL,通过WAL Sender​进程发送给备库。
  2. 备库:通过WAL Receiver​接收日志,并应用(重放)到本地数据文件,保持与主库一致。

  关键点:WAL 日志包含了事务的最终结果(如提交 / 回滚),但不直接同步事务的中间状态(如未提交的事务)。

主备复制中的 Undo 日志同步

  在 OpenGauss 的主备架构中,Undo 日志本身不直接同步到备库,但与 Undo 相关的关键信息会通过 WAL 日志间接同步:

1. WAL 日志包含 Undo 相关操作

  WAL 日志记录了事务对 Undo 日志的修改操作(如创建、更新 Undo 记录),但不包含 Undo 日志的完整内容。例如:

  • 当主库事务提交时,WAL 会记录 “提交事务 X” 的操作,备库重放此操作时会标记相应 Undo 记录为 “已提交”。
  • 若事务回滚,WAL 会记录 “回滚事务 X”,备库通过重放此操作触发 Undo 日志的应用,恢复数据。

2. 备库本地生成 Undo 日志

  备库在重放 WAL 日志时,会本地生成自己的 Undo 日志,用于支持 MVCC 和事务回滚。这些 Undo 日志基于主库 WAL 中的操作重建,而非直接复制主库的 Undo 日志。

通过备库 Undo 日志判断事务状态的局限性

  虽然备库上存在 Undo 日志,但无法直接通过 Undo 日志判断主库事务的实时执行情况

1. Undo 日志反映的是本地状态

  备库的 Undo 日志是重放 WAL 后的结果,仅反映备库自身的事务状态。例如:

  • 若主库有未提交的事务,备库可能根本不知道该事务的存在(除非 WAL 已发送相关信息)。
  • 备库上的 Undo 日志状态可能滞后于主库,尤其是在异步复制模式下。

2. 事务中间状态不完整

  Undo 日志主要记录数据变更前的状态,而非事务的执行流程。例如:

  • Undo 日志无法告诉你事务当前执行到哪条 SQL 语句。
  • 无法通过 Undo 日志判断事务是否处于等待锁的状态。

3. 备库只读限制

  备库通常作为只读节点(支持读操作),其 Undo 日志仅用于支持查询的多版本读,而非处理写事务。因此,备库只需根据 WAL 重放结果本地维护 Undo 日志,无需与主库的 Undo 日志完全一致,备库的 Undo 日志状态与主库的写事务状态无直接关联。

主备日志同步状态

  用户可以通过参数设置当前事务的同步方式。

  该参数属于USERSET类型参数,可被任何用户在任何时刻设置。

  通常情况下,一个事务产生的日志的同步顺序如下:

  1. 主机将日志内容写入本地内存。
  2. 主机将本地内存中的日志写入本地文件系统。
  3. 主机将本地文件系统中的日志内容刷盘。
  4. 主机将日志内容发送给备机。
  5. 备机接受到日志内容,存入备机内存。
  6. 备机将备机内存中的日志写入备机文件系统。
  7. 备机将备机文件系统中的日志内容刷盘。
  8. 备机回放日志,完成对数据文件的增量更新。

  参数取值范围:枚举类型

  • on:表示主机事务提交需要等待备机将对应日志刷新到磁盘。
  • off:表示主机事务提交无需等待主机自身将对应日志刷新到磁盘,通常也称为异步提交。
  • local:表示主机事务提交需要等待主机自身将对应日志刷新到磁盘,通常也称为本地提交。
  • remote_write:表示主机事务提交需要等待备机将对应日志写到文件系统(无需刷新到磁盘)。
  • remote_receive:表示主机事务提交需要等待备机接收到对应日志数据(无需写入文件系统)。
  • remote_apply:表示主机事务提交需要等待备机完成对应日志的回放操作。

同步机制对比表

状态类型是否同步到备库?同步方式一致性保障
WAL 日志✅ 必须同步实时传输与重放数据变更的强一致性
事务状态✅ 最终状态(提交 / 回滚)通过 WAL 日志中的提交记录(CLOG)同步最终一致性
锁状态❌ 不同步备库不维护锁表,提升为主库时重建切换后重新初始化
快照状态❌ 不同步查询时本地生成快照查询时刻的一致性

  ‍

  ‍

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:司小远

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!