【PostgreSQL】使用 pg_upgrade 检查 Postgres 升级

翻译:Kimi助手

Postgres 是一个出色的数据库系统,但它确实有一个五年的生命周期。这意味着您至少需要每五年对其进行一次重大升级。幸运的是,Postgres 提供了一个名为 pg_upgrade 的程序,它能够实现从一个主要版本的 Postgres 到另一个版本的快速且简便的迁移。

让我们通过一个例子来了解如何进行升级 - 在这个案例中,我们将从 Postgres 12 升级到 Postgres 16。您应该始终目标是升级到尽可能高的版本。检查 postgresql.org 来查看当前的版本是什么。如果您遇到问题,官方文档有很多细节可以参考。

pg_upgrade 程序的工作原理是在空的 Postgres 集群(新版本)中填充数据,基于您现有的 Postgres 集群中的数据。它复制系统目录信息,然后复制或硬链接数据文件。即使在大型多TB的系统上,如果您使用 --link 选项,这个过程也可能在不到一分钟内完成!让我们来看一下运行 pg_upgrade 的基本步骤。

设置

在开始之前,在开发环境中测试您的应用程序对新版本的兼容性。阅读发布说明 - 您需要检查您跨越的每个主要版本的“点零”发布说明。
在我们从 12 升级到 16 的例子中,我们希望检查 Postgres 13.0、14.0、15.0、16.0 和 16.x 系列中最新版本的发布说明。实际上,这可能是整个过程中最长的步骤!

下一步是安装新版本。我们不仅需要新的可执行文件和库,还必须创建一个新的集群,这将成为我们的新实例。安装取决于您的操作系统,但总体思路是使用您已经拥有的相同包,只是版本更高。这里有一个配方可以帮助您在支持 yum 的系统上完成这个操作:

yum list installed 'postgresql12*' | sed -e '1d; s/postgresql12/yum install postgresql16/; s/\\..*//'
yum install postgresql16
yum install postgresql16-contrib
yum install postgresql16-libs
yum install postgresql16-server

当新包版本就位后,我们需要创建一个新的集群。为此,我们将使用 initdb 命令。在一些操作系统上,它甚至可能不在你的路径中。在 Red Hat 启发的系统上,检查 /usr/pgsql‑16/bin/initdb。一旦找到,以 postgres 用户身份运行(带有 --version 参数)以确保它是您正在追求的目标版本(在我们的例子中是 16)。然后使用您的真实参数运行它以创建一个新的数据目录。特别注意使用与旧版 Postgres 创建数据目录时相同的参数。特别是,如果旧集群也启用了页面级校验和,那么在这个新集群中也要启用它。

由于新版本的各种 Postgres 可执行文件可以处理旧版本的 Postgres,我们可以将这个位置添加到我们的路径中:

export PATH=$PATH:/usr/pgsql-16/bin/
initdb --version
initdb --data-checksums -D /var/lib/pgsql/16

没有必要启动新集群 - pg_upgrade 将作为其过程的一部分自行完成。如果您有任何自定义扩展,或者您的打包系统没有处理的事情,现在根据需要安装它们。现在还没有到担心配置文件(如 postgresql.conf)的时候,这些稍后再说。

验证

下一步是使用 --check 参数运行 pg_upgrade 可执行文件。这确保一切看起来正常,而实际上并没有执行升级。pg_upgrade 程序始终需要知道四件事情的位置:旧的可执行文件、新的可执行文件、旧的数据目录和新的数据目录。虽然您可以将它们作为命令行参数输入,但使用环境变量会更清晰。现在让我们设置它们并运行检查:

export PGBINOLD=/usr/pgsql-12/bin
export PGBINNEW=/usr/pgsql-16/bin
export PGDATAOLD=/var/lib/pgsql/12
export PGDATANEW=/var/lib/pgsql/16
pg_upgrade --check

它将详细报告在两个 Postgres 集群之间发现的任何不兼容性。我们希望在底部看到这个消息:

集群是兼容的
如果您没有看到这个消息,您需要解决问题。失败的一个常见原因是校验和,给出像这样的消息:
旧集群不使用数据校验和,但新集群这样做
如果发生这种情况,请删除您的新数据目录,并重新运行 initdb 命令,这次不带 --data-checksums 参数。一个人总是可以在以后启用校验和。

备份

这是进行完整备份的好时机。如果出现问题,我们将有办法回到旧版本。通过以下方式启动完整备份:

pgbackrest backup --stanza=mystanza --type=full

没有 pgBackRest?
使用另一个可以完成、安全、高性能备份的系统是可以的。如果您没有备份系统,请停止升级并首先将其工作。这比您的重大升级更重要!

准备副本

如果您正在使用流复制,这些副本也需要升级。坏消息是我们不能在副本服务器上运行 pg_upgrade。好消息是升级它们的过程有些棘手,但很快。它们的升级发生在主服务器之后,但现在是准备事情的好时机。对于每个副本,您需要安装新的 Postgres 软件,就像我们上面做的那样,但不要运行 initdb。将每个副本上数据目录中存在的所有配置文件复制到目录外的安全地方。

升级

一旦备份和 pg_upgrade --check 完成,我们就准备好进行实际的升级了。非常重要的是确保您使用 --link 参数对 pg_upgrade 进行操作。这样做可以避免将旧集群的所有实际数据文件复制到新集群。相反,它在旧的和新的数据文件之间创建硬链接(不是更常见的符号链接)。这样做告诉操作系统每个数据文件有两个完全有效的路径可以访问文件。此外,与复制文件内容相比,它非常快速。命令看起来像这样:

# 这假设上面的 ENV 已经导出
pg_upgrade --link

运行这个命令后,当它启动新集群时,就没有简单的方法回到旧版本了。因此上面的备份步骤很重要。好消息是 pg_upgrade 程序经过了非常严格的测试,所以您不太可能需要恢复您的备份。pg_upgrade 命令的输出将类似于这样:

Upgrade Complete
----------------
Optimizer statistics are not transferred by pg_upgrade.
Once you start the new server, consider running:
    /home/greg/pg/16/bin/vacuumdb --all --analyze-in-stages
Running this script will delete the old cluster's data files:
    ./delete_old_cluster.sh

请注意,从 Postgres 14 开始,pg_upgrade 将不再创建一个 shell 脚本来帮助您重建统计数据,而是建议通过 vacuumdb 程序执行,即 vacuumdb --all --analyze-in-stages。这将对每个数据库进行三次运行。第一次运行的统计目标是 1(非常快,但统计数据非常粗糙),然后目标是 10(稍微慢一些,但统计数据要好得多),最后运行的值是 default_statistics_target(除非您已更改,否则为 100)。

复制和调整配置文件

现在新集群已经就位,在我们能够连接应用程序之前,还有一些更多的步骤需要完成。
新集群将有默认的 postgresql.conf、pg_hba.conf 和 pg_ident.conf 文件,这些并不是您想要的。从旧集群复制 pg_hba.conf 和 pg_ident.conf 文件。它们很可能无需任何修改就能工作,因为这些文件的格式很少改变。
接下来,您需要将旧的 postgresql.conf 文件与新的合并。如果您习惯在 postgresql.conf 文件的底部进行更改,您可以轻松地复制和粘贴它们。无论如何,您应该走过并确保所有设置仍然适用于新集群。不要忘记 postgresql.auto.conf 或任何由“include*”选项引用的 conf 文件。

打开校验和

如果您的新集群没有启用页面级校验和,这是一个很好的时机来启用它们。Postgres 附带了一个将您的集群更改为使用页面级校验和的程序,称为 pg_checksums。它将与我们上面使用的 initdb 在同一个目录中,用法如下:

pg_checksums -D $PGDATANEW --enable --verbose

这个程序需要重写集群中的每个文件,所以它可能需要一段时间,但这值得等待。这种重写将使下一步(同步您的副本)花费更长的时间;您可能更愿意从头开始重新创建副本。

同步您的副本

对于这部分,我将引用官方文档的第 11 步(“升级流复制和日志传输备用服务器”)。
按照那个 rsync 配方精确执行。未来可能会有更好的方法,所以我不想在这里留下一个链接,而不是复制那个大的 rsync 命令并在这里打印出来。😃
rsync 过程非常快速,因为它只复制已更改的文件。它比较主服务器上的新旧目录,然后是副本。与以前一样,这个过程的速度取决于文件的数量。您可以同时升级您的副本。

启动并生成统计数据

现在副本准备好了,您可以启动主服务器。如果您不是使用 pg_ctl 而是使用像 systemd 这样的东西,您可能需要调整一些配置文件或脚本以指向新的数据目录。如果集群在没有错误的情况下启动,恭喜您!您几乎拥有了一个工作集群。但是 Postgres 无法在没有关于表的良好统计数据的情况下生成良好的查询计划。截至本文撰写时,Postgres 不会从旧集群复制数据库统计数据到新集群。这一点将来会改变,但在它改变之前,您需要自己生成统计数据。正如我们上面看到的 pg_upgrade 输出所提到的,您可以分阶段进行,以便尽快生成统计数据:

vacuumdb --all --analyze-in-stages

如果您不需要分阶段进行,您可以简单地运行:

vacuumdb --all --analyze-only

升级扩展

Postgres 扩展有版本,并且可能需要它们自己的升级。做到这一点的方法是登录到新数据库并发出:

ALTER EXTENSION foobar UPDATE;

如果 pg_upgrade 能够检测到扩展,您将看到类似这样的消息:

Your installation contains extensions that should be updated
with the ALTER EXTENSION command.  The file
    update_extensions.sql
when executed by psql by the database superuser will update
these extensions.

不要忘记更新与您的数据库交互的所有内容,并告诉它您在一个新的主要版本上。您也可能有一个新的数据目录,某些工具需要知道这一点。请记住,重大升级意味着一个新的集群,一个新的系统标识符,以及新鲜的统计数据。

再次运行备份

这是再次运行备份的好时机,这次是对新版本进行备份。

pgbackrest backup --stanza=mystanza --type=full

移除旧集群

当一切运行良好一段时间后,您可以移除旧集群。在 pg_upgrade 运行结束时,它会创建一个小的 shell 脚本来帮助您完成这个任务。这个脚本非常简单,执行的是“rm -fr $OLDDATADIR”。最好运行那个脚本,不管它看起来多么简单,也不要冒着手指滑错的风险删除错误的数据目录!

pg_upgrade 需要多长时间?

好的,我听到您问,我们知道怎么做,但需要多长时间?如果使用推荐的 --link 模式,答案取决于您的数据目录中的文件数量。这反过来又取决于表的大小(更大的表意味着多个文件,因为 Postgres 会在磁盘上将表分解为 1GB 的文件),每个主表是否需要 TOAST 表,以及有多少索引。但是为了大致估计,表的数量就足够了。我为我的 Postgres 12 到 Postgres 16 升级运行了一些测试,这里是结果:

表的数量总升级时间
1287 秒
100012
10,00064
20,000145 (2:25)
40,000267 (4:27)
80,000507 (8:27)
100,000651 (10:51)
150,000989 (16:43)
200,0001328 (22:08)

使用一些简单的数学,我们发现对于每增加一万个表,升级过程需要额外一分钟。您的体验将根据您的操作系统和硬件而有所不同,但测试并得到一个大致数字是足够简单的。这里是我使用的:

# 在旧版本上:
psql -c 'do $$ begin for x in 1..10000 loop execute format($i$create table a%s()$i$, x); end loop; end; $$;'
psql -c 'do $$ begin for x in 1..10000 loop execute format($i$create table ab%s()$i$, x); end loop; end; $$;'
# 然后计时 pg_upgrade

在单个循环中超过 10,000 会导致问题,即使将 max_locks_per_transaction 调高,所以根据需要复制该行。您可以测试 10,000 个表的升级,然后是 20,000 个表,以生成每增加一万个表的额外时间的大致指南 - 并可以从中推断。您可以通过以下方式获取关系总数:

SELECT count(*) FROM pg_class;

根据需要进行总结,适用于您所有的数据库。您还可以通过计算当前版本数据目录的 base 目录下的所有文件来检查文件的数量:

find $OLDDATADIR/base -type f | wc -l

为下一次升级做准备

最后的事务 - 为下一次升级做准备!Postgres 每年都会发布一个新的主要版本。
因此,每年或每两年升级您的主要版本是一个好主意。
大约每三个月,一个新的次要版本就会发布。您希望立即将这些版本投入使用,因为它们只包含关键的错误修复,并且比上面的安装过程要容易得多!

这里是一个关于 Postgres 版本 14 到 17 发布时间的快速提醒:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值