关于 PolarDB PostgreSQL 版
PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。
XLOG类型WAL
在上一篇介绍WAL日志的文档中,我们介绍了PolarDB PostgreSQL数据库中关于WAL日志的组织形式、内部结构,WAL日志高效的结构设计,使其可以承载多种不同种类的WAL日志,覆盖数据库内部的所有主要数据结构:事务系统、数据表、BTree索引、Hash索引、Gin索引、Gist索引等。
这篇文章对于XLOG类型的WAL日志进行介绍,该类型的WAL日志记录了数据库控制信息的变化,比如:NextXid、NextOid、ControlFile等信息的变化,接下来进行一一介绍。
XLOG类型WAL的分类
PolarDB PostgreSQL 11版本中,共有以下16种子类型的WAL日志,每种子类型WAL日志负责恢复一种独特的控制信息,接下来对每种子类型做简单的介绍。
XLOG_NEXTOID
该类型WAL日志在main data部分记录了一个OID的值,回放时,直接赋值给当前共享内存中的ShmemVariableCache->nextOid,在主库节点上,就是从该共享内存变量中分配下一个有效的OID。
然而,并非每一个成功分配的OID都需要记录到WAL日志中,为了提高性能,PolarDB PostgreSQL内核选择每8192个OID记录一条WAL日志,即一条XLOG_NEXTOID日志可以分配出8192个OID值,预先分配出的OID个数保存在共享内存变量ShmemVariableCache->oidCount中,下次分配OID,直接执行ShmemVariableCache->nextOid++、ShmemVariableCache->oidCount--即可,当然,获取OID的逻辑是在持有LWLock锁OidGenLock的临界区内执行。
WAL日志回放时,需要将ShmemVariableCache->oidCount设置为0,即备库promote为主库后,从ShmemVariableCache->nextOid + 1开始分配OID。
XLOG_CHECKPOINT_SHUTDOWN/XLOG_CHECKPOINT_ONLINE
checkpoint分为online checkpoint和shutdown checkpoint,同时在startup进程回放结束时产生的EndOfRecovery checkpoint也属于shutdown checkpoint。
checkpoint WAL日志在main data部分记录了结构体CheckPoint的全部内容,可以用来恢复共享内存中的nextXid、nextOid、nextMulti、oldestMulti、oldestXid等信息。
online checkpoint和shutdown checkpoint两者的区别如下所示:
online checkpoint日志回放时,不修改nextOid的值,因为online checkpoint日志中的nextOid的值可能是过时的,原因是:主库在做online checkpoint时,还有其他backend会话在消耗nextOid的值,如果消耗的比较快,则可能在online checkpoint日志前,有一条XLOG_NEXTOID类型的WAL日志中记录的nextOid值比较新。
shutdown checkpoint是在主库节点上没有其他写业务运行时产生的,即当前没有其他事务在执行,因此可以使用空的running transactions数组,加上已经恢复的两阶段事务信息,来初始化共享内存procArray中记录的事务状态信息。
只有shutdown checkpoint可以切换时间线。WAL日志回放过程中,如果遇到了shutdown checkpoint日志,则尝试切换到WAL日志中记录的时间线,如果时间线切换成功,则接下来的WAL日志将从新时间线上读取。
XLOG_END_OF_RECOVERY
END_OF_RECOVERY日志记录了回放结束时的三个信息:回放结束时间戳、当前时间线、上一个时间线。
如果当前时间线和上一个时间线不相同,则意味着回放到该WAL日志时,需要进行时间线切换,切换成功后,接下来的WAL日志将从新时间线上读取。
XLOG_NOOP
一个空的XLOG WAL日志子类型,当前不具有任何意义。
XLOG_SWITCH
PolarDB PostgreSQL提供了xlog switch的操作,用于将当前的WAL日志写入位点切换到下一个WAL日志文件的对应位置,这种操作的主要用途有:
备份开始时,立刻执行一个xlog switch操作,可以保证在备库上执行备份时,新增checkpoint日志不会出现在旧时间线上。
备份结束时,可以让增量备份工具快速备份上一个WAL日志文件,不用等新的WAL日志将其填充满。
startup进程回放时,遇到XLOG_SWITCH日志,则默认切换到下一个WAL日志文件的对应位置,读取下一条WAL日志。
XLOG_RESTORE_POINT
RESTORE_POINT日志中记录了两个信息:当前时间戳、自定义的字符串表示restore point的名字。
这两个信息可被用来设置按时间点恢复的结束位置,即可以通过配置参数recovery_target_name或者recovery_target_time来指定按时间点恢复时的结束位置。
XLOG_FPI/XLOG_FPI_FOR_HINT/XLOG_FPI_MULTI
PostgreSQL的一个block大小是8192字节,而存储设备的最小IO单元一般小于等于4096字节,因此,在block持久化过程中,由于断电等异常,可能导致数据半写问题。为了解决半写问题,PostgreSQL引入了全页写(fullpage write)技术,即当block在checkpoint后的第一次被修改时,记录当前block的内容到FPI日志中。如果存储设备上数据出现半写损坏,则可以从WAL日志中恢复出完整的block页面内容。
XLOG_FPI日志将一个block的全部内容记录到WAL日志中,XLOG_FPI_FOR_HINT日志和XLOG_FPI日志的功能是一样的,只不过记录的时机不同。XLOG_FPI_MULTI日志,支持一次性将多个block的内容记录到同一条WAL日志中。
XLOG_BACKUP_END
BACKUP_END日志中记录了一个WAL日志LSN,即一次全量数据备份开始时的写入位点。
WAL日志回放过程中,遇到该类型的WAL日志时,说明当前已经达到了上一次全量备份的结束位置,需要设置minRecoveryPoint为当前WAL日志位点,以保证下次重启时,必须要回放到大于等于当前WAL日志位点后,才可以开始提供只读服务。
XLOG_PARAMETER_CHANGE
PolarDB PostgreSQL数据库中,有一类比较重要的实例级别的参数配置,需要进行节点间的同步和约束检查,XLOG_PARAMETER_CHANGE日志可以被用来达到这个目的。
目前,需要记录到XLOG_PARAMETER_CHANGE日志的重要参数有:MaxConnections、max_worker_processes、max_prepared_xacts、max_locks_per_xact、wal_level、wal_log_hints、track_commit_timestamp,这些参数在ControlFile文件中都有对应的记录。
XLOG_FPW_CHANGE
该类型WAL日志中记录了一个bool变量,表示full_page_writes开关是否开启,以记录重要参数full_page_writes的变化。
主要用于全量备份时检查参数full_page_writes是否开启,目前全量备份期间,要求参数full_page_writes必须是打开的。
XLOG_FPSI
该类型WAL日志中记录了一个uint64类型的整数,表示当前logindex fullpage number,用来跟踪当前内存中最大的fullpage number。
该类型WAL日志只用于logindex fullpage功能。
XLOG_CSNLOG_ZEROPAGE/XLOG_CSNLOG_TRUNCATE
该类型WAL日志中,记录了一个int类型的整数,用于记录当前操作的CSN LOG的page number,其ZEROPAGE日志用于扩展并初始化该page为全0页面,TRUNCATE日志用于truncate掉所有拥有大于当前page的文件。
该类型WAL日志只用于CSN功能。
总结
文章介绍了PolarDB PostgreSQL数据库中XLOG类型的WAL日志,共介绍了16种不同的子类型WAL日志,每种WAL日志子类型都有不同的用途。XLOG类型的WAL日志主要是用来恢复数据库中的控制信息,经过文章中的分析可知,涉及到的控制信息涉及:ControlFile控制文件、Checkpoint操作、OID/XID等全局ID的分配、全量备份以及按时间点恢复功能、重要参数的变更、FullPage Write模块、以及PolarDB自定义的logindex fullpage模块和CSN模块。




