pgcopydb v0.18 是这个项目迄今规模最大的一次发布:从 v0.17 以来合入了 88 个提交,带来 PostgreSQL 16、17、18 兼容性,默认基于 pgoutput 的 CDC 引擎改进,正则过滤,Citus 到 Citus 迁移支持,以及 24 个 bug 修复。对正在做 PostgreSQL 版本升级、跨实例迁移、云上搬迁的团队来说,这类工具的价值很直接:当物理文件复制不可用时,尽可能快地把库搬过去,并把停机窗口压到可控范围内。
pgcopydb 解决的不是“导出导入”这么简单
传统 PostgreSQL 迁移常见路径是 pg_dump | pg_restore,它可靠、通用,但在大库场景里会遇到几个硬问题:
- 数据量大时,单线程或有限并行度会拉长迁移时间。
- 索引和约束重建可能成为后半程瓶颈。
- 业务仍在写入时,需要额外方案同步增量变更。
- 中断后如果只能重来,迁移窗口会被风险放大。
pgcopydb 的设计重点正好落在这些地方。它会并行对所有表执行 COPY,数据装载完成后并行构建索引;如果需要低停机迁移,还可以通过逻辑复制做 Change Data Capture(CDC)。它还会把迁移状态记录在本地 SQLite catalog 中,因此中断后可以从已有状态继续,而不是从头再跑。
这意味着它更像一个迁移编排器,而不是单条导出命令的包装器。
v0.18 最值得注意的变化
这次发布的几个关键词都很偏“生产迁移”:兼容性、CDC、过滤、分布式 PostgreSQL。
PostgreSQL 16、17、18 的兼容性很重要。迁移工具通常会卡在系统目录、逻辑复制协议、扩展行为这些细节上;当源库或目标库升级到新版本后,工具链必须跟上,否则真正执行迁移时才发现不可用,成本很高。
CDC 引擎默认走 pgoutput,并强调可靠性和性能改进。pgoutput 是 PostgreSQL 内置逻辑复制输出插件,在减少额外插件依赖方面有天然优势。对迁移团队来说,少一个源库扩展依赖,就少一类变更审批、安装权限和兼容性问题。
正则表达式过滤则解决了一个实际痛点:生产库里经常不是所有 schema、表、索引都该搬。有些审计表、临时归档表、历史冷数据可能要排除;有些只想迁移一组业务前缀表。比起手写长列表,正则过滤更适合复杂数据库。
Citus 到 Citus 迁移支持也值得单独看。Citus 场景下不是简单的单机 PostgreSQL:分布式表、分片、协调节点和 worker 节点都会影响迁移策略。v0.18 把这个方向纳入支持范围,说明 pgcopydb 的目标已经不止是“单实例搬家”。
可以这样实践:先做一次可恢复的迁移演练
下面示例不是替代正式迁移方案,而是一个可以改造的演练脚本。你需要把连接串、过滤规则、并发参数替换成自己的环境配置。正式生产执行前,建议先在 staging 环境完整跑一遍。
#!/usr/bin/env bash
set -euo pipefail
export PGCOPYDB_SOURCE_PGURI="postgres://app_user:source_password@source-db.example.com:5432/appdb"
export PGCOPYDB_TARGET_PGURI="postgres://app_user:target_password@target-db.example.com:5432/appdb"
WORKDIR="./pgcopydb-workdir"
mkdir -p "$WORKDIR"
# 1. 查看源库对象,确认迁移范围
pgcopydb list tables \
--source "$PGCOPYDB_SOURCE_PGURI"
# 2. 执行一次 schema + data + index 的迁移
# 参数名称可能随版本变化,请以 pgcopydb --help 和当前版本文档为准。
pgcopydb clone \
--source "$PGCOPYDB_SOURCE_PGURI" \
--target "$PGCOPYDB_TARGET_PGURI" \
--dir "$WORKDIR" \
--table-jobs 8 \
--index-jobs 8
# 3. 迁移后做基础校验:源库和目标库表行数抽样对比
psql "$PGCOPYDB_SOURCE_PGURI" -Atc "select count(*) from public.orders;"
psql "$PGCOPYDB_TARGET_PGURI" -Atc "select count(*) from public.orders;"
如果你想把迁移做得更接近生产,可以加入几个约束:
# 只迁移 public schema 中业务表,排除归档表命名
pgcopydb clone \
--source "$PGCOPYDB_SOURCE_PGURI" \
--target "$PGCOPYDB_TARGET_PGURI" \
--dir "$WORKDIR" \
--include-table 'public\.(orders|customers|payments).*' \
--exclude-table '.*_archive$' \
--table-jobs 8 \
--index-jobs 8
上面的 --include-table、--exclude-table 表达的是 v0.18 正则过滤能力的实践方式;实际参数名请以你安装版本的 pgcopydb clone --help 为准。迁移脚本里保留 --dir 这类工作目录参数很关键,因为 pgcopydb 会在本地 SQLite catalog 中跟踪状态,方便中断后恢复。
低停机迁移时,CDC 不是魔法
CDC 可以显著缩短最终切换窗口,但它不会自动消除所有迁移风险。更稳妥的做法是把迁移拆成几个阶段:
- 全量复制:并行
COPY所有目标表。 - 构建索引:数据装载后并行创建索引,避免导入阶段被索引维护拖慢。
- 增量追平:通过逻辑复制捕获全量复制期间产生的变更。
- 只读切换:短暂停写或进入维护模式,等待复制延迟归零。
- 应用切库:更新连接串、重启服务或切换流量。
- 回滚窗口:保留源库只读一段时间,确认业务指标正常。
可以用下面的 SQL 在切换前做基础观察。它不是 pgcopydb 专属命令,但适合放进迁移 checklist:
-- 在源库查看逻辑复制槽状态
select
slot_name,
plugin,
slot_type,
active,
restart_lsn,
confirmed_flush_lsn
from pg_replication_slots;
-- 查看当前 WAL 位置,辅助判断复制推进情况
select pg_current_wal_lsn();
如果源库写入很重,CDC 阶段可能追不上业务写入速度。此时要么提高迁移并发和目标库写入能力,要么提前降低写入流量,要么接受更长的只读窗口。工具能降低复杂度,但不能替代容量评估。
上生产前的检查清单
采用 pgcopydb v0.18 前,可以按下面清单逐项确认:
- 确认源库和目标库 PostgreSQL 版本,尤其是 16、17、18 的组合是否在当前工具版本覆盖范围内。
- 在 staging 环境跑完整迁移,包括全量复制、索引构建、CDC 追平和应用切库演练。
- 明确过滤规则,特别是归档表、临时表、扩展管理表和 Citus 分布式表。
- 为工作目录预留磁盘空间,并保护本地 SQLite 状态文件,避免误删导致恢复困难。
- 给最终切换准备只读窗口、回滚方案和业务指标看板。
- 使用
pgcopydb --version、pgcopydb clone --help固化实际命令,避免脚本和安装版本不一致。
pgcopydb v0.18 的价值不在于把迁移包装成“一键完成”,而在于把 PostgreSQL 大库迁移中最容易出错的环节——并行复制、索引重建、增量同步、失败恢复——变成一套更可重复的流程。对需要在新 PostgreSQL 版本和更复杂部署形态之间移动数据的团队来说,这正是迁移工具应该补上的那块工程化拼图。