在True Engineering中,在一个项目中,需要将PostgreSQL的版本从9.6更改为11.1。
怎么了 该项目的数据库大小已经达到1.5 Tb,并且还在不断增长。 性能是系统的主要要求之一。 数据结构本身也在不断发展:添加新列,更改现有列。 新版本的Postgres已经学习了如何通过添加具有默认值的新列来有效地工作,因此无需在应用程序级别隔离自定义拐杖。 即使在新版本中,也添加了几种分区表的新方法,这在处理大量数据的情况下也非常有用。
因此,可以确定,我们正在迁移。 当然,您可以与旧版本同时发行新版本的PostgreSQL服务器,停止应用程序,使用转储/还原(或pg_upgrade)移动数据库,然后重新启动应用程序。 由于基地的规模很大,因此该解决方案不适合我们,此外,该应用程序可在战斗模式下工作,停机时间只有几分钟。
因此,我们决定尝试使用称为
pgologic的第三方插件在PostgreSQL中使用逻辑复制进行迁移。
在“试用”过程中,我们遇到了有关该过程的非常零散的文档(俄语根本不是),以及一些陷阱和不明显的细微差别。 在本文中,我们想以教程的形式介绍我们的经验。
TL; DR- 一切都结果了(并非没有拐杖,有关拐杖的文章)。
- 您可以在PostgreSQL版本中从9.4迁移到11.x,也可以从任何版本向下或向上迁移。
- 停机时间等于您的应用程序重新连接到新的数据库服务器所花费的时间(在我们的示例中,这是整个应用程序的重新启动,但显然,在野外显然是“可能的选择”)。
为什么“前额”解决方案不适合我们
正如我们已经说过的,最简单的方法是与旧版本同时提高新版本的PostgreSQL服务器,停止应用程序,使用dump / restore(或pg_upgrade)移动数据库,然后再次启动应用程序。 对于小容量的数据库,原则上来说,这是一个非常合适的选择(或者,通常情况下,当您可以选择在数据库从旧服务器到新服务器的“输液”期间“关闭”应用程序的停机时间时,无论该时间有多长,该卷都不重要)。 但是在我们的例子中,数据库在磁盘上大约需要1.5 Tb的存储空间,移动它不是几分钟,而是几个小时。 反过来,该应用程序可以在战斗模式下工作,我真的很想避免停机时间超过几分钟。
同样反对这一选择的事实是,我们使用主从复制,并且无法安全地从工作流程中关闭从服务器。 因此,要在迁移主服务器后将应用程序从旧版本的PostgreSQL切换到新版本,则有必要在启动应用程序之前准备新的从属服务器。 在创建从站之前,这要花费几个小时的停机时间(尽管比主服务器的迁移要少得多)。
因此,我们决定尝试使用称为pgologic的第三方插件在PostgreSQL中使用逻辑复制进行迁移。
一般资讯
pglogical是在PostgreSQL中使用本机逻辑解码的逻辑复制系统,并已实现为PostgreSQL扩展。 允许您使用订阅/发布模型配置选择性复制。 它不需要在数据库中创建触发器或使用任何外部实用程序进行复制。
该扩展名适用于从9.4版本开始的任何版本的PostgreSQL(自9.4起首次出现逻辑解码),并且允许您以任何方向在任何受支持的PostgreSQL版本之间迁移。
手动使用pgologic手动设置复制并不是一件容易的事,尽管从原理上讲这是完全可能的。 幸运的是,我们将使用第三方实用程序
pgrepup来自动执行配置过程。
磁盘空间备忘
由于我们计划与旧版本同时在同一服务器上提高新版本的PostgreSQL,因此主服务器和从属服务器上数据库的磁盘需求将增加一倍。 看来这是显而易见的,但是...在开始复制之前,请照顾好足够的可用空间,以免后悔漫漫的岁月。
在我们的案例中,需要修改数据库,以及在9.6和11之间“迁移”期间迁移的存储格式,而不是最新版本,因此磁盘空间必须增加2倍,而不是增加2.2倍。 赞美LVM,这可以在迁移过程中完成。
通常,请注意这一点。
在Master上安装PostgreSQL 11
注意:我们使用Oracle Linux,并且针对此发行版将完善以下所有内容。 其他Linux发行版可能需要对文件进行少许修订,但这不太重要。
旧的datadir位于
/var/lib/pgsql/9.6/data中 ,新的datadir因此位于
/ var / lib / pgsql / 11 / data中将访问设置(
pg_hba.conf )和服务器设置(
postgresql.conf )从9.6复制到11。
要在同一台机器上运行两个PostgreSQL服务器,请在
postgresql.conf 11配置配置中将端口更改为15432(端口= 15432)。
在这里,您需要仔细考虑在新版本的PostgreSQL中还需要做些什么,特别是针对您的情况,以便它从您的
postgresql.conf开始(您的应用程序最终可以使用它)。 在我们的情况下,需要在新版本中安装我们使用的PostgreSQL扩展。 这超出了本文的范围,仅使新的PostgreSQL启动,运行并完全适合您即可:)
我们在
/ var / lib / pgsql / 11 / data / pg_log /中查看 。 一切还好吗? 我们继续!
安装和配置pgrepup

细微差别:
- 作为app_owner,我们指定运行PostgreSQL服务器的用户。
- 对于数据库,指定template1 。
- 用户名和密码 -用于超级用户访问的数据。 在我们的例子中,在pg_hba.conf中为postgres用户的本地连接指定了trust方法,因此您可以指定任意密码。
配置复制
我们得到许多必须根据需要配置的参数列表的输出。
验证结果示例:


验证过程中的所有错误都需要消除。 在两台服务器的设置中,都应设置
wal_level = LOGICAL (为了使逻辑解码正常工作),这是复制引擎的必要设置(插槽数和
wal_senders )。 pgrepup实用程序的提示非常有用;大多数情况下都不会出现问题。
我们进行了pgrepup要求的所有必要设置。
在这两个
pg_hba.conf文件中,我们为将要执行复制的用户添加权限,所有权限都在pgrepup提示符下:
host replication pgrepup_replication 127.0.0.1/32 md5 host all pgrepup_replication 127.0.0.1/32 md5
添加主键
为了使复制生效,必须在所有表中定义主键。
在我们的情况下,PK并非无处不在,因此,在复制时,您需要添加它,在复制结束时,如有必要,将其删除。
没有PK的表列表将产生
pgrepup check
。 对于此列表中的所有表,您需要以适合您的任何方式添加主键。 在我们的情况下,它类似于:
ALTER TABLE %s ADD COLUMN temporary_pk BIGSERIAL NOT NULL PRIMARY KEY
pgrepup实用程序具有用于执行此操作的内置命令(
pgrepup fix
),即使使用了该命令,也可以理解,如果复制
pgrepup fix
,这些临时列将被自动删除。 但是,不幸的是,此功能在很大的基础上是如此虚幻和令人迷惑的错误,我们决定不使用它,而是手动进行此操作,因为它对我们很方便。
安装pgologic扩展
可以在
此处找到安装扩展的说明。 该扩展名必须同时安装在两台服务器上。
在两个服务器的
postgresql.conf中添加库负载:
shared_preload_libraries = 'pglogical'
安装pgl_ddl_deploy扩展
这是pgrepup用于逻辑DDL复制的帮助程序扩展。
在两个服务器的
postgresql.conf中添加库负载:
shared_preload_libraries = 'pglogical,pgl_ddl_deploy'
检查变更
现在使用
pgrepup check
您需要确保目标服务器一切正常,并且已完全消除了有关目标服务器的所有注释。
如果一切正常,则可以重新启动旧服务器。 在这里,您需要考虑应用程序对数据库服务器重启的反应,也许您应该首先停止它。
现在,在命令的输出中,所有项目都应标记为OK。
看来您可以开始迁移了,但是...
修复pgrepup错误
当前版本的pgrepup中有几个错误,这些错误使得无法移植。 拉取请求已发送,但是可惜它们被忽略了,因此您必须手动进行更正。
我们转到pgrepup安装文件夹(我们的情况是
/usr/lib/python2.7/site-packages/pgrepup/commands/ )。
做一次。 在每个
* .py文件中,在函数描述中添加缺少的
**kwargs
。 一幅图画胜过一千个单词:
在这里提交。
做两个。 在
setup.py中,我们搜索“ sh -c”这两个条目,所有多行shell命令都必须做成单行。
在这里提交。
开始迁移
pgrepup使用此命令准备两台服务器开始复制,创建用户,配置pgologic,传输数据库模式。

他说:“走吧!” 挥了挥手:

复制正在运行。 使用
pgrepup status
命令可以看到当前情况:

在这里,我们看到两个数据库已经移动并且复制正在进行中,而一个仍在移动过程中。 现在只剩下喝咖啡了,等到原始数据库的全部数据被抽出。
在此过程中,您可以更深入地了解pgrepup外观,并了解幕后情况。 对于询问者,以下是一系列查询作为起点:
SELECT * FROM pg_replication_origin_status ORDER BY remote_lsn DESC; SELECT *,pg_xlog_location_diff(s.sent_location,s.replay_location) byte_lag FROM pg_stat_replication s; SELECT query FROM pg_stat_activity WHERE application_name='subscription_copy'
喝咖啡(在撰写本文时,在测试服务器上,大约700Gb的数据迁移持续了一天左右),我们终于看到了下图:

这意味着是时候准备一个新的Slave了。
在从站上安装PostgreSQL 11
这里的一切都很简单,根据教科书,没有任何细微差别。
将访问设置(
pg_hba.conf )和服务器设置(
postgresql.conf )从9.6复制到11。在
postgresql.conf 11版本配置中,将端口更改为15432(port = 15432)
# Master SELECT *,pg_wal_lsn_diff(s.sent_lsn,s.replay_lsn) AS byte_lag FROM pg_stat_replication s; # Slave SELECT now()-pg_last_xact_replay_timestamp();
小计
完成所有这些步骤之后,我们得到了这个棘手的复制方案:

在这里,作为最后检查(最后只是很漂亮),您可以在9.6 Master数据库中执行一些UPDATE,并观察它如何复制到其他三台服务器。

将应用程序切换到新版本的PostgreSQL
到目前为止,我们的应用程序尚未怀疑有关新版本PostgreSQL的任何信息,是时候对其进行修复。 此处的选项基本上仅取决于两件事:
您是否会超过旧服务在相同端口上的新服务,
以及重新启动数据库服务器时您的应用程序是否需要重新启动。
为了娱乐,我们将回答两个问题“是”并继续。
我们停止申请。
# , , : SELECT * FROM pg_stat_activity;


我们将新版本的
postgresql.conf配置中的标准端口返回给Master和Slave。
在新的从站上,我们还将端口
恢复为recovery.conf中的标准端口。
在此过程中,有人提出过一个建议,那就是进一步更改不再活跃的旧版本上的端口:
我们将旧版本的
postgresql.conf中的非标准端口暴露给Master和Slave。
在旧的Slave上,我们还在
recovery.conf中将端口更改为非标准端口。
检查日志。
检查主服务器上的复制状态。
SELECT *,pg_wal_lsn_diff(s.sent_lsn,s.replay_lsn) AS byte_lag FROM pg_stat_replication s;
我们启动该应用程序。 我们高兴了半个小时。
最后,关于该主题的有用文献:祝你好运!