警告! 如果您的数据库非常大,您将需要大量的额外磁盘空间(数据库大小的 2 倍),并且对此升级务必格外小心!
我们刚刚完成了将 Docker 镜像升级至 PostgreSQL 13 的更改。任何通过命令行重新构建 Discourse 的网站管理员都将从之前的 PostgreSQL 12 升级到 PostgreSQL 13。请注意,如果您在 5 月份 PostgreSQL 12 更新 时选择暂缓升级,您可以跳过该步骤,直接升级到 PostgreSQL 13。
如果您之前暂缓了升级,请将 app.yml 中的 PostgreSQL 模板从 templates/postgres.10.template.yml 更改为 templates/postgres.template.yml。
与任何升级一样,在执行任何操作之前,强烈建议进行备份。
更新
官方安装指南(单容器)
在下一次重新构建时,您将在末尾看到以下消息:
-------------------------------------------------------------------------------------
POSTGRES 升级完成
旧的 12 数据库存储在 /shared/postgres_data_old
要完成升级,请再次使用以下命令重新构建:
./launcher rebuild app
-------------------------------------------------------------------------------------
这意味着升级过程一切顺利!您只需要再次执行重新构建即可让站点恢复运行。
数据容器安装
如果您使用的是基于我们 discourse_docker 仓库中提供的示例配置的专用数据容器,请确保以安全且干净的方式关闭 PostgreSQL。
如今,我们有后台作业运行跨越数分钟的查询,因此关闭 Web 容器将有助于安全地关闭数据容器。
./launcher stop web_only
./launcher stop data
./launcher rebuild data
./launcher rebuild data
./launcher rebuild web_only
在对数据容器发出第一次重新构建命令之前,您可以查看 PostgreSQL 日志以确认其是否已正确关闭。
运行 tail -f shared/data/log/var-log/postgres/current,如果是正常关闭,您应该会看到以下日志:
2020-05-13 18:33:33.457 UTC [36] LOG: received smart shutdown request
2020-05-13 18:33:33.464 UTC [36] LOG: worker process: logical replication launcher (PID 52) exited with exit code 1
2020-05-13 18:33:33.465 UTC [47] LOG: shutting down
2020-05-13 18:33:33.479 UTC [36] LOG: database system is shut down
手动更新 / 空间受限环境
在尝试此操作之前,您必须备份 POSTGRES_DATA
如果您处于空间受限且无法获取更多空间的环境中,可以尝试以下方法:
./launcher stop app #(或者如果您的情况如此,请停止 web_only 和 data)
mkdir -p /var/discourse/shared/standalone/postgres_data_new
docker run --rm \
-v /var/discourse/shared/standalone/postgres_data:/var/lib/postgresql/12/data \
-v /var/discourse/shared/standalone/postgres_data_new:/var/lib/postgresql/13/data \
tianon/postgres-upgrade:12-to-13
mv /var/discourse/shared/standalone/postgres_data /var/discourse/shared/standalone/postgres_data_old
mv /var/discourse/shared/standalone/postgres_data_new /var/discourse/shared/standalone/postgres_data
./launcher rebuild app #(或者如果您的情况如此,先重建 data,再重建 web_only)
在我的测试中,此过程所需的空闲空间小于当前数据库大小的 1 倍。
推迟更新
如果您需要在下一次重新构建时推迟更新,可以通过将 app.yml 文件中的 "templates/postgres.template.yml" 更改为 "templates/postgres.12.template.yml" 来交换 PostgreSQL 模板。
这不推荐,因为一些网站管理员可能会忘记之后撤销此更改。
更新后的可选任务
优化 PostgreSQL 统计信息
更新后,新的 PostgreSQL 将没有现成的表统计信息。您可以使用以下命令生成这些统计信息:
cd /var/discourse
./launcher enter app
su postgres
psql
\connect discourse
VACUUM VERBOSE ANALYZE;
\q
exit
exit
或者使用上述命令的单行版本:
/var/discourse/launcher run app "echo 'vacuum verbose analyze;' | su postgres -c 'psql discourse'"
重建索引
此升级的主要功能是在每个实例中为最大的表 post_timings 及其索引节省大量空间。在完成成功的更新后,您需要运行一个命令来重建索引并享受其带来的好处。
cd /var/discourse
./launcher enter app
su postgres
psql
\connect discourse
REINDEX SCHEMA CONCURRENTLY public;
\q
exit
exit
如果您能在 REINDEX 前后检查 post_timings 的大小,那将是一个值得分享的有趣统计数据!
您可以使用以下查询来检查前 20 个最大的数据对象,分别在重建索引之前和之后运行:
WITH RECURSIVE pg_inherit(inhrelid, inhparent) AS
(select inhrelid, inhparent
FROM pg_inherits
UNION
SELECT child.inhrelid, parent.inhparent
FROM pg_inherit child, pg_inherits parent
WHERE child.inhparent = parent.inhrelid),
pg_inherit_short AS (SELECT * FROM pg_inherit WHERE inhparent NOT IN (SELECT inhrelid FROM pg_inherit))
SELECT table_schema
, TABLE_NAME
, row_estimate
, pg_size_pretty(total_bytes) AS total
, pg_size_pretty(index_bytes) AS INDEX
, pg_size_pretty(toast_bytes) AS toast
, pg_size_pretty(table_bytes) AS TABLE
FROM (
SELECT *, total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes
FROM (
SELECT c.oid
, nspname AS table_schema
, relname AS TABLE_NAME
, SUM(c.reltuples) OVER (partition BY parent) AS row_estimate
, SUM(pg_total_relation_size(c.oid)) OVER (partition BY parent) AS total_bytes
, SUM(pg_indexes_size(c.oid)) OVER (partition BY parent) AS index_bytes
, SUM(pg_total_relation_size(reltoastrelid)) OVER (partition BY parent) AS toast_bytes
, parent
FROM (
SELECT pg_class.oid
, reltuples
, relname
, relnamespace
, pg_class.reltoastrelid
, COALESCE(inhparent, pg_class.oid) parent
FROM pg_class
LEFT JOIN pg_inherit_short ON inhrelid = oid
WHERE relkind IN ('r', 'p')
) c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
) a
WHERE oid = parent
) a
ORDER BY total_bytes DESC LIMIT 20;
清理旧数据
对于标准安装,您可以使用以下命令删除 PG12 格式的旧数据:
cd /var/discourse
./launcher cleanup
如果您有独立的数据容器,则需要像这样删除备份副本:
rm -fr /var/discourse/shared/data/postgres_data_old/
常见问题解答 (FAQ)
源集群未干净关闭
如果您收到升级失败的上述消息,可以尝试一种更简单的方法使其恢复到更好的状态。
使用 ./launcher start app 重新启动旧容器。等待几分钟,直到它重新上线。
现在再次使用 ./launcher stop app 将其关闭。之后查看日志以确认是否为干净关闭:
tail -f shared/data/log/var-log/postgres/current
2020-05-13 18:33:33.457 UTC [36] LOG: received smart shutdown request
2020-05-13 18:33:33.464 UTC [36] LOG: worker process: logical replication launcher (PID 52) exited with exit code 1
2020-05-13 18:33:33.465 UTC [47] LOG: shutting down
2020-05-13 18:33:33.479 UTC [36] LOG: database system is shut down
如果日志看起来像上面那样,现在您可以尝试使用 ./launcher rebuild app 再次进行升级。
数据库 “postgres” 的 lc_collate 值不匹配
如果您使用非默认区域设置(locales)作为数据库,会出现此错误。据报道,需要 3 个变量才能成功。请确保您的 app.yml 文件的 env: 部分包含以下 3 行:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LANGUAGE: en_US.UTF-8
将 en_US.UTF-8 更改为您的区域设置。
每次重新构建都会再次执行升级(升级循环)
当发生这种情况时,您的升级日志将包含以下内容:
mv: cannot move '/shared/postgres_data' to '/shared/postgres_data_old/postgres_data': Directory not empty
mv: cannot move '/shared/postgres_data_new' to '/shared/postgres_data/postgres_data_new': Directory not empty
这意味着上次升级留下的文件仍然存在。在继续之前,请将它们移动到其他位置。
升级完成建议脚本 - 我需要做什么吗?
一旦升级完成,您将看到 pg_upgrade 消息的输出如下:
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 12 更新,现在该怎么办?
您可以遵循本指南顶部的标准说明,它们将无问题地将您的版本升级到 13。
如果您遵循空间受限环境的说明,请相应地调整版本号。