29.14. 升级 #
仅当旧逻辑复制集群的所有成员都为 17.0 或更高版本时,才支持迁移逻辑复制集群。
29.14.1. 为发布端升级做准备 #
pg_upgrade 会尝试迁移逻辑槽。这有助于避免在新发布端手工定义相同的逻辑槽。仅当旧集簇版本为 17.0 或更高时才支持逻辑槽迁移。17.0 之前集簇中的逻辑槽会被静默忽略。
在开始升级发布端集簇前,请通过执行
ALTER SUBSCRIPTION ... DISABLE
临时禁用订阅。升级完成后再重新启用订阅。
pg_upgrade 升级逻辑槽有若干前置条件。若不满足,将报错。
新集簇必须将
wal_level设为replica或logical。新集簇中
max_replication_slots的配置值必须大于等于旧集簇中的槽数量。旧集簇中复制槽引用的输出插件必须安装在新 PostgreSQL 可执行文件目录中。还必须将它们包含在新集簇的 output_plugin_libraries 中;有关安全信息,请参阅该参数的文档。
旧集簇必须已将所有事务和逻辑解码消息复制到订阅端。
旧集簇中的所有槽都必须可用,即它们的 pg_replication_slots.
conflicting都为false。新集簇中不能存在任何永久逻辑槽,即所有已有逻辑槽的 pg_replication_slots.
temporary都必须设为true。
29.14.2. 为订阅端升级做准备 #
在新订阅端完成订阅端配置。pg_upgrade 会尝试迁移订阅依赖,包括 pg_subscription_rel 系统目录中的订阅表信息,以及订阅的复制源。这样新订阅端上的逻辑复制可以从旧订阅端停止的位置继续。仅当旧集簇版本为 17.0 或更高时才支持订阅依赖迁移。17.0 之前集簇中的订阅依赖会被静默忽略。
注意
升级期间不会保留提交时间戳和复制源数据。因此,即使启用了
retain_dead_tuples,升级后的订阅端在应用升级前发布端产生的变更时,也可能无法检测冲突或记录相关的提交时间戳和复制源。另外,升级之后,清理可能立即移除冲突检测所需的已删除行。这会影响那些在升级前尚未复制的变更。为确保冲突跟踪一致,用户应确保所有可能冲突的变更都在启动升级前复制到订阅端。
pg_upgrade 升级订阅也有若干前置条件。若不满足,将报错。
旧订阅端中所有订阅表应处于
i(初始化)或r(就绪)状态。可通过检查 pg_subscription_rel.srsubstate验证。旧集簇中每个订阅对应的复制源条目都必须存在。可通过检查 pg_subscription 与 pg_replication_origin 系统表确认。
新集簇中的
max_active_replication_origins配置值必须大于等于旧集簇中的订阅数量。如果存在启用了 retain_dead_tuples 的订阅,新集簇中不能存在保留的复制槽“
pg_conflict_detection”。此外,新集簇上的wal_level必须设置为replica或logical。
29.14.3. 升级逻辑复制集群 #
在升级订阅端时,发布端仍可执行写操作。这些变更会在订阅端升级完成后继续复制。
注意
逻辑复制的限制同样适用于逻辑复制集群升级。详见第 29.9 节。
发布端升级的前置条件同样适用于逻辑复制集群升级。详见第 29.14.1 节。
订阅端升级的前置条件同样适用于逻辑复制集群升级。详见第 29.14.2 节。
警告
升级逻辑复制集群需要在多个节点执行多个步骤。由于并非所有操作都是事务性的,建议按第 25.3.2 节所述先做好备份。
下列逻辑复制集群的升级步骤详见后文:
按照第 29.14.3.1 节的步骤升级双节点逻辑复制集群。
按照第 29.14.3.2 节的步骤升级级联逻辑复制集群。
按照第 29.14.3.3 节的步骤升级双节点环形逻辑复制集群。
29.14.3.1. 升级双节点逻辑复制集群的步骤 #
假设发布端位于 node1,订阅端位于 node2。订阅端 node2 上有订阅
sub1_node1_node2,用于订阅来自 node1 的变更。
在
node2上,使用ALTER SUBSCRIPTION ... DISABLE禁用所有订阅来自node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 DISABLE;
停止
node1上的发布端服务器,例如:pg_ctl -D /opt/PostgreSQL/data1 stop
使用目标新版本初始化
data1_upgraded实例。将发布端
node1升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data1" --new-datadir "/opt/PostgreSQL/postgres/18/data1_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node1发布端服务器,例如:pg_ctl -D /opt/PostgreSQL/data1_upgraded start -l logfile
停止
node2上的订阅端服务器,例如:pg_ctl -D /opt/PostgreSQL/data2 stop
使用目标新版本初始化
data2_upgraded实例。将订阅端
node2升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data2" --new-datadir "/opt/PostgreSQL/postgres/18/data2_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node2订阅端服务器,例如:pg_ctl -D /opt/PostgreSQL/data2_upgraded start -l logfile
在
node2上,创建从步骤 1 到当前期间在升级后的发布端node1新建的表,例如:/* node2 # */ CREATE TABLE distributors (did integer PRIMARY KEY, name varchar(40));
在
node2上,使用ALTER SUBSCRIPTION ... ENABLE启用所有订阅来自node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 ENABLE;
在
node2上使用ALTER SUBSCRIPTION ... REFRESH PUBLICATION刷新订阅发布,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 REFRESH PUBLICATION;
注意
上述步骤中先升级发布端,再升级订阅端。也可以采用类似步骤先升级订阅端,再升级发布端。
29.14.3.2. 升级级联逻辑复制集群的步骤 #
假设有级联逻辑复制拓扑
node1->node2->node3。其中 node2 订阅 node1 的变更,node3 订阅 node2 的变更。node2 上有订阅 sub1_node1_node2,node3 上有订阅 sub1_node2_node3。
在
node2上,使用ALTER SUBSCRIPTION ... DISABLE禁用所有订阅node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 DISABLE;
停止
node1上的服务器,例如:pg_ctl -D /opt/PostgreSQL/data1 stop
使用目标新版本初始化
data1_upgraded实例。将
node1服务器升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data1" --new-datadir "/opt/PostgreSQL/postgres/18/data1_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node1服务器,例如:pg_ctl -D /opt/PostgreSQL/data1_upgraded start -l logfile
在
node3上,使用ALTER SUBSCRIPTION ... DISABLE禁用所有订阅node2变更的订阅,例如:/* node3 # */ ALTER SUBSCRIPTION sub1_node2_node3 DISABLE;
停止
node2上的服务器,例如:pg_ctl -D /opt/PostgreSQL/data2 stop
使用目标新版本初始化
data2_upgraded实例。将
node2服务器升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data2" --new-datadir "/opt/PostgreSQL/postgres/18/data2_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node2服务器,例如:pg_ctl -D /opt/PostgreSQL/data2_upgraded start -l logfile
在
node2上,创建从步骤 1 到当前期间在升级后的发布端node1新建的表,例如:/* node2 # */ CREATE TABLE distributors (did integer PRIMARY KEY, name varchar(40));
在
node2上,使用ALTER SUBSCRIPTION ... ENABLE启用所有订阅node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 ENABLE;
在
node2上使用ALTER SUBSCRIPTION ... REFRESH PUBLICATION刷新订阅发布,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 REFRESH PUBLICATION;
停止
node3上的服务器,例如:pg_ctl -D /opt/PostgreSQL/data3 stop
使用目标新版本初始化
data3_upgraded实例。将
node3服务器升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data3" --new-datadir "/opt/PostgreSQL/postgres/18/data3_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node3服务器,例如:pg_ctl -D /opt/PostgreSQL/data3_upgraded start -l logfile
在
node3上,创建从步骤 6 到当前期间在升级后的node2新建的表,例如:/* node3 # */ CREATE TABLE distributors (did integer PRIMARY KEY, name varchar(40));
在
node3上,使用ALTER SUBSCRIPTION ... ENABLE启用所有订阅node2变更的订阅,例如:/* node3 # */ ALTER SUBSCRIPTION sub1_node2_node3 ENABLE;
在
node3上使用ALTER SUBSCRIPTION ... REFRESH PUBLICATION刷新订阅发布,例如:/* node3 # */ ALTER SUBSCRIPTION sub1_node2_node3 REFRESH PUBLICATION;
29.14.3.3. 升级双节点环形逻辑复制集群的步骤 #
假设有环形逻辑复制拓扑
node1->node2 以及
node2->node1。其中 node2 订阅 node1 的变更,node1 订阅 node2 的变更。node1 上有订阅 sub1_node2_node1,node2 上有订阅 sub1_node1_node2。
在
node2上,使用ALTER SUBSCRIPTION ... DISABLE禁用所有订阅node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 DISABLE;
停止
node1上的服务器,例如:pg_ctl -D /opt/PostgreSQL/data1 stop
使用目标新版本初始化
data1_upgraded实例。将
node1服务器升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data1" --new-datadir "/opt/PostgreSQL/postgres/18/data1_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node1服务器,例如:pg_ctl -D /opt/PostgreSQL/data1_upgraded start -l logfile
在
node2上,使用ALTER SUBSCRIPTION ... ENABLE启用所有订阅node1变更的订阅,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 ENABLE;
在
node1上,创建从步骤 1 到当前期间在node2新建的表,例如:/* node1 # */ CREATE TABLE distributors (did integer PRIMARY KEY, name varchar(40));
在
node1上使用ALTER SUBSCRIPTION ... REFRESH PUBLICATION刷新订阅发布,从node2复制初始表数据,例如:/* node1 # */ ALTER SUBSCRIPTION sub1_node2_node1 REFRESH PUBLICATION;
在
node1上,使用ALTER SUBSCRIPTION ... DISABLE禁用所有订阅node2变更的订阅,例如:/* node1 # */ ALTER SUBSCRIPTION sub1_node2_node1 DISABLE;
停止
node2上的服务器,例如:pg_ctl -D /opt/PostgreSQL/data2 stop
使用目标新版本初始化
data2_upgraded实例。将
node2服务器升级到目标新版本,例如:pg_upgrade --old-datadir "/opt/PostgreSQL/postgres/17/data2" --new-datadir "/opt/PostgreSQL/postgres/18/data2_upgraded" --old-bindir "/opt/PostgreSQL/postgres/17/bin" --new-bindir "/opt/PostgreSQL/postgres/18/bin"启动升级后的
node2服务器,例如:pg_ctl -D /opt/PostgreSQL/data2_upgraded start -l logfile
在
node1上,使用ALTER SUBSCRIPTION ... ENABLE启用所有订阅node2变更的订阅,例如:/* node1 # */ ALTER SUBSCRIPTION sub1_node2_node1 ENABLE;
在
node2上,创建从步骤 9 到当前期间在升级后的node1新建的表,例如:/* node2 # */ CREATE TABLE distributors (did integer PRIMARY KEY, name varchar(40));
在
node2上使用ALTER SUBSCRIPTION ... REFRESH PUBLICATION刷新订阅发布,从node1复制初始表数据,例如:/* node2 # */ ALTER SUBSCRIPTION sub1_node1_node2 REFRESH PUBLICATION;