升级到下一个 PostgreSQL 版本
2021年4月6日 | Lars Vogdt | CC-BY-SA-3.0
上周我们升级了内部PostgreSQL集群到最新版本。
时间过得真快:我们大约在2008年安装了我们的 PostgreSQL 集群。至少,这是第一个公开 MirrorBrain 发布版本2.2的时间,这是openSUSE运行PostgreSQL安装的原因。但MirrorBrain(以及它背后的PostgreSQL集群)要老得多。所以也许说MirrorBrain从2005年开始与openSUSE一起使用是公平的……?
无论如何:如果你维护一个数据库这么长时间,你不想丢失数据。停机时间也不是一个好主意,但这就是我们拥有集群的原因,对吧?
虽然MirrorBrain数据库目前仍然是最大的一个(大小超过105GB,仅列出镜像服务器上的文件的表就有大约1.2亿条记录),但我们的新服务,如 Matrix、Mailman3、Gitlab、Pagure、lnt 或 Weblate 也不小。总共目前使用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。
但通常,你可以将此迁移标记为完成。