36. PostgreSQL 备份和恢复

有很多方法可以备份 PostgreSQL 数据库,您选择的方法将很大程度上取决于您如何使用数据库。

  • 对于相对静态的数据库,可以使用基本的 pg_dump/pg_restore 工具定期对数据进行快照。

  • 对于频繁更改的数据,使用“在线备份”方案可以将更新持续存档到安全位置。

在线备份是 高可用性 的复制和备用系统的基础,特别是对于 PostgreSQL >= 9.0 的版本。

36.1. 数据布局

PostgreSQL 架构 中所述,确保生产数据始终存储在单独的架构中是管理数据的非常重要的最佳实践。有两个原因

  • 备份和恢复架构中的数据比管理要单独备份的表格列表要简单得多。

  • 将数据表格保留在“public”架构之外,可以更轻松地进行升级,如 软件升级 中所述。

36.2. 基本备份和恢复

使用 pg_dump 实用程序可以轻松备份整个数据库。该实用程序是一个命令行工具,这使得它易于使用脚本进行自动化,也可以通过 PgAdmin 实用程序中的 GUI 进行调用。

要备份我们的 nyc 数据库,我们可以使用 GUI,只需右键单击要备份的数据库

_images/backup1.jpg

输入您要创建的备份文件名称。

_images/backup2.jpg

请注意,有三种备份格式选项:压缩、tar 和纯文本。

  • 纯文本只是一个文本 SQL 文件。这是最简单的格式,在许多方面也是最灵活的,因为它可以轻松地编辑或修改,然后重新加载到数据库中,允许对所有权或其他全局信息进行离线更改。

  • Tar 使用 UNIX 归档格式将转储的组件存储在单独的文件中。使用 tar 格式允许 pg_restore 实用程序选择性地恢复转储的部分内容。

  • 压缩类似于 Tar 格式,但会单独压缩内部组件,允许在不解压缩整个存档的情况下选择性地恢复它们。

我们将选中压缩选项并继续,保存备份文件。

可以使用以下命令行执行相同的操作

pg_dump --file=nyc.backup --format=c --port=54321 --username=postgres nyc

由于备份文件采用压缩格式,因此可以使用 pg_restore 命令查看内容以列出清单。在 PgAdmin GUI 中,“查看”是面板中的一个选项。

_images/backup3.jpg

查看清单时,您可能会注意到其中包含许多“FUNCTION”签名。

_images/backup4.jpg

这是因为 pg_dump 实用程序会转储数据库中的所有非系统对象,包括 PostGIS 函数定义。

注意

PostgreSQL 9.1+ 包含一个“EXTENSION”功能,允许将 PostGIS 等附加包安装为注册的系统组件,因此从 pg_dump 输出中排除。PostGIS 2.0 及更高版本支持使用此扩展系统进行安装。

我们可以使用 pg_restore 直接从命令行查看相同的清单

pg_restore --list nyc.backup

包含大量 PostGIS 函数签名的转储文件的问题在于,我们真正想要的是数据的转储,而不是系统函数。

由于转储文件中包含所有对象,因此我们可以将其恢复到空白数据库并获得完整的功能。这样做时,我们预计要恢复到的系统具有与我们转储的系统完全相同的 PostGIS 版本(因为函数签名定义引用了特定版本的 PostGIS 共享库)。

从命令行,恢复看起来像这样

createdb --port 54321 nyc2
pg_restore --dbname=nyc2 --port 54321 --username=postgres nyc.backup

仅转储数据,不包括函数签名,这就是将数据放在模式中很方便的原因,因为有一个命令行标志可以仅转储特定模式

pg_dump --port=54321 -format=c --schema=census --file=census.backup

现在,当我们列出转储的内容时,我们只看到了我们想要的数据表。

pg_restore --list census.backup

;
; Archive created at Thu Aug  9 11:02:49 2012
;     dbname: nyc
;     TOC Entries: 11
;     Compression: -1
;     Dump Version: 1.11-0
;     Format: CUSTOM
;     Integer: 4 bytes
;     Offset: 8 bytes
;     Dumped from database version: 8.4.9
;     Dumped by pg_dump version: 8.4.9
;
;
; Selected TOC Entries:
;
6; 2615 20091 SCHEMA - census postgres
146; 1259 19845 TABLE census nyc_census_blocks postgres
145; 1259 19843 SEQUENCE census nyc_census_blocks_gid_seq postgres
2691; 0 0 SEQUENCE OWNED BY census nyc_census_blocks_gid_seq postgres
2692; 0 0 SEQUENCE SET census nyc_census_blocks_gid_seq postgres
2681; 2604 19848 DEFAULT census gid postgres
2688; 0 19845 TABLE DATA census nyc_census_blocks postgres
2686; 2606 19853 CONSTRAINT census nyc_census_blocks_pkey postgres
2687; 1259 20078 INDEX census nyc_census_blocks_geom_gist postgres

只有数据表很方便,因为这意味着我们可以将数据存储到安装了任何版本的 PostGIS 的数据库中,正如我们在 软件升级 中所述。

36.2.1. 备份用户

The pg_dump 实用程序一次操作一个数据库(或者一个模式或表,如果你限制它)。但是,有关用户的信息存储在整个集群中,它不会存储在任何一个数据库中!

要备份用户的信息,请使用 pg_dumpall 实用程序,并使用“–globals-only”标志。

pg_dumpall --globals-only --port 54321

你也可以使用 pg_dumpall 的默认模式来备份整个集群,但请注意,与 pg_dump 一样,你最终会备份 PostGIS 函数签名,因此转储必须恢复到相同的软件安装,它不能用作升级过程的一部分。

36.3. 在线备份和恢复

在线备份和恢复允许管理员保持一组最新的备份文件,而无需重复转储整个数据库。如果数据库处于频繁的插入和更新负载下,那么在线备份可能比基本备份更可取。

注意

了解在线备份的最佳方法是阅读 PostgreSQL 手册中关于 持续归档和时间点恢复 的相关部分。PostGIS 工作坊的这一部分将只提供在线备份设置的简要快照。

36.3.1. 工作原理

PostgreSQL 不会持续写入主数据表,而是最初将更改存储在“预写日志”(WAL)中。这些日志合在一起,构成了对数据库所做的所有更改的完整记录。在线备份包括复制数据库主数据表,然后复制从那时起生成的每个 WAL。

_images/backup5.jpg

当需要恢复到新的数据库时,系统从主数据副本开始,然后将所有 WAL 文件重播到数据库中。最终结果是恢复的数据库处于与接收最后一个 WAL 时原始数据库相同的状态。

由于 WAL 文件无论如何都会被写入,并且将副本传输到归档服务器在计算上很便宜,因此在线备份是保持系统最新备份的有效方法,而无需诉诸密集的定期完整转储。

36.3.2. 归档 WAL 文件

设置在线备份的第一步是创建一个归档方法。PostgreSQL 归档方法具有极高的灵活性:PostgreSQL 后端只需调用在 archive_command 配置参数中指定的脚本。

这意味着归档可以像将文件复制到网络挂载的驱动器一样简单,也可以像将文件加密并通过电子邮件发送到远程归档一样复杂。任何可以编写的过程都可以用来归档文件。

要启用归档,我们将编辑 postgresql.conf,首先启用 WAL 归档

wal_level = archive
archive_mode = on

然后将 archive_command 设置为将我们的归档文件复制到安全位置(根据需要更改目标路径)

# Unix
archive_command = 'test ! -f /archivedir/%f && cp %p /archivedir/%f'

# Windows
archive_command = 'copy "%p" "C:\\archivedir\\%f"'

重要的是,归档命令不要覆盖现有文件,因此 unix 命令包含一个初始测试以确保文件不存在。同样重要的是,如果复制过程失败,命令应返回非零状态。

完成更改后,您可以重新启动 PostgreSQL 以使更改生效。

36.3.3. 获取基本备份

归档过程到位后,您需要获取基本备份。

将数据库置于备份模式(这不会改变查询或数据更新的操作,它只是强制执行检查点并写入一个标签文件,指示备份的时间)。

SELECT pg_start_backup('/archivedir/basebackup.tgz');

对于标签,使用备份文件的路径是一个好习惯,因为它可以帮助您跟踪备份存储的位置。

将数据库复制到归档位置

# Unix
tar cvfz /archivedir/basebackup.tgz ${PGDATA}

然后告诉数据库备份过程已完成。

SELECT pg_stop_backup();

当然,所有这些步骤都可以为定期基本备份编写脚本。

36.3.4. 从归档中恢复

这些步骤来自 PostgreSQL 手册关于 持续归档和时间点恢复 的部分。

  • 如果服务器正在运行,请停止服务器。

  • 如果有足够的空间,请将整个集群数据目录和所有表空间复制到一个临时位置,以备不时之需。请注意,此预防措施需要您在系统上有足够的空间来保存现有数据库的两个副本。如果您没有足够的空间,您至少应该保存集群的 pg_xlog 子目录的内容,因为它可能包含在系统宕机之前未归档的日志。

  • 删除集群数据目录下和您正在使用的任何表空间的根目录下的所有现有文件和子目录。

  • 从您的文件系统备份中恢复数据库文件。确保它们以正确的拥有者(数据库系统用户,而不是 root!)和正确的权限恢复。如果您使用的是表空间,您应该验证 pg_tblspc/ 中的符号链接是否正确恢复。

  • 删除 pg_xlog/ 中存在的任何文件;这些文件来自文件系统备份,因此可能已经过时而不是最新的。如果您根本没有归档 pg_xlog/,那么请使用正确的权限重新创建它,并注意确保如果您之前将其设置为符号链接,则重新建立它。

  • 如果您在步骤 2 中保存了未归档的 WAL 段文件,请将它们复制到 pg_xlog/ 中。(最好复制它们,而不是移动它们,这样您仍然拥有未修改的文件,以防出现问题,您必须重新开始。)

  • 在集群数据目录中创建一个恢复命令文件 recovery.conf(参见第 26 章)。您可能还想暂时修改 pg_hba.conf,以防止普通用户连接,直到您确定恢复成功为止。

  • 启动服务器。服务器将进入恢复模式,并开始读取所需的归档 WAL 文件。如果恢复因外部错误而终止,则可以简单地重新启动服务器,它将继续恢复。恢复过程完成后,服务器将把 recovery.conf 重命名为 recovery.done(以防止以后意外重新进入恢复模式),然后开始正常的数据库操作。

  • 检查数据库内容,确保已恢复到所需状态。如果没有,请返回步骤 1。如果一切正常,请通过将 pg_hba.conf 恢复为正常状态来允许用户连接。