在 PostgreSQL 14中,cp 命令是默认的归档方式。官方文档中,包括在配置文件中的注释,是将 test 和 cp 命令结合在一起使用的。有关于cp命令的相关用法,可参考这里Linux cp 命令 Linux test 命令

1.启用WAL归档

在 postgresql.conf 文件中,配置以下参数。

当wal_level为minimal时,一些SQL命令被优化为避免记录WAL日志。在这些语句的其中之一的执行过程中如果打开了归档或流复制,WAL中将不会包含足够的信息用于归档恢(崩溃恢复不受影响)。出于这个原因,wal_level只能在服务器启动时修改。但是,archive_command可以通过重载配置文件来修改。如果你希望暂时停止归档,一种方式是将archive_command设置为空串('')。这将导致WAL文件积累在pg_wal/中,直到一个可用的archive_command被重新建立。wal_level决定多少信息写入到 WAL 中。默认值是replica,它会写入足够的数据以支持WAL归档和复制,包括在后备服务器上运行只读查询。minimal会去掉除从崩溃或者立即关机中进行恢复所需的信息之外的所有记录。logical会增加支持逻辑解码所需的信息。每个层次包括所有更低层次记录的信息。这个参数只能在服务器启动时设置。

wal_level(enum) 官方解释

# postgresql.conf
# 设置wal_level级别为replica或更高
wal_level = replica                    # minimal, replica, or logical
                                        # (change requires restart)
# 设置archive_mode为on
# - Archiving -

archive_mode = on               # enables archiving; off, on, or always
                                # (change requires restart)

archive_command = 'cp -i %p /pgccc/archive/%f'               
                                # command to use to archive a logfile segment
                                # placeholders: %p = path of file to archive
                                #               %f = file name only
                                # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0            # force a logfile segment switch after this
                                # number of seconds; 0 disables

2.重启 PostgreSQL数据库

[postgres@pgccc pgdata]$ pg_stop
waiting for server to shut down.... done
server stopped
[postgres@pgccc pgdata]$ pg_start
waiting for server to start....2023-07-28 14:21:29.051 CST [22082] LOG:  redirecting log output to logging collector process
2023-07-28 14:21:29.051 CST [22082] HINT:  Future log output will appear in directory "log".
 done
server started
[postgres@pgccc pgdata]$

3.查看WAL归档状态

这里的wal归档状态变为on; 有了两次归档记录。

[postgres@pgccc pgdata]$ psql
psql (14.7)
Type "help" for help.

postgres=# show archive_mode ;
 archive_mode
--------------
 on
(1 row)

postgres=# \x
Expanded display is on.
postgres=# select * from pg_stat_archiver;
-[ RECORD 1 ]------+------------------------------
archived_count     | 2
last_archived_wal  | 00000001000000060000009F
last_archived_time | 2023-07-28 14:21:24.486235+08
failed_count       | 0
last_failed_wal    |
last_failed_time   |
stats_reset        | 2023-07-26 09:05:27.454518+08

postgres=# \q
[postgres@pgccc pgdata]$ cd ..

4.查看WAL归档文件

这里手动切换了一次WAL归档 pg_switch_wal()后,归档记录变为3次。

[postgres@pgccc pgccc]$ cd archive
[postgres@pgccc archive]$ ll
total 32768
-rw------- 1 postgres postgres 16777216 Jul 28 12:33 00000001000000060000009E
-rw------- 1 postgres postgres 16777216 Jul 28 14:21 00000001000000060000009F
[postgres@pgccc archive]$ psql
psql (14.7)
Type "help" for help.

postgres=# select pg_switch_wal();
 pg_switch_wal
---------------
 6/A00000F0
(1 row)

postgres=# \x
Expanded display is on.
postgres=# select * from pg_stat_archiver;
-[ RECORD 1 ]------+------------------------------
archived_count     | 3
last_archived_wal  | 0000000100000006000000A0
last_archived_time | 2023-07-28 14:24:36.353639+08
failed_count       | 0
last_failed_wal    |
last_failed_time   |
stats_reset        | 2023-07-26 09:05:27.454518+08

postgres=# \q
[postgres@pgccc archive]$ ll
total 49152
-rw------- 1 postgres postgres 16777216 Jul 28 12:33 00000001000000060000009E
-rw------- 1 postgres postgres 16777216 Jul 28 14:21 00000001000000060000009F
-rw------- 1 postgres postgres 16777216 Jul 28 14:24 0000000100000006000000A0
[postgres@pgccc archive]$

为方便自己及大家以后查阅,将官方文档的内容抄录如下:

5 官方文档 《建立WAL归档》14版本

26.3.1. 建立WAL归档

抽象地来说,一个运行中的PostgreSQL系统产生一个无穷长的WAL记录序列。系统从物理上将这个序列划分成WAL 段文件,通常是每个16MB(段尺寸在initdb期间可修改)。段文件会被分配一个数字名称以便反映它在整个抽象WAL序列中的位置。在没有使用WAL归档时,系统通常只创建少量段文件,并且通过重命名不再使用的段文件为更高的段编号来“回收”它们。系统假设内容位于最后一个检查点之前的段文件是无用的且可以被回收。

在归档WAL数据时,我们需要在每一段被填充满时捕捉其内容,并且在段文件被回收重用之前保存该数据。依靠应用和可用的硬件,有很多不同的方法来“保存数据”:我们可以将段文件拷贝到一个已挂载的位于另一台机器上的NFS目录,或者将它们写出到一个磁带驱动器(确保你有办法标识每个文件的原始文件名),或者将它们批量烧录到CD上,或者其他什么方法。为了向数据库管理员提供灵活性,PostgreSQL不对如何归档做任何假设。取而代之的是,PostgreSQL让管理员声明一个shell命令来拷贝一个完整的段文件到它需要去的地方。 该命令可以简单得就是一个cp,或者它可以调用一个复杂的 shell 脚本 — 所有都由你决定。

要启用WAL归档,需设置wal_level配置参数为replica或更高,设置archive_mode为on,并且使用archive_command配置参数指定一个shell命令。实际上,这些设置总是被放置在postgresql.conf文件中。在archive_command中,%p会被将要归档的文件路径所替代,而%f只会被文件名所替代(路径名是相对于当前工作目录而言的,即集簇的数据目录)。如果你需要在命令中嵌入一个真正的%字符,可以使用%%。最简单的命令类似于:

archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'  # Unix
archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"'  # Windows

它将把 WAL 段拷贝到目录/mnt/server/archivedir(这个只是一个例子,并非我们建议的方法,可能不能在所有系统上都正确运行)。在%p和%f参数被替换之后,实际被执行的命令看起来可能是:

test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065

对每一个将要被归档的新文件都会生成一个类似的命令。

归档命令将在运行PostgreSQL服务器的同一个用户的权限下执行。因为被归档的一系列WAL 文件实际上包含你的数据库里的所有东西,所以你应该确保自己的归档数据不会被别人窥探; 比如,归档到一个没有组或者全局读权限的目录里。

有一点很重要:当且仅当归档命令成功时,它才返回零退出。在得到一个零值结果之后,PostgreSQL将假设该文件已经成功归档, 因此它稍后将被删除或者被新的数据覆盖。但是,一个非零值告诉PostgreSQL该文件没有被归档; 因此它会周期性的重试直到成功。

当归档命令被一个信号(不是作为服务器关闭的一部分所用的SIGTERM)或者是退出状态超过125(例如命令没有发现)的脚本的一个错误所终止时, 归档进程会退出并且被postmaster重新启动。当这种情况下,pg_stat_archiver 中不会报告故障。

归档命令通常应该被设计成拒绝覆盖已经存在的归档文件。这是一个非常重要的安全特性, 可以在管理员操作失误(比如把两个不同的服务器的输出发送到同一个归档目录)的时候保持你的归档的完整性。

我们建议你首先要测试你准备使用到归档命令,以保证它实际上不会覆盖现有的文件,并且在这种情况下它返回非零状态。以上Unix中的命令例子通过包含一个独立的test步骤来保证这一点。在某些Unix平台上,cp具有诸如-i的开关,可用来更简洁地完成这一切,但是在没有验证返回的退出状态正确之前你不能依赖它们(特别地,GNU的cp在使用-i时将对已存在的目标文件返回状态零,这并不是我们所期望的行为)。

在设计你的归档环境时,请考虑一下如果归档命令不停失败会发生什么情况, 因为有些情况要求操作者的干涉,或者是归档空间不够了。 例如,如果你往磁带机上写,但是没有自动换带机,那么就有可能发生这种情况; 如果磁带满了,除非换磁带,否则任何事也做不了。 你应该确保任何错误情况或者任何要求操作员干涉的情况都会被正确报告, 这样才能迅速解决这些问题。否则pg_wal/目录会不停地被WAL段文件填充,直到问题解决(如果包含pg_wal/的文件系统被填满,PostgreSQL将会做一次致命关闭。不会有未提交事务被丢失,但是数据库将会保持离线直到你释放一部分空间)。

归档命令的速度并不要紧,只要它能跟上你的服务器生成 WAL 数据的平均速度即可。即使归档进程稍微落后,正常的操作也会继续进行。 如果归档进程慢很多,就会增加灾难发生的时候丢失的数据量。这同时也意味着pg_wal/目录包含大量未归档的段文件, 并且可能最后超出了可用磁盘空间。我们建议你监控归档进程,确保它是按照你的期望运转的。

在写自己的归档命令的时候,你应该假设被归档的文件名最长为64个字符并且可以包含 ASCII 字母、数字以及点的任意组合。 我们不需要保持原始的相对路径(%p),但是有必要保持文件名(%f)。

请注意尽管 WAL 归档允许你恢复任何对你的PostgreSQL数据库中数据所做的修改, 但它不会恢复对配置文件的修改(即postgresql.conf、pg_hba.conf以及pg_ident.conf),因为这些文件都是手工编辑的,而不是通过 SQL 操作来编辑的。 所以你可能会需要把你的配置文件放在一个日常文件系统备份过程可处理的位置。如何重定位配置文件请参阅第 20.2 节。

归档命令只会为完成的WAL段调用。因此如果你的服务器产生了一点点WAL流量(或者在产生时有宽松的周期),从一个事务完成到它被安全地记录在归档存储中之间将会有较长的延迟。要为未归档数据设置一个年龄限制,你可以设置archive_timeout来强制要求服务器按照其设定的频度切换到一个新的WAL段。注意由于强制切换而被归档的文件还是具有和完全归档的文件相同的长度。因此设置一个很短的archive_timeout是很不明智的 — 它会膨胀你的归档存储。将archive_timeout设置为1分钟左右通常是合理的。

同样,如果你希望确保一个刚刚完成的事务能被尽快归档,可以使用pg_switch_wal进行一次手动段切换。其他与WAL管理相关的使用函数在表 9.85中列出。

如第 14.4.7 节所述,当wal_level为minimal时,一些SQL命令被优化为避免记录WAL日志。在这些语句的其中之一的执行过程中如果打开了归档或流复制,WAL中将不会包含足够的信息用于归档恢(崩溃恢复不受影响)。出于这个原因,wal_level只能在服务器启动时修改。但是,archive_command可以通过重载配置文件来修改。如果你希望暂时停止归档,一种方式是将archive_command设置为空串('')。这将导致WAL文件积累在pg_wal/中,直到一个可用的archive_command被重新建立。

6 basic_archive

在 PostgreSQL 15中,提供了一个自定义模块 basic_archive ,使归档配置操作更加简洁稳定高效。这里不做相关演示,请查看相关文档 F.6. basic_archive。基本配置是这样:

# postgresql.conf
archive_mode = 'on'
archive_library = 'basic_archive'
basic_archive.archive_directory = '/path/to/archive/directory'

PostgreSQL-WAL归档 archive_PostgreSQL

PostgreSQL-WAL归档 archive_wal归档_02

7 清理归档

# 清理归档
pg_archivecleanup -d archive/ 0000000010000000001000000000019.backup