pg_upgrade — 升级 PostgreSQL 服务器实例
pg_upgrade
-b
oldbindir
[-B
newbindir
] -d
oldconfigdir
-D
newconfigdir
[option
...]
pg_upgrade(以前称为 pg_migrator)允许将存储在 PostgreSQL 数据文件中的数据升级到更高版本的 PostgreSQL 主要版本,而无需通常用于主要版本升级的数据转储/恢复,例如从 12.14 升级到 13.10 或从 14.9 升级到 15.5。对于次要版本升级,例如从 12.7 升级到 12.8 或从 14.1 升级到 14.5,则不需要使用此工具。
PostgreSQL 的主要版本定期添加新功能,这些功能通常会更改系统表的布局,但内部数据存储格式很少更改。pg_upgrade 利用这一事实,通过创建新的系统表并简单地重用旧的用户数据文件来执行快速升级。如果未来主要版本以某种方式更改了数据存储格式,导致旧数据格式无法读取,则 pg_upgrade 将无法用于此类升级。(社区将努力避免这种情况。)
pg_upgrade 会尽最大努力确保旧集群和新集群在二进制级别上兼容,例如,通过检查兼容的编译时设置,包括 32 位/64 位二进制文件。重要的是,任何外部模块也必须是二进制兼容的,尽管 pg_upgrade 无法检查这一点。
pg_upgrade 支持从 9.2.X 及更高版本升级到当前主要版本的 PostgreSQL,包括快照和测试版。
pg_upgrade 接受以下命令行参数
-b
bindir
--old-bindir=
bindir
旧的 PostgreSQL 可执行文件目录;环境变量 PGBINOLD
-B
bindir
--new-bindir=
bindir
新的 PostgreSQL 可执行文件目录;默认是 pg_upgrade 所在的目录;环境变量 PGBINNEW
-c
--check
仅检查集群,不更改任何数据
-d
configdir
--old-datadir=
configdir
旧的数据库集群配置目录;环境变量 PGDATAOLD
-D
configdir
--new-datadir=
configdir
新的数据库集群配置目录;环境变量 PGDATANEW
-j njobs
--jobs=njobs
要使用的并行进程或线程数
-k
--link
使用硬链接而不是将文件复制到新集群
-N
--no-sync
默认情况下,pg_upgrade
将等待升级后的集群的所有文件安全写入磁盘。此选项会导致 pg_upgrade
不等待就返回,速度更快,但这意味着后续的操作系统崩溃可能会导致数据目录损坏。通常,此选项对于测试很有用,但不应在生产安装中使用。
-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 和日志文件
-s
dir
--socketdir=
dir
升级期间用于 postmaster 套接字的目录;默认是当前工作目录;环境变量 PGSOCKETDIR
-U
username
--username=
username
集群的安装用户名;环境变量 PGUSER
-v
--verbose
启用详细的内部日志记录
-V
--version
显示版本信息,然后退出
--clone
使用高效的文件克隆(在某些系统上也称为 “reflinks”)而不是将文件复制到新集群。这可以导致数据文件的近乎瞬时的复制,从而在保留旧集群不变的情况下,获得 -k
/--link
的速度优势。
文件克隆仅在某些操作系统和文件系统上受支持。如果选择了它,但不支持,则 pg_upgrade 运行将出错。目前,它在 Linux(内核 4.5 或更高版本)上的 Btrfs 和 XFS(在创建时启用了 reflink 支持的文件系统上)以及 macOS 上的 APFS 上受支持。
--copy
将文件复制到新集群。这是默认设置。(另请参阅 --link
和 --clone
。)
--copy-file-range
使用 copy_file_range
系统调用进行高效复制。在某些文件系统上,这会产生类似于 --clone
的结果,共享物理磁盘块,而在另一些文件系统上,它仍然可以复制块,但会通过优化的路径进行复制。目前,它在 Linux 和 FreeBSD 上受支持。
--sync-method=
method
当设置为 fsync
(默认值)时,pg_upgrade
将递归打开并同步升级后的集群数据目录中的所有文件。文件搜索将遵循 WAL 目录和每个配置的表空间的符号链接。
在 Linux 上,可以使用 syncfs
来请求操作系统同步包含升级后的集群数据目录、其 WAL 文件和每个表空间的整个文件系统。有关使用 syncfs
时需要注意的注意事项,请参阅 recovery_init_sync_method。
当使用 --no-sync
时,此选项不起作用。
-?
--help
显示帮助,然后退出
以下是使用 pg_upgrade 执行升级的步骤
可选地移动旧集群
如果您使用的是特定版本的安装目录,例如 /opt/PostgreSQL/17
,则无需移动旧集群。图形安装程序都使用特定版本的安装目录。
如果您的安装目录不是特定版本的,例如 /usr/local/pgsql
,则有必要移动当前的 PostgreSQL 安装目录,以免干扰新的 PostgreSQL 安装。一旦当前的 PostgreSQL 服务器关闭,重命名 PostgreSQL 安装目录是安全的;假设旧目录是 /usr/local/pgsql
,您可以执行
mv /usr/local/pgsql /usr/local/pgsql.old
来重命名该目录。
对于源代码安装,构建新版本
使用与旧集群兼容的 configure
标志构建新的 PostgreSQL 源代码。pg_upgrade 将检查 pg_controldata
,以确保所有设置在开始升级之前都是兼容的。
安装新的 PostgreSQL 二进制文件
安装新服务器的二进制文件和支持文件。默认安装中包含 pg_upgrade。
对于源代码安装,如果您希望将新服务器安装在自定义位置,请使用 prefix
变量
make prefix=/usr/local/pgsql.new install
初始化新的 PostgreSQL 集群
使用 initdb
初始化新的集群。同样,使用与旧集群匹配的兼容的 initdb
标志。许多预构建的安装程序会自动执行此步骤。无需启动新的集群。
安装扩展共享对象文件
许多扩展和自定义模块,无论是来自 contrib
还是其他来源,都使用共享对象文件(或 DLL),例如 pgcrypto.so
。如果旧集群使用了这些文件,则必须将与新服务器二进制文件匹配的共享对象文件安装到新集群中,通常通过操作系统命令。不要加载模式定义,例如 CREATE EXTENSION pgcrypto
,因为这些定义将从旧集群复制。如果有可用的扩展更新,pg_upgrade 将报告这一点,并创建一个可以稍后运行以更新它们的脚本。
复制自定义全文搜索文件
将任何自定义全文搜索文件(词典、同义词、词库、停用词)从旧集群复制到新集群。
调整身份验证
pg_upgrade
将多次连接到旧服务器和新服务器,因此您可能希望在 pg_hba.conf
中将身份验证设置为 peer
或使用 ~/.pgpass
文件(请参阅第 32.16 节)。
准备发布者升级
pg_upgrade 尝试迁移逻辑槽。这有助于避免在新发布者上手动定义相同逻辑槽的需求。只有当旧集群的版本为 17.0 或更高时,才支持逻辑槽的迁移。对于版本低于 17.0 的集群,逻辑槽将被静默忽略。
在开始升级发布者集群之前,请确保通过执行 ALTER SUBSCRIPTION ... DISABLE
临时禁用订阅。升级后重新启用订阅。
pg_upgrade 能够升级逻辑槽有一些先决条件。如果未满足这些条件,将会报告错误。
新集群必须将 wal_level
设置为 logical
。
新集群必须将 max_replication_slots
配置为大于或等于旧集群中存在的槽数量的值。
旧集群上的槽引用的输出插件必须安装在新 PostgreSQL 可执行文件目录中。
旧集群已将所有事务和逻辑解码消息复制到订阅者。
旧集群上的所有槽都必须可用,即,不存在 pg_replication_slots.conflicting
不为 true
的槽。
新集群不得有永久逻辑槽,即,不存在 pg_replication_slots.temporary
为 false
的槽。
准备订阅者升级
在新订阅者中设置订阅者配置。pg_upgrade 尝试迁移订阅依赖关系,包括 pg_subscription_rel 系统目录中存在的订阅表信息以及订阅的复制源。这允许新订阅者上的逻辑复制从旧订阅者停止的地方继续。只有当旧集群的版本为 17.0 或更高时,才支持订阅依赖关系的迁移。对于版本低于 17.0 的集群,订阅依赖关系将被静默忽略。
pg_upgrade 能够升级订阅有一些先决条件。如果未满足这些条件,将会报告错误。
旧订阅者中的所有订阅表都应处于 i
(初始化) 或 r
(就绪) 状态。可以通过检查 pg_subscription_rel.srsubstate
来验证这一点。
与每个订阅对应的复制源条目应存在于旧集群中。可以通过检查 pg_subscription 和 pg_replication_origin 系统表来查找。
新集群必须将 max_replication_slots
配置为大于或等于旧集群中存在的订阅数量的值。
停止两个服务器
确保使用以下命令停止两个数据库服务器,例如在 Unix 上:
pg_ctl -D /opt/PostgreSQL/12 stop pg_ctl -D /opt/PostgreSQL/17 stop
或者在 Windows 上,使用正确的服务名称
NET STOP postgresql-12 NET STOP postgresql-17
流复制和日志传送备用服务器必须在此关闭期间运行,以便它们接收所有更改。
准备备用服务器升级
如果您使用步骤 13中概述的方法升级备用服务器,请通过针对旧主服务器和备用集群运行 pg_controldata 来验证旧备用服务器是否已追上。验证所有集群中的 “最新检查点位置” 值是否匹配。此外,请确保新主集群上的 postgresql.conf
文件中的 wal_level
未设置为 minimal
。
运行 pg_upgrade
始终运行新服务器的 pg_upgrade 二进制文件,而不是旧服务器的。 pg_upgrade 需要指定旧集群和新集群的数据和可执行文件 (bin
) 目录。您还可以指定用户和端口值,以及您希望数据文件以链接还是克隆的方式而不是默认的复制行为进行处理。
如果您使用链接模式,升级速度会快得多(无需复制文件)并且占用更少的磁盘空间,但是一旦您在升级后启动新集群,您将无法访问旧集群。链接模式还要求旧集群和新集群的数据目录位于同一文件系统中。(表空间和 pg_wal
可以位于不同的文件系统中。) 克隆模式提供相同的速度和磁盘空间优势,但不会导致新集群启动后旧集群无法使用。克隆模式还要求旧数据目录和新数据目录位于同一文件系统中。此模式仅在某些操作系统和文件系统上可用。
--jobs
选项允许使用多个 CPU 内核来复制/链接文件以及并行转储和恢复数据库模式;一个好的起点是 CPU 内核数和表空间的最大值。此选项可以显著减少在多处理器机器上运行的多数据库服务器的升级时间。
对于 Windows 用户,您必须登录到管理帐户,然后运行带有引号目录的 pg_upgrade,例如:
pg_upgrade.exe --old-datadir "C:/Program Files/PostgreSQL/12/data" --new-datadir "C:/Program Files/PostgreSQL/17/data" --old-bindir "C:/Program Files/PostgreSQL/12/bin" --new-bindir "C:/Program Files/PostgreSQL/17/bin"
启动后,pg_upgrade
将验证两个集群是否兼容,然后执行升级。您可以使用 pg_upgrade --check
仅执行检查,即使旧服务器仍在运行。 pg_upgrade --check
还会概述您在升级后需要进行的任何手动调整。如果您打算使用链接或克隆模式,则应使用带有 --check
的 --link
或 --clone
选项来启用特定于模式的检查。 pg_upgrade
需要当前目录的写入权限。
显然,在升级期间不应有人访问集群。 pg_upgrade 默认在端口 50432 上运行服务器,以避免意外的客户端连接。在进行升级时,您可以对两个集群使用相同的端口号,因为旧集群和新集群不会同时运行。但是,当检查正在运行的旧服务器时,旧端口号和新端口号必须不同。
如果在恢复数据库模式时发生错误,pg_upgrade
将退出,并且您必须按照下面的步骤 19中所述恢复到旧集群。要再次尝试 pg_upgrade
,您需要修改旧集群,以便 pg_upgrade 模式恢复成功。如果问题是 contrib
模块,则您可能需要从旧集群卸载 contrib
模块,并在升级后将其安装到新集群中,前提是该模块未用于存储用户数据。
升级流复制和日志传送备用服务器
如果您使用了链接模式并且有流复制(请参阅 第 26.2.5 节)或日志传送(请参阅 第 26.2 节)备用服务器,则可以按照以下步骤快速升级它们。您不会在备用服务器上运行 pg_upgrade,而是在主服务器上运行 rsync。不要启动任何服务器。
如果您没有使用链接模式,没有或不想使用 rsync,或者想要更简单的解决方案,请跳过本节中的说明,只需在 pg_upgrade 完成且新的主服务器正在运行时重新创建备用服务器即可。
在备用服务器上安装新的 PostgreSQL 二进制文件
确保新的二进制文件和支持文件已安装在所有备用服务器上。
确保新的备用数据目录不存在
确保新的备用数据目录不存在或为空。如果运行了 initdb,请删除备用服务器的新数据目录。
安装扩展共享对象文件
在新备用服务器上安装与您在新主集群中安装的相同的扩展共享对象文件。
停止备用服务器
如果备用服务器仍在运行,请立即使用上述说明停止它们。
保存配置文件
从您需要保留的旧备用服务器的配置目录中保存任何配置文件,例如, postgresql.conf
(以及它包含的任何文件)、postgresql.auto.conf
、pg_hba.conf
,因为这些文件将在下一步中被覆盖或删除。
运行 rsync
使用链接模式时,可以使用 rsync 快速升级备用服务器。为此,从主服务器上高于旧数据库集群目录和新数据库集群目录的目录中,在每个备用服务器的主服务器上运行此命令
rsync --archive --delete --hard-links --size-only --no-inc-recursive old_cluster new_cluster remote_dir
其中 old_cluster
和 new_cluster
相对于主服务器上的当前目录,remote_dir
高于备用服务器上的旧集群目录和新集群目录。主服务器和备用服务器上指定目录下的目录结构必须匹配。有关指定远程目录的详细信息,请参阅 rsync 手册页,例如,
rsync --archive --delete --hard-links --size-only --no-inc-recursive /opt/PostgreSQL/12 \ /opt/PostgreSQL/17 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_12_201909212 \ /vol1/pg_tblsp/PG_17_202307071 standby.example.com:/vol1/pg_tblsp
如果您已将 pg_wal
重新定位到数据目录之外,则也必须对这些目录运行 rsync。
配置流复制和日志传送备用服务器
为日志传送配置服务器。(您无需运行 pg_backup_start()
和 pg_backup_stop()
或进行文件系统备份,因为备用服务器仍与主服务器同步。) 如果旧主服务器的版本低于 17.0,则主服务器上的任何槽都不会复制到新的备用服务器,因此旧备用服务器上的所有槽都必须手动重新创建。如果旧主服务器的版本为 17.0 或更高版本,则只有主服务器上的逻辑槽才会复制到新的备用服务器,但旧备用服务器上的其他槽不会被复制,因此必须手动重新创建。
恢复 pg_hba.conf
如果您修改了 pg_hba.conf
,请恢复其原始设置。可能还需要调整新集群中的其他配置文件以匹配旧集群,例如 postgresql.conf
(以及它包含的任何文件)、postgresql.auto.conf
。
启动新服务器
现在可以安全地启动新服务器,然后启动任何通过 rsync 同步的备用服务器。
升级后处理
如果需要任何升级后处理,pg_upgrade
将在完成时发出警告。它还将生成必须由管理员运行的脚本文件。这些脚本文件将连接到每个需要升级后处理的数据库。每个脚本应使用以下方式运行:
psql --username=postgres --file=script.sql postgres
这些脚本可以按任意顺序运行,并且在运行后可以删除。
通常,在重建脚本完成运行之前访问重建脚本中引用的表是不安全的;这样做可能会产生不正确的结果或性能不佳。未在重建脚本中引用的表可以立即访问。
统计信息
由于优化器统计信息不会被 pg_upgrade
传输,您将被指示在升级结束时运行命令来重新生成该信息。您可能需要设置连接参数以匹配您的新集群。
使用 vacuumdb --all --analyze-only
可以有效地生成此类统计信息,并且使用 --jobs
可以加快速度。可以使用选项 --analyze-in-stages
快速生成最少的统计信息。如果 vacuum_cost_delay
设置为非零值,则可以使用 PGOPTIONS
来覆盖此设置以加快统计信息的生成,例如 PGOPTIONS='-c vacuum_cost_delay=0' vacuumdb ...
。
删除旧集群
如果您对升级感到满意,则可以通过运行 pg_upgrade
完成时提到的脚本来删除旧集群的数据目录。(如果您的旧数据目录中有用户定义的表空间,则无法自动删除。)您还可以删除旧的安装目录(例如,bin
,share
)。
恢复到旧集群
如果在运行 pg_upgrade
后,您希望恢复到旧集群,则有以下几种选择:
如果使用了 --check
选项,则旧集群未被修改;它可以重新启动。
如果 --link
选项 没有 被使用,则旧集群未被修改;它可以重新启动。
如果使用了 --link
选项,则数据文件可能在旧集群和新集群之间共享。
如果 pg_upgrade
在链接开始之前中止,则旧集群未被修改;它可以重新启动。
如果您没有启动新集群,则旧集群未被修改,只是在链接开始时,将 .old
后缀附加到了 $PGDATA/global/pg_control
。 要重用旧集群,请从 $PGDATA/global/pg_control
中删除 .old
后缀;然后您可以重新启动旧集群。
如果您启动了新集群,它已写入共享文件,并且使用旧集群是不安全的。在这种情况下,需要从备份恢复旧集群。
可以使用一些环境变量为命令行选项提供默认值:
PGBINOLD
旧的 PostgreSQL 可执行文件目录;选项 -b
/--old-bindir
。
PGBINNEW
新的 PostgreSQL 可执行文件目录;选项 -B
/--new-bindir
。
PGDATAOLD
旧数据库集群配置目录;选项 -d
/--old-datadir
。
PGDATANEW
新数据库集群配置目录;选项 -D
/--new-datadir
。
PGPORTOLD
旧集群端口号;选项 -p
/--old-port
。
PGPORTNEW
新集群端口号;选项 -P
/--new-port
。
PGSOCKETDIR
升级期间用于 postmaster 套接字的目录;选项 -s
/--socketdir
。
PGUSER
集群的安装用户名;选项 -U
/--username
。
pg_upgrade 会创建各种工作文件,例如模式转储,这些文件存储在新的集群目录中的 pg_upgrade_output.d
中。每次运行都会创建一个新的子目录,该子目录的名称以 ISO 8601 (%Y%m%dT%H%M%S
) 格式的时间戳命名,其中存储所有生成的文件。如果 pg_upgrade 成功完成,pg_upgrade_output.d
及其包含的文件将自动删除;但如果出现问题,那里的文件可能会提供有用的调试信息。
pg_upgrade 在旧数据目录和新数据目录中启动短暂的 postmaster。默认情况下,用于与这些 postmaster 通信的临时 Unix 套接字文件在当前工作目录中创建。在某些情况下,当前目录的路径名可能太长而无法成为有效的套接字名称。在这种情况下,可以使用 -s
选项将套接字文件放在路径名较短的某个目录中。为了安全起见,请确保该目录不可被任何其他用户读取或写入。(Windows 不支持此功能。)
如果失败、重建和重新索引的情况影响您的安装,pg_upgrade 将报告所有这些情况;将自动生成用于重建表和索引的升级后脚本。如果您尝试自动化多个集群的升级,您应该会发现具有相同数据库模式的集群在所有集群升级中都需要相同的升级后步骤;这是因为升级后步骤基于数据库模式,而不是用户数据。
对于部署测试,请创建旧集群的仅模式副本,插入虚拟数据,然后升级该副本。
pg_upgrade 不支持升级包含使用以下 reg*
OID 引用系统数据类型的表列的数据库:
regcollation |
regconfig |
regdictionary |
regnamespace |
regoper |
regoperator |
regproc |
regprocedure |
(可以升级 regclass
、regrole
和 regtype
。)
如果您想使用链接模式,并且不希望在启动新集群时修改旧集群,请考虑使用克隆模式。如果克隆模式不可用,请创建旧集群的副本,并在链接模式下升级该副本。要创建旧集群的有效副本,请在使用服务器运行时使用 rsync
创建旧集群的脏副本,然后关闭旧服务器并再次运行 rsync --checksum
,以使用任何更改来更新副本,使其保持一致。(--checksum
是必需的,因为 rsync
的文件修改时间粒度只有一秒。)您可能需要排除一些文件,例如 postmaster.pid
,如第 25.3.4 节 中所述。如果您的文件系统支持文件系统快照或写入时复制的文件副本,则可以使用它来备份旧集群和表空间,尽管快照和副本必须同时创建或在数据库服务器关闭时创建。
如果您在文档中发现任何不正确的内容、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 来报告文档问题。