pg 崩溃恢复篇(四)—— 检查点进程与崩溃恢复

一、 检查点进程

在pg中,当下列情形之一发生时,checkpointer进程会启动执行检查点:

  • 自上次检查点执行时间已超过checkpoint_timeout设置(默认300秒)。
  • 在9.5之前,自上一次检查点以来使用的WAL文件数量,超过了checkpoint_segments设置(默认为3)。
  • 9.5开始为pg_xlog中WAL文件总大小超过max_wal_size设置(默认1GB,64个文件)。
  • 以smart或fast模式关闭pg。
  • 超级用户手动发出CHECKPOINT命令

在9.1之前,bgwriter进程同时负责checkpoint和脏页写。

以下将简要描述检查点进程和保存当前检查点元数据的pg_control文件。

1. 检查点进程概述

检查点进程负责两个工作:

  • 为崩溃恢复做准备(本节主要描述)
  • 将共享缓冲池中的脏页刷盘

在这里插入图片描述

(1)检查点进程启动时,会将重做点存储在内存中。重做点是最新的检查点开始时xlog记录写入的位置,也是崩溃恢复的起点。
(2)将此检查点对应的XLOG记录(即检查点记录)写入WAL缓冲区。该记录的数据部分由CheckPoint结构体定义,结构体包含一些变量,如步骤(1)中重做点的位置。此外,写入检查点记录的位置按照字面意思也称作检查点。
(3,4)刷新共享缓冲池中的所有数据(例如CLOG的内容等)到磁盘。
(5)更新pg_control文件,该文件包含一些基本信息,例如检查点记录所写的位置,稍后将详细描述。

checkpoint结构体定义:
在这里插入图片描述

2. pg_control文件

由于pg_control文件包含检查点的基本信息,因此它对于崩溃恢复是必不可少的。如果它被破坏或不可读,系统将无法得知恢复起点,无法进行恢复。

尽管pg_control文件存储了40多个项目,但主要有三项与崩溃恢复相关:

  • State:最新检查点开始时数据库的状态。共有七个:start up表示数据库正在启动;shutdown表示正常关闭;in production表示数据库正在运行,等等。
  • Latest checkpoint location:最新检查点的LSN位置。
  • Prior checkpoint location:前一个检查点的LSN位置,pg 11开始已弃用(节约用于WAL文件的磁盘空间)。

pg_control文件存储在global子目录中,可以使用pg_controldata命令查看其内容。

-bash-4.2$ pg_controldata $PGDATA
pg_control version number:            1002
Catalog version number:               201707211
Database system identifier:           6748611403308013153
Database cluster state:               in archive recovery <---------
pg_control last modified:             Mon 21 Oct 2019 04:10:29 PM CST
Latest checkpoint location:           0/1B0003D8  <---------
Prior checkpoint location:            0/1B000028  <---------
Latest checkpoint's REDO location:    0/1B0003A0
Latest checkpoint's REDO WAL file:    00000007000000000000001B
Latest checkpoint's TimeLineID:       7
Latest checkpoint's PrevTimeLineID:   7
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0:587
Latest checkpoint's NextOID:          32800
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        548
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  587
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Mon 21 Oct 2019 04:02:36 PM CST
Fake LSN counter for unlogged rels:   0/1
Minimum recovery ending location:     0/1B000480
Min recovery ending loc's timeline:   7
Backup start location:                0/0
Backup end location:                  0/0
End-of-backup record required:        no
wal_level setting:                    replica
wal_log_hints setting:                off
max_connections setting:              1000
max_worker_processes setting:         8
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off
Maximum data alignment:               8
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        1996
Size of a large-object chunk:         2048
Date/time type storage:               64-bit integers
Float4 argument passing:              by value
Float8 argument passing:              by value
Data page checksum version:           0
Mock authentication nonce:          c93bf5a4c60af9b458db7cc843906e084d4228c160ff96f11af92e2ceeacf5a7

二、 崩溃恢复

pg实现了基于重做日志的崩溃恢复。如果数据库服务器崩溃,pg通过从重做点按序重放WAL文件中的XLOG记录来恢复数据库集群。

在本节之前我们已经多次讨论了数据库恢复,因此这里仅介绍两个与恢复有关而尚未解释的内容。

第一是pg如何启动恢复过程。当pg启动时,它首先读取pg_control文件,恢复过程如下:


在这里插入图片描述

  • (1)pg在启动时读取pg_control文件内容。如果state为’in production’,PostgreSQL将进入恢复模式,因为这意味着数据库没有正常停止;如果为’shutdown’,将进入正常启动模式。
  • (2)pg从相应的WAL段文件中读取最新的检查点记录(位于pg_control文件中),并从记录中获取重做点。如果最新的检查点记录无效(invalid),pg将读取前一个检查点的记录。如果两个记录都不可读,将放弃恢复。注意,从11版本开始不会再存储前一个检查点的记录信息。
  • (3)使用合适的资源管理器从重做点开始按顺序读取和重放XLOG记录,直到最新WAL文件的最后位置。当遇到备份块时,无论其LSN如何,都会将覆盖相应表的页面。否则仅当此xlog记录LSN>相应页面的pd_lsn时,才会重放该XLOG记录。

第二点是关于LSN的比较。为什么应该比较非备份块xlog记录的LSN与相应页面的pd_lsn。这里使用一个特定示例来解释强制两个LSN的比较需求。注意这里省略了WAL缓冲区以简化描述。


在这里插入图片描述

(1)向TABLE_A中插入一个元组,并在LSN_1处写入一条XLOG记录。
(2)bgwriter 将TABLE_A的页面写入磁盘。此时,此页面的pd_lsn为LSN_1。
(3)向TABLE_A中再插入一个元组,并在LSN_2处写入一条XLOG记录,修改后的页面还没有写入磁盘。

与前面的示例不同,本场景中,TABLE_A的页面已写入磁盘。

使用immediate模式关闭,然后启动,恢复过程如下:

在这里插入图片描述
(1)pg加载第一个XLOG记录和TABLE_A的页面,但不重放,因为该xlog记录的LSN不大于TABLE_A的LSN(都是LSN_1)。实际也可以看到完全没有重放的必要性。

(2)接下来,pg会重放第二个XLOG记录,因为该记录的LSN(LSN_2)大于当前TABLE_A的LSN(LSN_1)。

可以看出,如果非备份块的重放顺序不正确或者被多次重放,数据库集群将不一致。简而言之,非备份块的重放操作不是幂等的。因此,为了保留正确的重放顺序,当且仅当其LSN大于相应页面的pd_lsn时,才重放非备份块记录。

另一方面,由于备份块的重做操作是幂等的,因此备份块可以重放任意次,而不管其LSN如何。

注:在数学与计算机学中,幂等操作是指其执行任意多次所产生的影响均与执行一次相同,即f(f(x))=f(x)。

参考

The Internals of PostgreSQL : Chapter 9 Write Ahead Logging — WAL

Postgresql管理系列-第九章 WAL(Write Ahead Logging)介绍_魂醉的博客-CSDN博客

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值