pg_upgrade — 升级PostgreSQL服务器实例
pg_upgrade
-b
oldbindir
[-B
newbindir
] -d
oldconfigdir
-D
newconfigdir
[option
...]
pg_upgrade(以前称为pg_migrator)允许将存储在 PostgreSQL数据文件中的数据升级到后续的PostgreSQL 主要版本,而无需进行通常需要的数据转储/恢复 主要版本升级,例如,从9.5.8升级到9.6.4或从10.7升级到11.2。 对于次要版本升级,例如,从9.6.2升级到9.6.3 或从10.1升级到10.2,则不需要。
PostgreSQL主发行版本通常会加入新的特性,这些新特性常常会更改系统表的 布局,但是内部数据存储格式很少会改变。pg_upgrade 使用这一事实来通过创建新系统表并且重用旧的用户数据文件来执行快速升级。 如果未来的主发行版本更改了数据存储格式,导致旧数据格式不可读,那么 pg_upgrade将无法用于此类升级。(社区将努力避免这种情况)。
pg_upgrade会尽力(例如通过检查兼容的编译时设 置)确保新旧集簇在二进制上也是兼容的,包括 32/64 位二进制。保持 外部模块也是二进制兼容的也很重要,不过 pg_upgrade无法检查这一点。
pg_upgrade支持从9.2.X及更高版本升级到当前主要版本的PostgreSQL,包括快照和beta版本。
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。
-?
--help
显示帮助信息,然后退出
下面是用pg_upgrade执行一次升级的步骤:
移动旧集簇(可选)
如果你在使用一个与版本相关的安装目录(例如
/opt/PostgreSQL/15
),你就不需要移动旧的集簇。
图形化的安装程序会使用版本相关的安装目录。
如果你的安装目录不是版本相关的(例如/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
或其他源,使用共享对象文件(或DLLs),例如, pgcrypto.so
。
如果旧集群使用过这些,匹配新服务器二进制的共享对象文件,必须安装在新集群中。
通常是通过操作系统命令。
不要加载模式定义,例如CREATE EXTENSION pgcrypto
,因为这些将从旧集群复制。
如果扩展更新是可用的,pg_upgrade将报告这一点,并创建一个脚本,可以稍后运行来更新它们。
拷贝定制的全文本检索文件
从旧集群向新集群拷贝任何定制化全文本检索文件(词典、同义词、辞典、停用词)
调整认证
pg_upgrade
将会多次连接到旧服务器和新服务器,因此
你可能想要在pg_hba.conf
中把认证设置成
peer
或者使用一个~/.pgpass
文件(见
第 34.16 节)。
停止两个服务器
确认两个数据库服务器都被停止使用,例如在 Unix 上可以:
pg_ctl -D /opt/PostgreSQL/9.6 stop pg_ctl -D /opt/PostgreSQL/15 stop
或者在 Windows 上使用正确的服务名:
NET STOP postgresql-9.6 NET STOP postgresql-15
流复制和日志传送备用服务器必须在此关闭期间运行,以便它们接收所有更改。
为后备服务器升级做准备
如果您正在使用第步骤 11节中概述的方法升级备用服务器,请通过运行pg_controldata命令检查旧的备用服务器和主服务器集群是否同步。
确保所有集群中“最新检查点位置”的值匹配。此外,请确保在新的主服务器集群的postgresql.conf
文件中未将wal_level
设置为minimal
。
运行 pg_upgrade
总是应该运行新服务器而不是旧服务器的pg_upgrade二进制文件。
pg_upgrade要求制定新旧集簇的数据和可执行文件(bin
)目录。
你也可以指定用户和端口值,以及你是否想要用链接或克隆来取代默认的复制行为对数据文件进行处理。
如果你使用链接模式,升级将会快很多(不需要文件拷贝)并且将使用
更少的磁盘空间,但是在升级后一旦启动新集簇,旧集簇就无法被访问。
链接模式也要求新旧集簇数据目录位于同一个文件系统中(表空间和
pg_wal
可以在不同的文件系统中)。
克隆模式提供了相同的速度以及磁盘空间优势,但不会导致新群集启动后旧群集不可用。
克隆模式还需要新旧数据目录位于同一文件系统中。 此模式仅在某些操作系统和文件系统上可用。
--jobs
选项允许多个CPU核用于文件的复制/链接以及并行转储和恢复数据库模式;一个好的起点是CPU核数和表空间数的最大值。这个选项可以显著减少在多处理器机器上运行的多数据库服务器升级所需的时间。
对于 Windows 用户,你必须以一个超级账号登录,并且以
postgres
用户启动一个 shell 并且设置正确的路径:
RUNAS /USER:postgres "CMD.EXE" SET PATH=%PATH%;C:\Program Files\PostgreSQL\15\bin;
并且用带引号的目录运行pg_upgrade,例如:
pg_upgrade.exe --old-datadir "C:/Program Files/PostgreSQL/9.6/data" --new-datadir "C:/Program Files/PostgreSQL/15/data" --old-bindir "C:/Program Files/PostgreSQL/9.6/bin" --new-bindir "C:/Program Files/PostgreSQL/15/bin"
一旦启动,pg_upgrade
将验证两个集簇是否兼容并且
执行升级。你可以使用pg_upgrade --check
来只执行检查,
这种模式即使在旧服务器还在运行时也能使用。
pg_upgrade --check
也将列出任何在更新后需要做的手工调整。
如果你将要使用链接或克隆模式,你应该使用--link
或--clone
选项和--check
一起来启用链接模式相关的检查。
pg_upgrade
要求在当前目录中的写权限。
显然,没有人可以在升级期间访问这些集簇。pg_upgrade 默认会在端口 50432 上运行服务器来避免意外的客户端连接。在做升级时, 可以对两个集簇使用相同的端口号,因为新旧集簇不会在同时被运行。不过, 在检查一个旧的运行中服务器时,新旧端口号必须不同。
如果在恢复数据库模式时发生错误,pg_upgrade
将会退出
并且你必须按照下文步骤 17中所说的恢复
旧集簇。要再次尝试pg_upgrade
,你将需要修改
旧集簇,这样 pg_upgrade 模式会成功恢复。如果问题是一个
contrib
模块,
你可能需要从旧集簇中卸载该模块并且在升级后重新把它安装在新集簇中,不过
这样做的前提是该模块没有被用来存储用户数据。
升级流复制和日志传送后备服务器
如果使用链接模式并且有流复制(见第 27.2.5 节)或者日志 传送(见第 27.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/9.5 \ /opt/PostgreSQL/9.6 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。
配置流复制和日志传送后备服务器
配置服务器进行日志传送。(您无需运行pg_backup_start()
和pg_backup_stop()
或进行文件系统备份,因为备用服务器仍与主服务器同步。) 复制槽不会被复制,必须重新创建。
恢复 pg_hba.conf
如果你修改了pg_hba.conf
,则要将其恢复到原始的设置。
也可能需要调整新集簇中的其他配置文件来匹配旧集簇,例如
postgresql.conf
(以及它包含的任何文件)和
postgresql.auto.conf
。
启动新服务器
现在可以安全地启动新的服务器,并且可以接着启动任何 rsync过的后备服务器。
升级后处理
如果需要做任何升级后处理,pg_upgrade 将在完成后发出警告。它也将 生成必须由管理员运行的脚本文件。这些脚本文件将连接到每一个需要做 升级后处理的数据库。每一个脚本应该这样运行:
psql --username=postgres --file=script.sql postgres
这些脚本可以以任何顺序运行并且在运行之后立即删除。
通常在重建脚本运行完成之前访问重建脚本中引用的表是不安全的,这样做 可能会得到不正确的结果或者很差的性能。没有在重建脚本中引用的表可以 随时被访问。
统计信息
由于pg_upgrade
并未传输优化器统计信息,在升级的尾声
你将被指示运行一个命令来生成这些信息。你可能需要设置连接参数来匹配你
的新集簇。
删除旧集簇
一旦你对升级表示满意,你就可以通过运行
pg_upgrade
完成时提到的脚本来删除旧集簇的
数据目录(如果在旧数据目录中有用户定义的表空间就不可能实现自动删除)。
你也可以删除旧安装目录(例如bin
、share
)。
恢复到旧集簇
在运行pg_upgrade
之后,如果你希望恢复到
旧集簇,有几个选项:
如果使用了 --check
选项, 则旧集群没有被修改;它可以被重新启动。
如果 --link
选项 没有被使用, 旧集群没有被修改;它可以被重新启动。
如果使用了--link
选项, 数据文件可能在新旧群集之间共享:
如果pg_upgrade
在链接启动之前中止,旧群集没有被修改,它可以重新启动。
如果你没有启动新集群,旧集群没有被修改,当链接启动时,一个.old
后缀会附加到$PGDATA/global/pg_control
。
如果要重用旧集群,从$PGDATA/global/pg_control
移除.old
后缀;你就可以重启旧集群。
如果你已经启动新群集,它已经写入了共享文件,并且使用旧群集会不安全。这种情况下,需要从备份中还原旧群集。
pg_upgrade创建各种工作文件,例如模式转储,存储在新集群目录中的pg_upgrade_output.d
中。
每次运行都会创建一个新的子目录,以ISO 8601格式化的时间戳命名(%Y%m%dT%H%M%S
),其中存储了所有生成的文件。
如果pg_upgrade成功完成,则pg_upgrade_output.d
及其包含的文件将被自动删除;
但如果出现问题,则那里的文件可能提供有用的调试信息。
pg_upgrade在新旧数据目录中启动短期的postmasters。临时 Unix 套接字文件用于与这些postmasters通信,默认情况下,在当前工作目录中进行。
在某些情况下,当前目录的路径名称可能太长,无法成为有效的套接字名称。这种情况下你可以使用-s
选项将套接字文件放在某些具有较短路径名称的目录中。
为了安全原因,请确保该目录不可被任何其他用户读取或者写入。(这在 Windows 上不受支持。)
如果失败、重建和重新索引会影响你的安装,pg_upgrade 将会报告这些情况。用来重建表和索引的升级后脚本将会自动被建立。 如果你正在尝试自动升级很多集簇,你应该发现具有相同数据库模式的集簇 对所有集簇升级都要求同样的升级后步骤,这是因为升级后步骤是基于数据 库模式而不是用户数据。
对于部署测试,创建一个只有模式的旧集簇副本,在其中插入假数据并且升级。
pg_upgrade不支持包含使用这些reg*
OID-引用 系统数据类型的表列的数据库的升级:
regcollation |
regconfig |
regdictionary |
regnamespace |
regoper |
regoperator |
regproc |
regprocedure |
(regclass
, regrole
, and regtype
can be upgraded.)
如果你想要使用链接模式并且你不想让你的旧集簇在新集簇启动时被修改,考虑使用克隆模式。
如果(克隆模式)不可用,可以复制一份旧集簇并且在副本上以链接模式进行升级。要创建旧集簇的一
份合法拷贝,可以在服务器运行时使用rsync
创建旧集簇的
一份脏拷贝,然后关闭旧服务器并且再次运行rsync --checksum
把更改更新到该拷贝以让其一致(--checksum
是必要的,因为
rsync
在判断文件修改时间的更改时的精度只能到秒级)。如
第 26.3.3 节中所述,你可能想要排除
一些文件,例如postmaster.pid
。如果你的文件系统支持文
件系统快照或者 copy-on-write 文件副本,你可以使用它们来创建旧集簇和
表空间的一个备份,不过快照和副本必须被同时创建或者在数据库服务器关闭
期间被创建。