升级到下一个 PostgreSQL 版本

2021年4月6日 | Lars Vogdt | CC-BY-SA-3.0

Upgrading to the next PostgreSQL version

上周我们升级了内部PostgreSQL集群到最新版本。

时间过得真快:我们大约在2008年安装了我们的 PostgreSQL 集群。至少,这是第一个公开 MirrorBrain 发布版本2.2的时间,这是openSUSE运行PostgreSQL安装的原因。但MirrorBrain(以及它背后的PostgreSQL集群)要老得多。所以也许说MirrorBrain从2005年开始与openSUSE一起使用是公平的……?

无论如何:如果你维护一个数据库这么长时间,你不想丢失数据。停机时间也不是一个好主意,但这就是我们拥有集群的原因,对吧?

虽然MirrorBrain数据库目前仍然是最大的一个(大小超过105GB,仅列出镜像服务器上的文件的表就有大约1.2亿条记录),但我们的新服务,如 MatrixMailman3、Gitlab、PagurelntWeblate 也不小。总共目前使用142GB。

我们已经升级了数据库多次(从版本7开始)。但这次,我们决定尝试从PostgreSQL 11直接跳到13,中间没有步骤。

那么我们如何处理PostgreSQL数据库的升级? - 通常,我们只是遵循 上游文档 - 仅调整值以适应我们的本地设置

本地设置细节

  • 我们的配置文件存储在/etc/postgresql/中 - 并链接到当前数据目录。这不仅使我们更容易进行通用备份,还将它们的文件所有权设置为root:postgres - 只能由root编辑,只能由postgres组读取(文件权限:0640)。
  • 在openSUSE上PostgreSQL的通用数据目录(/var/lib/pgsql)下方,我们为每个版本都有“data”目录:data11用于当前使用的PostgreSQL 11版本。
  • 一个符号链接/var/lib/pgsql/data指向当前活动的数据库目录(开始时为data11)

逐步操作

准备

首先让我们设置一些将在整个步骤中使用的shell变量。由于我们稍后需要这些变量作为用户‘root’和用户‘postgres’,让我们将它们放在一个可以引用(source)的文件中……

cat > /tmp/postgresql_update << EOL
export FROM_VERSION=11
export TO_VERSION=13
export DATA_BASEDIR="/var/lib/pgsql/"
export BIN_BASEDIR="/usr/lib/postgresql"
EOL
注意:你可以从当前运行的postgresl实例中获取DATA_BASEDIR:ps aufx grep ‘^postgres.* -D’

不要忘记在下面的步骤中source包含变量的文件。

安装新的RPM包

并行安装新的二进制文件(通过rpm或zypper找出你需要哪些)

source /tmp/postgresql_update
zypper in $(rpmqpack | grep "^postgresql${FROM_VERSION}" | sed -e "s|${FROM_VERSION}|${TO_VERSION}|g")

初始化新版本

现在进入数据库目录并为迁移创建一个新的子目录

su - postgres
source /tmp/postgresql_update
cd ${DATA_BASEDIR}
install -d -m 0700 -o postgres -g postgres data${TO_VERSION}
cd ${DATA_BASEDIR}/data${TO_VERSION}
${BIN_BASEDIR}/bin/initdb .

对于initdb调用的确切参数,你可以搜索上次initdb运行的shell历史记录。但我们采用上面的标准设置。

你应该最终得到一个完全独立、全新且干净的PostgreSQL数据目录。

现在开始备份新的配置文件并创建指向当前配置文件的符号链接。建议diff旧的配置文件和新的配置文件,并密切关注启动过程中的日志。最坏的情况:新服务器根本无法使用旧设置启动。但这可以在日志文件中找到。

su - postgres
source /tmp/postgresql_update
cd ${DATA_BASEDIR}/data${TO_VERSION}

for i in  pg_hba.conf pg_ident.conf postgresql.conf postgresql.auto.conf ; do 
 old $i
 ln -s /etc/postgresql/$i .; 
 # diff $i $i-$(date +"%Y%m%d")
done

即将停机:执行迁移

下一步是最终完成这项工作 - 这包括数据库的停机时间!

rcpostgresql stop

su - postgres
source /tmp/postgresql_update
pg_upgrade --link             \
 --old-bindir="${BIN_BASEDIR}${FROM_VERSION}/bin"     \
 --new-bindir="${BIN_BASEDIR}${TO_VERSION}/bin"       \
 --old-datadir="${DATA_BASEDIR}/data${FROM_VERSION}/" \
 --new-datadir="${DATA_BASEDIR}/data${TO_VERSION}/"

如果想要短时间的停机时间,–link选项非常重要

–link 将文件链接到新的集群,而不是复制文件

在我们的例子中,上述操作花费了大约20分钟。

希望你最终得到类似的结果

[...]
Upgrade Complete
----------------
Optimizer statistics are not transferred by pg_upgrade so,
once you start the new server, consider running:
    ./analyze_new_cluster.sh

Running this script will delete the old cluster's data files:
    ./delete_old_cluster.sh

切换到新的PostgreSQL版本

切换到新的数据库目录。在我们的例子中,我们更喜欢指向正确目录的符号链接

source /tmp/postgresql_update
cd ${DATA_BASEDIR}
ln -fs data${TO_VERSION} data

或者,你可以通过编辑/etc/sysconfig/postgresql中的配置来切换数据库目录

source /tmp/postgresql_update
echo "POSTGRES_DATADIR='${DATA_BASEDIR}/data${TO_VERSION}'" >> /etc/sysconfig/postgresql

(你可能想直接编辑文件并立即设置正确的值。)文件中的前缀应与${DATA_BASEDIR}变量匹配。

启动新服务器

systemctl start postgresql

清理

Postgres在pg_upgrade开始的文件夹中创建了一些脚本。你可以直接以postgres用户身份执行这些脚本,或者使用以下命令

sudo -i -u postgres
source /tmp/postgresql_update
${BIN_BASEDIR}${TO_VERSION}/bin/vacuumdb \
 --all \
 --analyze-in-stages
${BIN_BASEDIR}${TO_VERSION}/bin/reindexdb \
 --all \
 --concurrently

请注意,上述两个命令会影响服务器的性能。当你执行它们时,你的数据库可能会变得响应缓慢(甚至完全无响应)。因此,你可能希望在维护窗口期间使用它们。另一方面,一旦你执行了这些命令,你的新数据库服务器将表现得更好。所以不要等待太久。

检查一切

现在可能是检查监控、应用程序的数据库访问等的好时机。之后,你可以删除旧的数据库目录并删除旧的二进制文件以及rm /tmp/postgresql_update。

但通常,你可以将此迁移标记为完成。

分享此帖子