由 John Doe 六月 24, 2025
你有没有需要自定义 WAL 归档流程?比如:压缩、上传到指定备份目标,记录归档文件的校验码。
特性提交日志
允许通过可加载模块进行归档。
为每个要归档的 WAL 文件运行 shell 命令,会带来大量开销,并且可能无法提供所需的错误检查或确切语义。因此,我们提供了一个选项,即针对每个要归档的文件调用可加载模块,而不是运行 shell 命令。
此外,添加了一个 ‘basic_archive’ 的 contrib 模块作为示例实现,用于将 WAL 文件归档到本地目录。
讨论:http://postgr.es/m/20220202224433.GA1036711@nathanxps13
示例
通常,为了备份的目的,以及在流复制严重滞后时还能继续同步,需要启用 WAL 归档。
在之前的 PostgreSQL 版本中,要实现 WAL 归档,我们会使用 archive_command 设置,该设置基本上会为每个要归档的 WAL 文件运行一次 shell 命令。这虽然可行,但存在一些性能方面的缺点。如果生成大量 WAL,频繁创建新进程的成本不可忽视。
大多数常用工具通过一次处理多个文件来解决这个问题,并对不需要处理的文件 “标记” 为已归档。这虽然可行,但始终不够规范。 现在,新的 PostgreSQL 版本中,我们可以编写扩展,该扩展会针对每个 WAL 文件被调用,并且一直都是加载的。与创建新进程相关的所有开销都消失了。
让我们来看看它是如何工作的。首先,我们现在有了一个新的配置参数:archive_library。如果设置了该参数(并且 archive_mode 为 on),将会使用该库进行归档,而不是 archive_command。
让我们尝试设置它:
select name, setting from pg_settings where name ~ '^archive' order by 1;
name | setting
-------------------------+-----------
archive_cleanup_command |
archive_command | /bin/true
archive_library |
archive_mode | on
archive_timeout | 0
(5 rows)
目前,我们没有设置归档。虽然已启用,但 archive_command 设置为 /bin/true,因此实际上没有进行归档。
让我们使用提供的示例归档库 basic_archive 来启用它:
alter system set archive_library = 'basic_archive';
可以通过执行pg_ctl reload
或者select pg_reload_conf()
,使更改生效。
请注意,我们还没有为归档指定任何目录。
通常,如果使用了 archive_command 但未正确设置,会看到类似这样的 postgres 进程:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
redrock 1189 0.0 0.0 219572 6272 ? Ss 14:49 0:00 postgres: archiver process failed on 0000000100000F72000000F0
但现在,使用 archive_library 时,会是这样:
$ ps uw -U redrock | grep arch
redrock 37562 0.0 0.0 209756 4964 ? Ss 15:48 0:00 postgres: archiver
在上面没有看到任何错误。这要么意味着 ps 输出中不再显示相关信息,要么意味着它工作正常?
幸运的是,我们可以直接查询归档状态:
select * from pg_stat_archiver;
archived_count | last_archived_wal | last_archived_time | failed_count | last_failed_wal | last_failed_time | stats_reset
----------------+--------------------------+-------------------------------+--------------+-----------------+------------------+-------------------------------
233 | 0000000100000000000000E9 | 2025-02-06 15:48:06.802869+08 | 0 | [null] | [null] | 2025-02-06 14:57:31.437907+08
(1 row)
归档状态也是正常的。那么,归档正常工作了吗?让我们再检查下日志:
$ grep archive postgresql.log | grep -v pg_stat_archiver | tail -n 5
2025-02-06 15:50:46.500 CST @ 37562 WARNING: archive_mode enabled, yet archiving is not configured
2025-02-06 15:51:46.561 CST @ 37562 WARNING: archive_mode enabled, yet archiving is not configured
2025-02-06 15:52:46.581 CST @ 37562 WARNING: archive_mode enabled, yet archiving is not configured
2025-02-06 15:53:46.641 CST @ 37562 WARNING: archive_mode enabled, yet archiving is not configured
2025-02-06 15:54:46.648 CST @ 37562 WARNING: archive_mode enabled, yet archiving is not configured
实际上,归档还是失败了。让我们来完成配置,首先,我们看看当前的 WAL 位置:
select pg_current_wal_lsn(), pg_walfile_name(pg_current_wal_lsn());
pg_current_wal_lsn | pg_walfile_name
--------------------+--------------------------
1/1206FCD0 | 000000010000000100000012
(1 row)
上面是当前的 WAL 位置。请注意,在 pg_stat_archiver 中我们看到 last_archived_wal 是 0000000100000000000000E9。
让我们来看看如何解决这个问题。我们先创建好目录/tmp/archive
,并将basic_archive.archive_directory
更改为/tmp/archive
。
重新加载配置,并等待一段时间后,查询状态如下:
select * from pg_stat_archiver ;
archived_count | last_archived_wal | last_archived_time | failed_count | last_failed_wal | last_failed_time | stats_reset
----------------+--------------------------+-------------------------------+--------------+-----------------+------------------+-------------------------------
273 | 000000010000000100000011 | 2025-02-06 16:00:25.272431+08 | 0 | [null] | [null] | 2025-02-06 14:57:31.437907+08
(1 row)
并且在/tmp/archive
中,会看到有 40 个文件,从 0000000100000000000000EA 到 000000010000000100000011。
终于,归档正常工作了。
basic_archive 的代码非常简单,没有太多内容,它只是一个概念验证,证明它是可行的,以及它能实现什么。相信,Barman、pgBackRest 和其他归档或备份工具很快会发布新版本,这些版本可以提供归档库使用,而不是通过创建新进程来执行命令。
此外,一旦 WAL 归档真正工作起来以后,ps 输出中的信息也正常了:
redrock 37562 0.0 0.0 209756 6916 ? Ss 15:48 0:00 \_ postgres: archiver last was 000000010000000100000011
非常不错的新特性,感谢社区的所有相关人员。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/5ef1eefd76f404ddc59b885d50340e602b70f05f