PostgreSQL 18 新增了 max_active_replication_origins。这个参数背后是一笔拖了十年的技术债:从 PostgreSQL 9.5 开始,复制源(replication origin)没有自己的容量参数,只能借用 max_replication_slots 的数值。到了 PostgreSQL 18,复制槽和复制源终于可以独立规划。
这不是单纯给配置文件多加一行。对于逻辑复制订阅端,它意味着调整复制槽数量时,不会再无意中改变可同时跟踪的复制源容量;升级时,也需要重新检查原来隐藏在 max_replication_slots 后面的资源假设。
复制源为什么需要单独计数
复制源用于记录从外部节点接收的数据已经复制到什么位置。逻辑复制订阅端依靠这类进度信息避免重复应用事务,并在重启后继续处理。
复制槽与复制源解决的是不同问题:
- 复制槽通常位于发布端,用来防止发送端过早删除订阅端尚未消费的 WAL。
- 复制源通常由接收或应用数据的一侧使用,用来记录来自某个源的复制进度。
- 两者可能在同一实例上出现,但数量并不存在天然的一一对应关系。
在 PostgreSQL 17 及更早版本中,这两类资源共享 max_replication_slots 给出的容量上限。假设管理员为了限制发布端资源而降低该参数,订阅端能够同时跟踪的复制源数量也可能跟着下降。这种耦合既不直观,也让容量规划依赖一个名字并不匹配的参数。
PostgreSQL 18 的 max_active_replication_origins 把两者分开:max_replication_slots 继续管理复制槽容量,新参数负责可同时活动并被跟踪的复制源容量。
这里要注意“活动”二字。不要简单地把数据库目录中存在的复制源对象数量等同于参数需求;真正需要评估的是并发使用复制源的会话、订阅应用进程以及相关复制拓扑。
升级时最容易忽略的变化
从 PostgreSQL 14~17 升级到 18 时,不能只确认旧的 max_replication_slots 被带进了新配置。应当分别回答两个问题:实例需要多少复制槽,以及需要同时跟踪多少复制源。
可以先在旧实例上采集基线:
-- 已配置的复制槽
SELECT slot_name, slot_type, active
FROM pg_replication_slots
ORDER BY slot_name;
-- 当前已加载并记录进度的复制源
SELECT local_id, external_id, remote_lsn, local_lsn
FROM pg_replication_origin_status
ORDER BY local_id;
-- 逻辑复制订阅
SELECT subname, subenabled, subslotname
FROM pg_subscription
ORDER BY subname;
pg_replication_origin_status 是一个运行状态视图,不能单独代表历史峰值。生产环境最好在业务高峰、批量同步和故障恢复期间重复采样,并结合订阅数量、并发应用方式和未来增长量设置余量。
在 PostgreSQL 18 中验证新参数
下面的 Docker 示例可以直接运行。执行前需要安装 Docker,并确认本机的 55432 端口没有被占用。示例把活动复制源上限改为 32;生产环境应替换成根据监控得到的值。
docker run --name pg18-origins \
-e POSTGRES_PASSWORD=postgres \
-p 55432:5432 \
-d postgres:18
until docker exec pg18-origins pg_isready -U postgres >/dev/null 2>&1; do
sleep 1
done
docker exec pg18-origins \
psql -U postgres -d postgres \
-c "SHOW max_active_replication_origins;"
docker exec pg18-origins \
psql -U postgres -d postgres \
-c "ALTER SYSTEM SET max_active_replication_origins = 32;"
docker restart pg18-origins
until docker exec pg18-origins pg_isready -U postgres >/dev/null 2>&1; do
sleep 1
done
docker exec pg18-origins \
psql -U postgres -d postgres \
-c "SHOW max_active_replication_origins;"
该参数需要在服务器启动时生效,因此修改后必须重启实例,普通的配置重载不够。采用配置管理时,也可以直接写入 postgresql.conf:
# PostgreSQL 18+
max_replication_slots = 20
max_active_replication_origins = 32
两个数字不必相同。一个主要作为订阅端的实例可能需要较多活动复制源,却只需要少量本地复制槽;承担多个下游发布任务的实例则可能恰好相反。
不要靠一次报错决定容量
配置过低会让新的复制活动无法取得所需状态,影响订阅应用或自定义逻辑复制流程。配置过高则会为共享内存相关结构预留更多容量。具体内存成本应以 PostgreSQL 18 的文档、实际版本和监控结果为准,不应把参数无上限地调大。
上线前可以使用这份检查清单:
- 盘点
pg_replication_slots、pg_subscription和pg_replication_origin_status。 - 按峰值并发而不是仅按当前对象数估算活动复制源。
- 为故障恢复、临时订阅和拓扑扩容保留明确余量。
- 把
max_replication_slots与max_active_replication_origins分别纳入配置管理。 - 在升级预演中执行
SHOW max_active_replication_origins,并验证订阅重启和追赶过程。 - 修改参数后安排实例重启,而不是只执行配置重载。
max_active_replication_origins 的价值在于让配置名称重新对应实际资源。PostgreSQL 18 之后,复制槽和复制源应被当作两个独立容量维度管理;升级工作的重点,也应从“保留旧参数值”转向“重新验证复制拓扑的真实需求”。