让我们通过使用PostgreSQL15和pg_exclusive_backup来复现关于在线物理备份的独占模式下的服务器启动失败问题!

这是《2022年PostgreSQL降临节日历》第五天的文章。

根据下面版本说明的条目,PostgreSQL15移除了在线物理备份的排他模式。版本说明中指出移除排他模式的原因是,如果数据库服务器在该模式下突然停止,可能导致服务器启动失败。现在我们将具体确认该问题是如何发生的。

删除长期不推荐使用的排他备份模式(David Steele,Nathan Bossart)。
如果数据库服务器在此模式下突然停止,服务器可能无法启动。非排他备份模式被认为在所有情况下都更优。函数pg_start_backup()/pg_stop_backup()已更名为pg_backup_start()/pg_backup_stop(),函数pg_backup_start_time()和pg_is_in_backup()已被删除。

这个问题在使用排他模式的 PostgreSQL14 及之前版本中会发生,但本次我们故意使用“在 PostgreSQL15 及以后版本中也支持排他模式的 pg_exclusive_backup 扩展”在 PostgreSQL15 上进行复现。

顺便提一句,关于独占模式和非独占模式的区别,以及独占模式被删除的背景等内容,可以在PostgreSQL未公开说明书的演示资料中找到解释,请务必参考。

为PostgreSQL15准备pg_exclusive_backup。

在安装了PostgreSQL15的环境中,可以参考这里来安装pg_exclusive_backup 1.0版本。可以从这里获取源代码压缩文件。

$ tar zxf pg_exclusive_backup-1.0.tar.gz
$ cd pg_exclusive_backup-1.0/
$ make USE_PGXS=1
$ make USE_PGXS=1 install

安装成功后,使用CREATE EXTENSION命令注册pg_exclusive_backup插件。

$ psql -c "CREATE EXTENSION pg_exclusive_backup"

确认使用独占模式进行备份获取步骤

在重現問題之前,首先確認進行排他模式的備份取得步驟。步驟如下所示,類似於以下執行示例。

    1. 开始备份。

 

    1. $ psql -c “SELECT pg_start_backup(‘test’, true)”

获取数据库数据备份。
$ cp -a $PGDATA /backup/

结束备份。
$ psql -c “SELECT pg_stop_backup()”

通过复现启动失败问题,由于排他模式引起的问题。

为了模拟排他模式下的问题,您可以在备份开始和结束之间多次切换WAL文件并生成检查点,以确保备份开始时的WAL文件被删除。在这种情况下,您可以在备份结束之前异常终止PostgreSQL,并通过崩溃恢复方式启动PostgreSQL。以下是执行示例。

    1. 开始备份。

 

    1. $ psql -c “SELECT pg_start_backup(‘test’, true)”

从由pg_start_backup()创建的backup_label文件中确认备份开始时的WAL文件。在以下示例中,可以确认000000010000000000000002是备份开始时的WAL文件。
$ cat $PGDATA/backup_label
START WAL LOCATION: 0/2000028 (file 000000010000000000000002)
CHECKPOINT LOCATION: 0/2000060
BACKUP METHOD: pg_start_backup
BACKUP FROM: primary
START TIME: 2022-12-05 15:02:31 JST
LABEL: test
START TIMELINE: 1

执行多次WAL文件切换和检查点。
$ psql -c “SELECT pg_switch_wal(); CHECKPOINT”
$ psql -c “SELECT pg_switch_wal(); CHECKPOINT”
$ psql -c “SELECT pg_switch_wal(); CHECKPOINT”
$ psql -c “SELECT pg_switch_wal(); CHECKPOINT”

确认备份开始时的WAL文件已被删除。如果尚未删除,则返回步骤3。
$ ls $PGDATA/pg_wal
000000010000000000000006 000000010000000000000007 archive_status

(在完成备份之前)向postmaster进程发送SIGKILL信号,异常终止PostgreSQL。
$ kill -SIGKILL $(head -1 data/postmaster.pid)

启动PostgreSQL。崩溃恢复失败,启动失败。
$ pg_ctl start

LOG: database system was interrupted; last known up at 2022-12-05 15:04:30 JST
LOG: invalid checkpoint record
FATAL: could not locate required checkpoint record
HINT: If you are restoring from a backup, touch “/System/Volumes/Data/opt/pgsql-15.1/data/recovery.signal” and add required recovery options.
If you are not restoring from a backup, try removing the file “/System/Volumes/Data/opt/pgsql-15.1/data/backup_label”.
Be careful: removing “/System/Volumes/Data/opt/pgsql-15.1/data/backup_label” will result in a corrupt cluster if restoring from a backup.
LOG: startup process (PID 65731) exited with exit code 1
LOG: aborting startup due to startup process failure
LOG: database system is shut down

在进行PostgreSQL启动时,要求在$PGDATA目录下存在backup_label文件。在这种情况下,PostgreSQL会尝试从备份开始时的WAL文件(上述为000000010000000000000002)进行崩溃恢复。然而,由于该WAL文件已被检查点删除,因此无法开始恢复,启动将失败。

这个启动失败是排他模式特有的问题,而排他模式被认为是不推荐的,并且是 PostgreSQL 15 中被删除的原因之一。另一方面,非排他模式下,在备份开始时不会在$PGDATA下创建backup_label,因此不会出现这个问题。

如果您不是从备份中恢复数据,请尝试删除文件“/System/Volumes/Data/opt/pgsql-15.1/data/backup_label”。

顺便提一下,要成功从状态6启动,需要根据启动失败时的提示信息(上述摘录)删除备份标签。这样一来,PostgreSQL将能够从最新的检查点位置的WAL文件开始崩溃恢复,而不是从备份开始,从而成功启动。

$ rm $PGDATA/backup_label
$ pg_ctl start
...
LOG:  database system is ready to accept connections

最后

由于在线物理备份的互斥模式存在类似我们这次确认到的服务器启动失败的风险,PostgreSQL15已将其删除。因此,在升级到PostgreSQL15及更高版本时,之前使用互斥模式的用户需要考虑转移到非互斥模式。

在某些情况下,独占模式可能更方便使用,在使用pg_exclusive_backup工具进行PostgreSQL15及更高版本的备份时,请务必考虑到服务器启动失败的风险。

广告
将在 10 秒后关闭
bannerAds