暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB PostgreSQL WAL日志介绍

PolarDB 2025-03-13
168

PolarDB PostgreSQL WAL日志介绍

关于 PolarDB PostgreSQL 版

PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。

WAL日志

PolarDB PostgreSQL使用WAL日志来记录数据库的变动,WAL日志是用来持久化数据库的修改、保证数据库crash前后状态一致性的重要手段。

数据库一般都有自己的数据缓存池(Buffer Pool),所有的数据更新操作都是发生在Buffer Pool中,一般来说,Buffer Pool主要存在于共享内存中,由于内存具有断电不可恢复的弱点,于是要想将一笔更新操作进行持久化,必须不断地将Buffer Pool中的buffer落盘才行,为了提高性能,WAL日志结构被提出来,WAL日志可以保存数据的更新部分,将WAL日志落盘就表示数据的修改已经持久化。

PolarDB PostgreSQL数据库采用MVCC机制来保证事务的原子性,事务一旦提交,其状态需要持久化到存储上,以保证crash后事务状态不变。WAL日志提供了Transaction类型日志来记录事务状态,事务提交时,只需要将对应的WAL日志落盘,即可保证事务的持久化,既降低了事务状态持久化带来的性能损耗,又保证了crash前后事务状态的一致性,进而维护了crash前后事务的原子性。

WAL日志分类

WAL日志一般分为Redo日志和Undo日志,Redo日志是指将修改后的数据内容持久化到存储上,Undo日志是指将修改前的数据内容持久化到存储上。

根据Redo日志的特性,其回放时,需要从某一个位点A开始,向后遍历所有的WAL日志,依次回放,直到最后一条有效的WAL日志。

根据Undo日志的特性,其回放时,需要从某一个位点A开始,向前遍历所有的WAL日志,依次回放,直到指定的一条WAL日志(位点B,B <= A)。

PolarDB PostgreSQL采用Redo日志来做数据恢复,crash时第一条需要回放的WAL日志位点由ControlFile中指定的checkpoint操作的redo点提供,向后依次回放完剩余所有的WAL日志。

WAL日志文件组织

WAL日志文件由三部分组成:时间线、XLogID、SegmentID,以十六进制的形式,分别在名字中占8个字节,比如:WAL日志文件000000010000000000000001的时间线是1,XLogID是0,SegmentID是1。

如下图所示,PolarDB PostgreSQL默认的wal segment size是1GB,第一个时间线是1,第一个XLogID是0,第一个SegmentID是1。加上时间线切换操作后的变化如图所示。其中蓝色表示实际存在的WAL日志文件,红箭头表示时间线切换操作。

image.png

WAL日志文件内部结构

WAL日志文件由多个8KB大小的block组成,其文件大小在Initdb的时候由选项--wal-segsize指定,然后固化到ControlFile文件中。

WAL日志的每个block都由两个部分组成:header部分和data部分。header部分由于位置的不同,分为两种:XLogLongPageHeader和XLogPageHeader,其中XLogLongPageHeader是位于WAL日志文件第一个block的头部,XLogPageHeader是位于WAL日志文件其余位置block的头部,XLogLongPageHeader比XLogPageHeader多存储了关于整个WAL日志文件的控制信息。

虽然不同WAL日志的长度不同,但是在WAL日志文件中都是紧密存储的。另外,每条WAL日志的长度都是对齐到8字节边界的,保证其长度是8字节的整数倍。

image.png

WAL日志结构

XLOG平面布局

WAL日志在PolarDB PostgreSQL中也被称之为XLOG日志,其平面布局如下图所示,包含:日志头部XLogRecord、数据block头部XLogRecordBlockHeader及数据block data、元信息头部XLogRecrodDataHeader[Short|Long]及元信息main data。

image.png

XLogRecord

头部XLogRecord结构的具体内容如下所示,xl_tot_len表示整条WAL日志的大小,xl_xid表示产生这条WAL日志的事务ID,xl_prev表示当前这条WAL日志的上一条WAL日志的开始位置,xl_rmid表示这条WAL日志的类型,xl_info表示WAL日志的子类型,xl_crc保存了当前这条WAL日志的CRC校验值。

typedef struct XLogRecord
{

 uint32  xl_tot_len;  /* total len of entire record */
 TransactionId xl_xid;  /* xact id */
 XLogRecPtr xl_prev;  /* ptr to previous record in log */
 uint8  xl_info;  /* flag bits, see below */
 RmgrId  xl_rmid;  /* resource manager for this record */
 /* 2 bytes of padding here, initialize to zero */
 pg_crc32c xl_crc;   /* CRC for this record */

 /* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */

} XLogRecord;

XLogRecordBlockHeader

数据头部XLogRecordBlockHeader的具体结构及其含义如下图所示,一个WAL日志中可以包含多个XLogRecordBlockHeader,每个XLogRecordBlockHeader与WAL日志中的block data部分一一对应,即头部与数据部分一一对应。

这里对于fork_flags和bimg_info成员变量做额外的解释:

  1. 关于fork_flags

    1. BKPBLOCK_HAS_IMAGE 0x10:对应block data是备份页。

    2. BKPBLOCK_HAS_DATA 0x20:是否对应某个block data。

    3. BKPBLOCK_WILL_INIT 0x40:redo时重新初始化页面。

    4. BKPBLOCK_SAME_REL 0x80:RelFileNode和上一个XLogRecordBlockHeader相同。

    1. 高4bit的值范围:

    2. 低4bit的值:表示该block属于表的哪个文件,例如:2603、2603_fsm、2603_vm。

  2. 关于bimg_info

    1. BKPIMAGE_HAS_HOLE 0x01:是否有空洞。

    2. BKPIMAGE_IS_COMPRESSED 0x02:是否被压缩。

    3. BKPIMAGE_APPLY 0x04:回放时从WAL中重载该页面。

image.png

XLogRecrodDataHeader[Short|Long]

每条WAL日志都有一个元信息字段(WAL日志结构中的main data部分),保存了生成WAL日志的操作的上下文内容,比如:插入一个新的tuple,新tuple在page中的offset位置等信息。

main data部分在WAL日志中也有对应的头部,即XLogRecordDataHeader[Short|Long]。当main data部分的长度小于256字节的时候,使XLogRecordDataHeaderShort,当main data部分的长度大于等于256字节的时候,使用XLogRecordDataHeaderLong。其主要结构及解释如下:

image.png

总结

本文章主要介绍了PolarDB PostgreSQL数据库中所使用的WAL日志的一些基本信息。首先,介绍了WAL日志的来源背景、基本功能以及在现有不同数据库中的两种主要形式;接着,介绍了WAL日志文件层面的组织结构、文件内容布局等;最后,详细介绍了单条WAL日志的内部结构,对于不同情况下WAL日志的具体承载内容做了细致的说明。该文章的内容对于认识、熟悉WAL日志来说具有一定的借鉴意义。


文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论