9.7 PostgreSQL中的检查点过程

PostgreSQL中,检查点进程(后台)会执行检查点;当下列情形之一发生时,它会启动处理:

  1. 距离上次检查点已经过去了由参数checkpoint_timeout配置的时间间隔(默认间隔为300秒(5分钟))。
  2. 在9.4及以前的版本中,自上一次检查点以来消耗的WAL段文件超出了参数checkpoint_segments的数量(默认值为3)。
  3. 在9.5及以后的版本,pg_xlog(10之后是pg_wal)中的WAL段文件总大小超过参数max_wal_size配置的值(默认值为1GB,64个段文件)。
  4. PostgreSQL服务器以smartfast模式关闭。

当超级用户手动执行CHECKPOINT命令时,该进程也会启动。

在9.1或更早的版本中,后台写入进程(见8.6节)同时负责脏页写入与检查点。

在接下来的几个小节中会简要描述检查点过程与pg_control文件,pg_control文件保存了当前检查点的元数据。

9.7.1 检查点过程概述

检查点进程负责两个方面:为数据库恢复做准备工作,以及共享缓冲池上脏页的刷盘工作。在本小节介绍其内部过程时,将重点关注前一个方面。参见图9.13和以下描述。

图9.13 PostgreSQL检查点的内部流程图9.13 PostgreSQL检查点的内部流程

  1. 当检查点进程启动时,会将重做点(REDO Point) 存储在内存中;重做点 是上次检查点开始时刻时XLOG记录的写入位置,也是数据库恢复的开始位置。
  2. 该检查点相应的XLOG记录(即检查点)会被写入WAL缓冲区,该记录的数据部分是由CheckPoint结构体定义的,包含了一些变量,比如第一步中重做点的位置。另外,写入检查点记录的位置,也按照字面意义叫做检查点(checkpoint )。
  3. 共享内存中的所有数据(例如,CLOG的内容)都会被刷入持久存储中。
  4. 共享缓冲池中的所有脏页都会被逐渐刷写到存储中。
  5. 更新pg_control文件,该文件包含了一些基础信息,例如上一次检查点的位置,后面会介绍该文件的细节
typedef struct CheckPoint
{
  XLogRecPtr      redo;           /* 当创建存盘时,下一个可用的RecPtr(即重做点) */
  TimeLineID      ThisTimeLineID; /* 当前时间线ID TLI */
  TimeLineID      PrevTimeLineID; /* 前一个时间线ID TLI, 如果当前记录开启了一条新的时间线
                                   * (其他情况下等于ThisTimeLineID) */
  bool            fullPageWrites; /* 当前全页写入的状态 */
  uint32          nextXidEpoch;   /* 下一个时事务ID(nextXid)的高位bit */
  TransactionId   nextXid;        /* 下一个空闲事务ID */
  Oid             nextOid;        /* 下一个空闲OID */
  MultiXactId     nextMulti;      /* 下一个空闲MultiXactId */
  MultiXactOffset nextMultiOffset;/* 下一个空闲MultiXact 偏移量 */
  TransactionId   oldestXid;      /* 集蔟范围最小的datfronzenxid */
  Oid             oldestXidDB;    /* 带有最小datfrozenxid的数据库 */
  MultiXactId     oldestMulti;    /* 集蔟范围内最小的datminmxid */
  Oid             oldestMultiDB;  /* 带有最小datminmxid的数据库 */
  pg_time_t       time;           /* 存盘的时间戳 */
 /* 最老的仍然在运行的事务ID,只有当从在线检查点中初始化一个热备时才会需要该字段。因此只有
  * 当在线检查点且wal_level配置为热备时我们才会费劲计算这个字段。其他情况下会被设置为
  * InvalidTransactionId  */
  TransactionId oldestActiveXid;
} CheckPoint;

让我们从数据库恢复的角度来总结上面的内容,检查点过程会创建包含重做点的检查点,并将检查点位置与其他信息存储到pg_control文件中。因此,PostgreSQL能够通过从重做点回放WAL数据来进行恢复(重做点是从检查点中获取的)。

9.7.2 pg_crontrol文件

由于pg_control文件包含了检查点的基本信息,因此它对于数据库恢复肯定是必不可少的。如果它被破坏或不可读,因为系统不知道从哪里开始恢复,则恢复过程就无法启动。

尽管pg_control文件存储了40多条数据项,如下三个是接下来和我们讨论内容相关的:

  1. 状态(State) —— 最近检查点过程开始时数据库的状态,总共有七种状态:start up表示系统正在启动,shut down表示系统被关机命令正常关闭,in production表示数据库正在运行,诸如此类。
  2. 最新检查点位置(Latest Checkpoint Location) —— 最新检查点的LSN位置
  3. 上次检查点位置(Prior Checkpoint Location) —— 前一个检查点的LSN位置,在版本11中已经弃用,细节如引文所示。

pg_control文件存储在数据目录中global子目录内;可以使用pg_controldata程序显示其内容。

PostgreSQL11中移除了前任检查点

PostgreSQL 11及后续版本只会存储包含最新检查点或更新版本的WAL段文件;将不会存储包含先前检查点的旧段文件,以减少用于在pg_xlog(pg_wal)子目录下保存WAL段文件的磁盘空间。 详细信息请参见此主题