PostgreSQL 归档和基于时间点恢复

1. 简介

最近我一直在练习 PostgreSQL 连续归档的内部原理以及我当前开发工作所需的时间点恢复功能。今天我想用最近在 Ubuntu 18.04 上发布的 PostgreSQL 14 来演示这些重要功能。

2. 预写日志?

在详细介绍连续归档(continuous archiving)之前,了解预写日志 (WAL) 的概念非常重要。 WAL 文件由 PG 生成,其中包含从一开始就对数据库进行的所有操作。 INSERT 、 UPDATE 、 DELETE 、 VACUUM 等操作被捕获在 WAL 文件中。有了这些WAL文件,就可以简单地通过 replaying 它们来重新创建数据库,从而允许用户在发生故障时将数据库恢复到某种状态。这是连续归档和时间点恢复的基础。

3. 什么是连续归档?

生成的WAL文件通常存储在PG数据库集群内的 pg_wal 目录中,但它们不会永远增长。配置参数 max_wal_size 和 min_wal_size 控制 pg_wal 目录中可以保存多少个WAL文件。检查点进程将定期清除旧的 WAL 文件,只留下最近的文件。

因此,设置连续归档非常重要,以便所有这些 WAL 文件都可以 archived 到 PG 集群之外的其他地方。因此,当您需要恢复所有旧的 WAL 文件时,PG 可以从存档中恢复它们。

要启用 WAL 归档和恢复,请在 postgresql.conf 中设置以下参数:

ini 复制代码
archive_mode = on
archive_command = 'cp %p /path/to/archive/%f'
restore_command = 'cp /path/to/archive/%f %p'

您应该将 /path/to/archive 替换为您自己的系统上的存档路径。执行时pg会用 WAL segment 路径 和 WAL segment 名称 替换命令中的占位符 %p 和 %f 。

当一个 WAL 段准备好归档时,PG 将在 pg_wal/archive_status 中创建一个信号文件来指示特定的 WAL 段已准备好归档。

在下面的示例中,段 00000001000000000000000E 已准备好存档,由后缀 .ready 表示,而之前的所有段均已成功存档,因此由后缀 .done表示

bash 复制代码
$ ls pgtest/pg_wal/archive_status/
000000010000000000000002.done  000000010000000000000005.done  00000001000000000000000A.done  00000001000000000000000E.ready
000000010000000000000003.done  000000010000000000000007.done  00000001000000000000000B.done
000000010000000000000004.done  000000010000000000000008.done  00000001000000000000000D.done

然后,PG 的归档进程将被唤醒,通过运行配置的 archive_command 来执行归档。

yaml 复制代码
$ps -ef | grep postgres

caryh     1487     1  0 11:10 ?        00:00:00 postgres -D /home/caryh/pgtest
caryh     1510  1487  0 11:10 ?        00:00:00 postgres: checkpointer
caryh     1511  1487  0 11:10 ?        00:00:00 postgres: background writer
caryh     1512  1487  0 11:10 ?        00:00:00 postgres: walwriter
caryh     1516  1487  0 11:10 ?        00:00:00 postgres: autovacuum launcher
caryh     1520  1487  0 11:10 ?        00:00:00 postgres: archiver   archiving 00000001000000000000000E
caryh     1521  1487  0 11:10 ?        00:00:00 postgres: stats collector
caryh     1522  1487  0 11:10 ?        00:00:00 postgres: logical replication launcher

请注意,归档程序 (PID=1520) 还会在 ps 显示屏上显示其进度。

成功完成后, pg_wal/archive_status 中的信号文件将更新为后缀 .done

bash 复制代码
$ ls pgtest/pg_wal/archive_status/
000000010000000000000002.done  000000010000000000000005.done  00000001000000000000000A.done  00000001000000000000000E.done
000000010000000000000003.done  000000010000000000000007.done  00000001000000000000000B.done
000000010000000000000004.done  000000010000000000000008.done  00000001000000000000000D.done

在下一个检查点中,这些 .done 文件将被删除,因此这些状态文件也不会持续增长。

4. 什么是时间点恢复 (PITR)?

将所有 WAL 段备份在单独的存档中,我们就能够将数据库恢复到过去的某个时间点或完全恢复整个数据库。这取决于您的需求,如果您犯了一个重大错误,需要从过去的某个时间点重新开始,您可以让 PG 在恢复模式下恢复到该特定时间,并从该时间点继续数据库操作。这也称为 switching to a new time line ID ,我们将在下一篇博客中对此进行更多讨论。

我们继续上面的例子(已经有100万行数据),做一个时间点恢复。

  • 4.1 对当前数据库进行基础备份,我们可以使用 pg_basebackup 来实现
shell 复制代码
$ pg_basebackup -U caryh -h 127.0.0.1 --progress -D pgtest-back
  • 4.2做完基础备份后,继续插入一些数据,使用 pg_switch_wal 立即写出 WAL 段并获得 LSN 。 LSN 代表 Log Sequence Number,它在逻辑上表示 WAL 段内的 WAL 条目。请参阅此处的文档以获取更多信息。

获得LSN后,我们再次插入更多行数据。

sql 复制代码
insert into test values(generate_series(1,1000000), 'asdas');
insert into test values(generate_series(1,1000000), 'asdas');

pg_switch_wal();

 pg_switch_wal
---------------
 0/13DAC308

insert into test values(generate_series(1,1000000), 'asdas');
insert into test values(generate_series(1,1000000), 'asdas');

因此,这个表 test 总共应该有 500 万行数据,因为它以 100 万行开始,而我们在上面的示例中刚刚插入了 400 万行。

LSN 0/13DAC308 指示的 WAL 位置表示数据库仅包含 300 万行的时间,这就是我们要在示例中恢复到的 point of time 。

Stop the database server

  • 4.3 停止数据库服务器
shell 复制代码
pg_ctl -D pgtest stop
  • 4.4 清除该数据库中的所有内容 pgtest
shell 复制代码
$ rm -rf pgtest/

这样做很疯狂,但请记住,我们在 步骤4.1 中 存档中的所有 WAL 段中进行了基础备份,因此从技术上讲,我们仍然拥有一切。

  • 4.5 将基本备份中的所有内容复制回 pgtest
shell 复制代码
cp -r pgtest-back/* pgtest/
  • 4.6 编辑 pgtest/postgresql.conf 并设置恢复目标

由于我们使用 LSN 作为目标,因此我们可以简单地将捕获的 LSN 放入 recovery_target_lsn 配置中

ini 复制代码
recovery_target_lsn = '0/13DAC308'

PG还支持其他方式来定义恢复目标,基于时间戳、名称或xid。有关其他选项,请参阅此文档。

  • 4.7 通过在 pgtest 集群下创建 recovery.signal 文件来指示数据库以恢复模式运行
shell 复制代码
$touch pgtest/recovery.signal
  • 4.8 启动服务器
shell 复制代码
$pg_ctl -D pgtest start

服务器现在将以恢复模式启动,并且将从存档中恢复 WAL 文件并执行恢复。您可以使用 psql 登录并检查数据库是否还应包含 300 万行而不是 5 行。

您可能会注意到,即使数据库已恢复到过去的某个时间点,如果您打算插入其他数据,您也会遇到 database in recovery 或 read only database 错误。这是因为我们仍在 recovery mode 中,但当前处于 paused 中。

这是由 recovery_target_action 选项配置的,默认为 pause 。这实际上是为了让您有时间检查数据库并确认它确实是您想要恢复到的数据库状态。如果这是错误的,您只需关闭数据库并重新配置 recovery_target_lsn ,直到达到所需的数据库状态。

  • 4.9 退出恢复模式

一旦确认数据库已正确恢复,您可以通过以下 psql 命令退出恢复模式:

sql 复制代码
select pg_wal_replay_resume();

此命令将结束恢复模式,您应该能够将其他数据插入数据库。 recovery.signal 文件将被删除,并且未来的 WAL 片段将具有新的时间线 ID。

原文地址

相关推荐
清水白石008几秒前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
Python私教5 小时前
model中能定义字段声明不存储到数据库吗
数据库·oracle
Estar.Lee6 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
BestandW1shEs7 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师7 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球7 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...7 小时前
表的操作(MySQL)
数据库·mysql·表的操作
哥谭居民00017 小时前
MySQL的权限管理机制--授权表
数据库
2401_857610037 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全