亚马逊AWS官方博客
使用 Pub/Sub 逻辑复制实现 Aurora PostgreSQL 大版本近零停机升级
摘要:Amazon Aurora PostgreSQL 大版本升级有多种方案可供选择。本文聚焦于手动蓝绿部署(Clone + 原生 Pub/Sub)方案,深入介绍如何利用 PostgreSQL 原生逻辑复制能力,以分钟级停机时间完成 Aurora PostgreSQL 大版本升级。
文中以 PostgreSQL 13 升级至 PostgreSQL 17 为例进行说明,相同步骤适用于其他 Aurora PostgreSQL 大版本升级组合(如 PG11→PG15、PG14→PG17 等)。本文还重点讲解针对高写入量表的并行订阅任务拆分技巧,以及完整的回滚保障机制。
一、概述与方案选型
说明:本文以 PG13 升级至 PG17 为例。命令中出现的版本号(如 17.7)请替换为实际目标版本,其余步骤不变。
1.1 为什么选择手动 Pub/Sub 方案
Aurora PostgreSQL 大版本升级有以下几类主流方案:
| 方案 | 停机时间 | 适用场景 | 限制条件 | |
| 1 | 原地升级 | 分钟到小时级 | 可接受较长停机 | 升级后不可回滚中断时间相对较长并且和数据库大小有关17版本以下slot需要重建 |
| 2 | AWS 蓝绿部署 | 通常 < 1 分钟 | 标准场景一键操作 | PG16 以下单线程 apply,高写入量时 lag 难以追平需要重建slot存在一些其他限制条件,具体见官方文档链接。 |
| 3 | 手动蓝绿DMS | 分钟级 | 支持部分表迁移同步,但需要数据校验 | 需要应用和下游CDC订阅修改连接地址 |
| 4 | Clone + 原生 Pub/Sub | 分钟级 | 需要使用原生的逻辑复制写负载高、需要表级进行任务拆分 | 需要应用和下游CDC订阅修改连接地址 |
| 5 | 业务双写 | 秒级 | 停机时间要求极短、无主键/唯一键限制 | 需要业务改造开源 proxy 方案难以保证数据一致性 |
手动 Pub/Sub 方案的核心优势
- 最小化停机时间,通过 Aurora Clone 快速创建新版本集群(写时复制,不需要物理拷贝数据),业务在源集群持续运行,逻辑复制持续追赶增量变更,切换窗口可压缩到分钟级。
- 使用 PostgreSQL 原生逻辑复制(Publication/Subscription),数据一致性更有保障,无需引入 DMS、外部 CDC 工具等额外组件,减少架构复杂性和故障面。
- 精细控制与灵活度,支持按表或表组拆分为多个独立订阅,每个订阅独立追赶延迟,高写入量场景下可并行消化积压;可自由选择目标大版本(跨多个大版本升级),不受 AWS 蓝绿部署支持的版本路径限制;升级节奏完全自主掌控,随时暂停、恢复、回退。
- 全程可观测,通过
pg_replication_slots、pg_stat_subscription、pg_stat_replication实时监控复制进度和延迟,切换前可明确确认数据已完全同步,而非依赖黑盒式的”就绪”状态。 - 安全回退,切换前源集群完整保留,任何阶段发现问题可立即回退到源集群,无数据丢失风险,相比就地升级(in-place upgrade),风险显著降低。
- 成本优势,Aurora Clone 基于存储层写时复制,初始不产生额外存储费用,仅在新集群产生写入后按增量计费,升级验证期间只需为新集群的计算实例付费。
1.2 整体架构
[图1] |
二、升级前置准备
2.1 参数组准备
在源集群上,逻辑复制需要以下参数。需要注意修改 rds.logical_replication 后需要重启实例:
对应 AWS CLI 修改方式:
2.2 表结构检查
原生逻辑复制要求复制的表有主键或唯一键(或显式设置 REPLICA IDENTITY FULL)。可以通过以下 SQL 提前识别无主键表:
对于只有 INSERT 操作的表(如日志流水表),无主键不影响复制。对于有 UPDATE/DELETE 的表,建议提前补加主键,或设置:
2.3 兼容性验证
在 Clone 集群完成大版本升级后、执行 Cutover 前,运行升级验证脚本(pg_version_upgrade_validation.sh),涵盖以下检查:
| 检查项 | 内容 | |
| 1 | 索引健康度 | 无效索引、Collation 版本不匹配 |
| 2 | B-tree 物理一致性 | 通过 amcheck 扩展(可选) |
| 3 | 函数/触发器兼容性 | 跨版本破坏性变更扫描(如 extract、power) |
| 4 | Public schema 权限 | PG15+ 默认权限变更检查 |
| 5 | GUC 参数 | 废弃存储参数、移除配置项 |
| 6 | 扩展版本 | 各 database 中 extension 版本一致性 |
三、手动 Pub/Sub 升级全流程
整个流程由三个脚本协作完成:
| 脚本 | 职责 | |
| 1 | aurora_clone_replication_final.sh |
Step 1:建 Publication/Replication Slot,克隆,升级,建 Subscription |
| 2 | pg_version_upgrade_validation.sh |
Step 2:升级兼容性验证 |
| 3 | aurora_cutover.sh |
Step 3:停写、追赶、切换流量 |
3.1 Step 1:创建复制槽与发布
在源集群上,为每个复制任务分别创建 Publication 和 Replication Slot,这一步必须在 Clone 之前完成,使 WAL 保留从此时刻起的所有变更:
关键设计:复制槽在 Clone 之前创建,确保 Clone 时刻之后的所有 WAL 都被保留。Clone 完成后需要将槽位推进到 Clone 的 LSN,避免在 Clone 已有数据上重复 apply。
对应脚本自动执行:
3.2 Step 2:Aurora Fast Clone
通过 Aurora PITR Clone 创建克隆集群。Aurora Fast Clone 是写时复制(Copy-on-Write)机制,克隆操作本身瞬时完成,不拷贝数据,对源集群无影响:
Clone 完成后,记录 Clone 集群的起始 LSN(用于后续对齐订阅位点):
3.3 Step 3:对 Clone 进行原地大版本升级
Clone 集群从源版本原地升级到目标版本。此操作仅影响 Clone,生产集群不受任何影响:
升级完成后,清理 Clone 集群内由 Clone 带入的旧复制槽(Clone 会带入源的 slot,不清理会阻塞 WAL 清理):
升级扩展插件:
3.4 Step 4:推进 Slot 位点 + 创建订阅
这是手动 Pub/Sub 方案的核心关键步骤:将源集群上的 Replication Slot 推进到Step 2获取的Clone LSN,确保订阅从 Clone 数据一致的时间点开始 apply,避免重复数据冲突:
3.4.1 为什么要推进 Slot?
Slot 在 Clone 之前创建,其 restart_lsn 早于 Clone 时刻。如果不推进,订阅会尝试 apply Clone 已包含的数据,导致主键冲突报错。推进到 Clone 的 aurora_volume_logical_start_lsn() 后,WAL replay 从 Clone 数据一致点开始,两侧数据对齐。
随后在 Clone 集群(目标版本)上创建订阅,指向源集群的 Publication 和 Slot:
3.5 Step 5:监控复制延迟
在 Clone 追赶期间,通过以下 SQL 实时观测各任务的复制 lag:
3.6 Step 6:升级验证
在 Clone 集群上运行兼容性验证脚本,确认无问题后再执行 Cutover:
3.7 Step 7:Cutover 切流
验证通过、选定维护窗口后,执行 Cutover:
脚本依次执行以下步骤:
(1)源集群设为只读,阻止新写入
(2)等待复制 lag 归零
(3)停止所有订阅
(4)重置 Sequence 避免主键冲突
在停写后、切流前,在 Clone 集群上将各序列的 nextval 对齐到当前最大值 + 1,防止切流后新数据与 Clone 追赶期间已写入数据发生主键冲突:
(5)更新 DNS / Route 53 CNAME 指向 Clone 集群,恢复业务
(6)验证 Clone 集群可正常写入后,完成 Cutover。
四、高写入负载场景:并行订阅任务拆分
4.1 问题:单订阅任务的吞吐瓶颈
PostgreSQL 逻辑复制的默认模式是每个订阅单线程 apply。当某张表(如区块链流水表)写入量极大时,单订阅会形成瓶颈:一张高写入量表的积压会阻塞所有其他表的同步进度,导致整体 lag 无法追平。
4.2 方案:按表组拆分多个独立任务
将表按写入量分组,每组创建独立的 Publication、Slot 和 Subscription,各组互不阻塞,并发 apply:
[图2] |
每个任务的 lag 独立可控,不再互相影响。
4.3 使用方式
通过 --table-pattern 参数以逗号分隔不同任务:
| A | B | C | |
| 1 | % | 通配符,匹配任意字符 | public.s% 匹配所有 s 开头的表 |
| 2 | , | 任务分隔符,每段创建独立 Pub/Sub | a%,b% → 2 个任务 |
| 3 | + | 合并符,多个模式共享一个任务 | a%+b% → 1 个任务含两组表 |
| 4 | – | 排除模式 | a%-ab% → 在a开头的表的基础上排除ab开头的表 |
使用 + 合并多个前缀到同一任务(减少 slot 数量):
4.4 WAL / LSN 并行追赶示意图
[图3] |
所有任务 lag = 0 bytes 后,才能执行 Cutover。监控各任务 lag:
五、回滚方案
手动 Pub/Sub 方案提供三个时间窗口的回滚能力:
5.1 Cutover 前(零成本回滚)
源集群全程正常运行,不做任何改变。如发现问题:
- 直接停止脚本,删除 Clone 集群即可
- 无任何业务影响
5.2 Cutover 后、Cleanup 前(DNS 回切)
源集群在 Cutover 时被设为只读并保留,回滚步骤:
ℹ️ 注意:
Cutover 后到 DNS 回切之间,有少量写入已发生在目标版本 Clone 集群上。这部分数据不会自动同步回源集群。对于关键场景,建议在 Cutover 后立即搭建目标版本 → 源版本的反向逻辑复制链路(参考 5.3)。
5.3 切流后反向复制(高可用回滚保障)
对于核心生产数据库,建议在切流同时建立反向复制链路,保障回滚窗口内数据可恢复:
(1)在目标版本 Clone 集群上创建反向复制槽(在 Cutover 停写、DNS 切换前执行)
(2)在源集群上预创建反向订阅(同样在 Cutover 停写前执行,先禁用)
Cutover 完成后源集群会被设为只读,DDL 无法执行。因此 CREATE SUBSCRIPTION 必须在 Cutover 停写之前、源集群还可写时执行,通过 enabled = false 先不激活,等 DNS 切换完成后再手动开启:
(3)Cutover 完成、DNS 指向目标版本集群后,启动反向订阅
反向链路启动后,源集群持续接收目标版本的增量变更,确保任何时刻回切都有完整数据。
5.4 Cleanup 后(快照恢复)
运行 aurora_cleanup_replication.sh 清理复制对象后,复制链路不再可用。此时回滚需要通过 Aurora 自动备份的快照恢复,会有数据丢失风险。建议在业务稳定运行 1-2 天后再执行 Cleanup。
六、注意事项
6.1 无主键表的处理
原生逻辑复制要求 UPDATE/DELETE 操作的表有主键或唯一键。对于只有 INSERT 的表(如日志、流水表),无主键不影响正常复制。建议升级前通过检查脚本提前识别并处理无主键表。
6.2 外键与 Trigger 的处理
PostgreSQL 逻辑复制的 apply worker 进程默认已以 session_replication_role = replica 身份运行,外键检查和非 ALWAYS 类型的 Trigger 本身就是跳过的,无需额外设置。
如果追赶阶段出现外键约束违反报错,根本原因通常是子表数据先于父表数据到达(事务跨 WAL 段被拆分投递)。处理方式:
- 有外键关联的父子表必须放在同一个订阅任务中(使用
+语法合并)。若父子表被拆分到不同任务,各任务并发 apply 时无法保证事务顺序,子表记录可能先于父表到达,触发外键约束违反。检查pg_subscription_rel中报错的表,确认父子表是否在同一个订阅任务中,若不是则合并即可解决。 - 若确实需要临时禁用约束以手动修复数据,应在 Clone 集群上以管理员用户身份执行
ALTER TABLE ... DISABLE TRIGGER ALL或SET CONSTRAINTS ALL DEFERRED,而不是SET session_replication_role(该命令只影响当前 psql 会话,对后台 worker 无效)。
6.3 LOB / TOAST 大字段
包含大字段(text、bytea、json 等)的表,逻辑复制会将完整行内容通过 WAL 传输,对 WAL 大小和网络带宽有较大影响。可通过拆分任务(将含大字段的表单独成一个任务)来控制影响范围。
6.4 升级后必做:全库 ANALYZE
大版本升级后,查询优化器的统计信息基于旧版本收集,可能导致执行计划偏差。切流后在新集群上执行:
6.5 WAL 膨胀风险
Replication Slot 会保留其 restart_lsn 之后的所有 WAL,防止被清理。如果 Clone 追赶速度慢,源集群的 WAL 体积可能持续增长。建议监控源集群存储使用率,必要时调整 max_slot_wal_keep_size 限制最大保留量(但设置过小会导致 slot 失效):
6.6 升级后的 Extension 版本对齐
大版本升级不会自动升级 Extension 版本,需手动执行 ALTER EXTENSION ... UPDATE。建议在切流前在 Clone 集群完成所有 Extension 升级并验证功能正常。
6.7 并行任务数量与 Slot 限制
每个并行任务占用一个 max_replication_slots 和一个 max_wal_senders。规划任务数量时,确保源集群参数留有足够余量:
七、相关内容推荐
Aurora-PostgreSQL-PubSub 脚本与工具(本文参考实现)
aurora_clone_replication_final.sh— Clone + Pub/Sub 自动化脚本pg_version_upgrade_validation.sh— 升级兼容性验证脚本aurora_cutover.sh— 停写、追赶、切流自动化脚本aurora_cleanup_replication.sh— 切流后复制对象清理脚本
官方文档
- Amazon Aurora 蓝绿部署
- Aurora PostgreSQL 逻辑复制
- PostgreSQL Publication/Subscription 文档
- Aurora Fast Clone
- Aurora PostgreSQL Release Notes
相关博客
相关产品
- Amazon Aurora — 云原生 PostgreSQL/MySQL 托管数据库
- Amazon RDS — 全托管关系数据库服务
- Amazon CloudWatch — 监控与可观测性
- AWS Secrets Manager — 密钥与凭证管理
*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。
本篇作者
AWS 架构师中心:云端创新的引领者探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用 |
![]() |




