pg_upgrade

pg_upgrade — 升级PostgreSQL服务器实例

大纲

pg_upgrade -b oldbindir -B newbindir -d olddatadir -D newdatadir [option...]

描述

pg_upgrade(之前被称为pg_migrator) 允许存储在PostgreSQL数据文件中的数据被升级到一个较晚 的PostgreSQL主版本而无需进行主版本升级(例如从 9.6.3 升级到当前的PostgreSQL主发行)通常所需的数据转储/重载。 对于次版本升级(例如从 9.6.2 到 9.6.3)则不需要这个程序。

主 PostgreSQL 发行通常会加入新的特性,这些新特性常常会更改系统表的 布局,但是内部数据存储格式很少会改变。pg_upgrade 使用这一事实来通过创建新系统表并且重用旧的用户数据文件来执行快速升级。 如果一个未来的主发行没有把数据存储格式改得让旧数据格式不可读取,这类 升级就用不上pg_upgrade(社区将尝试避免这类情况)。

pg_upgrade会尽力(例如通过检查兼容的编译时设 置)确保新旧集簇在二进制上也是兼容的,包括 32/64 位二进制。保持 外部模块也是二进制兼容的也很重要,不过 pg_upgrade无法检查这一点。

pg_upgrade 支持从 8.4.X 及其后版本升级到当前的 PostgreSQL主发布,包括快照和 beta 发布。

选项

pg_upgrade接受下列命令行参数:

-b bindir
--old-bindir=bindir

旧的 PostgreSQL 可执行文件目录; 环境变量PGBINOLD

-B bindir
--new-bindir=bindir

新的 PostgreSQL 可执行文件目录; 环境变量PGBINNEW

-c
--check

只检查集簇,不更改任何数据

-d datadir
--old-datadir=datadir

旧的集簇数据目录;环境变量 PGDATAOLD

-D datadir
--new-datadir=datadir

新的集簇数据目录;环境变量 PGDATANEW

-j
--jobs

要同时使用的进程或线程数

-k
--link

使用硬链接来代替将文件拷贝到新集簇

-o options
--old-options options

直接传送给旧 postgres命令的选项,多个选项可以追加在后面

-O options
--new-options options

直接传送给新 postgres命令的选项,多个选项可以追加在后面

-p port
--old-port=port

旧的集簇端口号;环境变量 PGPORTOLD

-P port
--new-port=port

新的集簇端口号;环境变量 PGPORTNEW

-r
--retain

即使在成功完成后也保留 SQL 和日志文件

-U username
--username=username

集簇的安装用户名;环境变量 PGUSER

-v
--verbose

启用详细的内部日志

-V
--version

显示版本信息,然后退出

-?
--help

显示帮助,然后退出

使用

下面是用pg_upgrade执行一次升级的步骤:

  1. 移动旧集簇(可选)

    如果你在使用一个与版本相关的安装目录(例如 /opt/PostgreSQL/10),你就不需要移动旧的集簇。 图形化的安装程序会使用版本相关的安装目录。

    如果你的安装目录不是版本相关的(例如/usr/local/pgsql), 就有必要移动当前的 PostgreSQL 安装目录,以免它干扰新的 PostgreSQL安装。一旦当前的 PostgreSQL服务器被关闭,就可以安全地重命名 PostgreSQL 安装目录。假设旧目录是 /usr/local/pgsql,你可以这样:

    mv /usr/local/pgsql /usr/local/pgsql.old

    来重命名该目录。

  2. 对于源码安装,编译新版本

    用兼容旧集簇的configure标记编译新的 PostgreSQL 源码。在开始升级之前,pg_upgrade 将检查pg_controldata来确保所有设置都是兼容的。

  3. 安装新的 PostgreSQL 二进制文件

    安装新服务器的二进制文件和支持文件。pg_upgrade 会被包含在默认的安装中。

    对于源码安装,如果你希望把新服务器安装在一个自定义的位置, 可以使用prefix变量:

    make prefix=/usr/local/pgsql.new install
  4. 初始化新的 PostgreSQL 集簇

    使用initdb初始化新集簇。这里也要使用与 旧集簇相兼容的initdb标志。许多预编译的 安装程序会自动做这个步骤。这里没有必要启动新集簇。

  5. 安装自定义的共享对象文件

    把旧集簇使用的所有自定义共享对象文件(或者 DLL)安装到新集簇中, 例如pgcrypto.so,不管它们是来自于 contrib还是某些其他源码。不要安装模式定义 (例如CREATE EXTENSION pgcrypto),因为这些将会从旧集簇升级得到。 还有,任何自定义的全文搜索文件(词典、同义词、辞典、停用词)也必须 被复制到新集簇中。

  6. 调整认证

    pg_upgrade将会多次连接到旧服务器和新服务器,因此 你可能想要在pg_hba.conf中把认证设置成 peer或者使用一个~/.pgpass文件(见 第 33.15 节)。

  7. 停止两个服务器

    确认两个数据库服务器都被停止使用,例如在 Unix 上可以:

    pg_ctl -D /opt/PostgreSQL/9.6 stop
    pg_ctl -D /opt/PostgreSQL/10 stop

    或者在 Windows 上使用正确的服务名:

    NET STOP postgresql-9.6
    NET STOP postgresql-10

    直到后面的步骤之前,流复制和日志传送后备服务器可以保持运行。

  8. 为升级备用服务器做准备

    如果要使用步骤 10中概述的方法升级备用服务器, 请通过针对旧的主要和备用集群运行pg_controldata来验证旧的备用服务器是否追赶上。 验证最新检查点位置值在所有群集中是否匹配。 (如果在旧主服务器之前关闭旧备用服务器,将会出现不匹配)。另外, 在新的主要群集的postgresql.conf文件中将wal_level更改为 replica

  9. 运行 pg_upgrade

    总是应该运行新服务器而不是旧服务器的pg_upgrade二进制文件。 pg_upgrade要求制定新旧集簇的数据和可执行文件( bin)目录。你也可以指定用户和端口值, 以及是否要链接数据文件而不是默认的复制行为。

    如果你使用链接模式,升级将会快很多(不需要文件拷贝)并且将使用 更少的磁盘空间,但是在升级后一旦启动新集簇,旧集簇就无法被访问。 链接模式也要求新旧集簇数据目录位于同一个文件系统中(表空间和 pg_wal可以在不同的文件系统中)。完整的选项列表 可见pg_upgrade --help

    --jobs选项允许多个 CPU 核心被用来复制/链接文件以及 并行地转储和重载数据库模式。这个选项一个比较好的值是 CPU 核心数 和表空间数的最大值。这个选项可以显著地减少升级运行在一台多处理 器机器上的多数据库服务器的时间。

    对于 Windows 用户,你必须以一个超级账号登录,并且以 postgres用户启动一个 shell 并且设置正确的路径:

    RUNAS /USER:postgres "CMD.EXE"
    SET PATH=%PATH%;C:\Program Files\PostgreSQL\10\bin;

    并且用带引号的目录运行pg_upgrade,例如:

    pg_upgrade.exe
            --old-datadir "C:/Program Files/PostgreSQL/9.6/data"
            --new-datadir "C:/Program Files/PostgreSQL/10/data"
            --old-bindir "C:/Program Files/PostgreSQL/9.6/bin"
            --new-bindir "C:/Program Files/PostgreSQL/10/bin"

    一旦启动,pg_upgrade将验证两个集簇是否兼容并且 执行升级。你可以使用pg_upgrade --check来只执行检查, 这种模式即使在旧服务器还在运行时也能使用。 pg_upgrade --check也将列出任何在更新后需要做的手工 调整。如果你将要使用链接模式,你应该使用--link选项和 --check一起来启用链接模式相关的检查。 pg_upgrade要求在当前目录中的写权限。

    显然,没有人可以在升级期间访问这些集簇。pg_upgrade 默认会在端口 50432 上运行服务器来避免意外的客户端连接。在做升级时, 可以对两个集簇使用相同的端口号,因为新旧集簇不会在同时被运行。不过, 在检查一个旧的运行中服务器时,新旧端口号必须不同。

    如果在恢复数据库模式时发生错误,pg_upgrade将会退出 并且你必须按照下文步骤 16中所说的恢复 旧集簇。要再次尝试pg_upgrade,你将需要修改 旧集簇,这样 pg_upgrade 模式会成功恢复。如果问题是一个 contrib模块, 你可能需要从旧集簇中卸载该模块并且在升级后重新把它安装在新集簇中,不过 这样做的前提是该模块没有被用来存储用户数据。

  10. 升级流复制和日志传送后备服务器

    如果使用连接模式并且有流复制(见第 26.2.5 节)或者日志 传送(见第 26.2 节)后备服务器,可以遵照下面的 步骤对它们进行快速升级。你将不用在这些后备服务器上运行 pg_upgrade,而是在主服务器上运行rsync。 到这里还不要启动任何服务器。

    如果您没有使用链接模式,没有或不想使用rsync, 或者想要更简单的解决方案,请跳过本节中的说明并在pg_upgrade 完成且新的主服务器正在运行后简单地重新创建备用服务器。

    1. 在后备服务器上安装新的 PostgreSQL 二进制文件

      确保新的二进制和支持文件被安装在所有后备服务器上。

    2. 确保存在新的后备机数据目录

      确保新的后备机数据目录存在或者为空。如果 运行过initdb,请删除后备服务器的新数据目录。

    3. 安装自定义共享对象文件

      将相同的自定义共享对象文件安装在新主群集中安装的新备用数据库上。

    4. 停止后备服务器

      如果后备服务器仍在运行,现在使用上述的指令停止它们。

    5. 保存配置文件

      保存您需要保留的旧备用数据目录中的所有配置文件,例如 postgresql.confrecovery.conf, 因为这些将在下一步被覆盖或删除。

    6. 运行rsync

      使用链接模式时,可以使用rsync快速升级备用服务器。 为了实现这个目标,可以从主服务器上新旧数据库集群目录之上的一个目录, 在主服务器上为每个备用服务器运行::

      rsync --archive --delete --hard-links --size-only --no-inc-recursive old_pgdata new_pgdata remote_dir

      其中old_pgdatanew_pgdata是相对于主目录上的当前目录, 而remote_dir是后备服务器上一个高于新旧集簇目录的目录。 主服务器和后备服务器上指定目录下的目录结构必须匹配。 有关指定远程目录的详细信息,请参阅rsync手册页,例如

      rsync --archive --delete --hard-links --size-only --no-inc-recursive /opt/PostgreSQL/9.5/data \
            /opt/PostgreSQL/9.6/data standby.example.com:/opt/PostgreSQL

      您可以使用rsync--dry-run选项来验证命令将执行的操作。 虽然rsync必须在主服务器上至少运行一个备用服务器, 但是可以在升级的备用服务器上运行rsync以升级其他备用服务器, 只要升级的备用服务器尚未开始。

      它所做的就是记录由pg_upgrade的链接模式创建的链接, 用于连接主服务器上旧群集和新群集中的文件。然后它在备用的旧集群中找到匹配的文件, 并在备用的新集群中为它们创建链接。未在主节点上链接的文件将从主节点复制到备用节点。 (它们通常很小。)这提供了快速备机升级。不幸的是,rsync 会不必要地复制与临时表和非日志表关联的文件,因为这些文件通常不在备用服务器上。

      如果有表空间,你将需要为每一个表空间目录运行一个类似的 rsync命令,例如

      rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tblsp/PG_9.5_201510051 \
            /vol1/pg_tblsp/PG_9.6_201608131 standby.example.com:/vol1/pg_tblsp

      如果已经把pg_wal 放在了数据目录之外,也必须在这些目录上运行rsync

    7. 配置流复制和日志传送后备服务器

      为日志传送配置服务器(不需要运行pg_start_backup() 以及pg_stop_backup()或者做文件系统备份,因为备机 仍在与主机同步)。

  11. 恢复 pg_hba.conf

    如果你修改了pg_hba.conf,则要将其恢复到原始的设置。 也可能需要调整新集簇中的其他配置文件(例如 postgresql.conf)来匹配旧集簇。

  12. 启动新服务器

    现在可以安全地启动新的服务器,并且可以接着启动任何 rsync过的后备服务器。

  13. 升级后处理

    如果需要做任何升级后处理,pg_upgrade 将在完成后发出警告。它也将 生成必须由管理员运行的脚本文件。这些脚本文件将连接到每一个需要做 升级后处理的数据库。每一个脚本应该这样运行:

    psql --username=postgres --file=script.sql postgres

    这些脚本可以以任何顺序运行并且在运行之后立即删除。

    小心

    通常在重建脚本运行完成之前访问重建脚本中引用的表是不安全的,这样做 可能会得到不正确的结果或者很差的性能。没有在重建脚本中引用的表可以 随时被访问。

  14. 统计信息

    由于pg_upgrade并未传输优化器统计信息,在升级的尾声 你将被指示运行一个命令来生成这些信息。你可能需要设置连接参数来匹配你 的新集簇。

  15. 删除旧集簇

    一旦你对升级表示满意,你就可以通过运行 pg_upgrade完成时提到的脚本来删除旧集簇的 数据目录(如果在旧数据目录中有用户定义的表空间就不可能实现自动删除)。 你也可以删除旧安装目录(例如binshare)。

  16. 恢复到旧集簇

    在运行pg_upgrade之后,如果你希望恢复到 旧集簇,有几个选项:

    • 如果你运行了带有--checkpg_upgrade,则没有对旧集簇做修改并且 可以在任何时候重新使用它。

    • 如果你运行了带有--linkpg_upgrade,数据文件在新旧集簇之间 共享。如果你开启了新集簇,并且新服务器已经对这些共享文件做了写 入,那么使用旧集簇就不安全。

    • 如果你运行了不带 --linkpg_upgrade或者没有启动新服务器, 旧集簇还没有被修改,如果已经执行了链接,会在 $PGDATA/global/pg_control后追加一个 .old后缀。要重用旧集簇,可以从 $PGDATA/global/pg_control移除 .old后缀,然后你就能重启旧集簇了。

注解

pg_upgrade不支持对某些数据库的升级,此类 数据库包含以下reg*开头的 OID 引用的系统数据类型: regprocregprocedureregoperregoperatorregconfig以及regdictionaryregtype可以被升级)。

如果失败、重建和重索引会影响你的安装,pg_upgrade 将会报告这些情况。用来重建表和索引的升级后脚本将会自动被建立。 如果你正在尝试自动升级很多集簇,你应该发现具有相同数据库模式的集簇 对所有集簇升级都要求同样的升级后步骤,这是因为升级后步骤是基于数据 库模式而不是用户数据。

对于部署测试,创建一个只有模式的旧集簇副本,在其中插入假数据并且升级。

如果你在升级一个PostgreSQL 9.2 之前的集簇,并且 它使用一个只有配置文件的目录,你必须向pg_upgrade 传递真正的数据目录位置,并且把配置目录位置传递给服务器,例如 -d /real-data-directory -o '-D /configuration-directory'

如果正在使用的一个 9.1 之前的旧服务器用的是一个非默认Unix 域套接字目录 或者使用的默认值不同于新集簇的默认值,请把PGHOST设置为 指向旧服务器的套接字位置(这与 Windows 无关)。

如果你想要使用链接模式并且你不想让你的旧集簇在新集簇启动时被修改, 可以复制一份旧集簇并且在副本上以链接模式进行升级。要创建旧集簇的一 份合法拷贝,可以在服务器运行时使用rsync创建旧集簇的 一份脏拷贝,然后关闭旧服务器并且再次运行rsync --checksum 把更改更新到该拷贝以让其一致(--checksum是必要的,因为 rsync在判断文件修改时间的更改时的精度只能到秒级)。如 第 25.3.3 节中所述,你可能想要排除 一些文件,例如postmaster.pid。如果你的文件系统支持文 件系统快照或者 copy-on-write 文件副本,你可以使用它们来创建旧集簇和 表空间的一个备份,不过快照和副本必须被同时创建或者在数据库服务器关闭 期间被创建。

另见

initdb, pg_ctl, pg_dump, postgres