max_replication_slots 看起来只是 PostgreSQL 对复制槽数量的限制,实际上它还决定了服务器为复制槽预留的共享内存数组大小。这个数组需要容纳实例中的每一个复制槽——无论是物理槽还是逻辑槽,也无论它当前处于活跃还是非活跃状态。
因此,规划这个参数时不能只数正在工作的复制任务。遗留槽、暂时断开的订阅者以及备用槽,同样占用数组中的位置。
它限制的是全部复制槽,而不是活跃连接
复制槽用于让 PostgreSQL 记住消费者已经处理到哪个位置。常见使用者包括:
- 使用物理复制槽的流复制备库;
- 使用逻辑复制槽的订阅端或变更数据捕获系统;
- 暂时断开、但复制槽仍未删除的消费者;
- 已创建但尚未开始消费的复制槽。
这些槽都会计入 max_replication_slots。例如,实例中有 4 个活跃物理槽、3 个非活跃逻辑槽和 1 个测试遗留槽,那么已经使用了 8 个位置,而不是 4 个。
可以直接在数据库中查看容量和使用情况:
psql -X -v ON_ERROR_STOP=1 postgres <<'SQL'
SHOW max_replication_slots;
SELECT
slot_type,
active,
count(*) AS slot_count
FROM pg_replication_slots
GROUP BY slot_type, active
ORDER BY slot_type, active DESC;
SELECT
current_setting('max_replication_slots')::integer AS configured_slots,
count(*) AS used_slots,
current_setting('max_replication_slots')::integer - count(*) AS free_slots
FROM pg_replication_slots;
SQL
运行前只需把最后的 postgres 改成实际连接串或数据库名。第二条查询按类型和状态拆分复制槽,第三条查询则直接给出剩余位置。
为什么不能等槽满了再调整
max_replication_slots 控制的是共享内存结构,而不是一个可以随请求自动扩容的普通表。调整这类参数通常需要重启 PostgreSQL 才能生效,单纯重新加载配置并不能完成共享内存数组的重建。
这意味着容量耗尽时,临时修改配置未必能立即解围。更稳妥的做法是把以下需求都计入容量:
- 当前物理备库使用的槽;
- 当前逻辑订阅和 CDC 管道使用的槽;
- 计划新增的消费者;
- 滚动迁移、新旧系统并行期间的临时槽;
- 少量操作缓冲空间。
也不应为了避免告警而无限增大参数。既然它用于确定共享内存数组大小,过度配置会为根本不会使用的容量付出资源成本。目标应当是有余量,而不是无限余量。
安全修改与验证
下面是一种可以改造的操作流程。示例把上限设为 16;请先根据实际复制拓扑替换这个数字。
ALTER SYSTEM SET max_replication_slots = '16';
SELECT pg_reload_conf();
SELECT
name,
setting,
unit,
context,
pending_restart
FROM pg_settings
WHERE name = 'max_replication_slots';
重新加载配置后,可以通过 pending_restart 判断新值是否仍在等待重启。随后按部署方式重启 PostgreSQL。例如,在使用 systemd 的主机上可以执行:
sudo systemctl restart postgresql
psql -X postgres -c "SHOW max_replication_slots;"
容器、托管数据库和高可用集群应使用各自的重启或参数组流程。生产环境重启前还应确认故障转移策略、连接影响以及备库状态,不要把上述命令直接当作无停机操作。
清理非活跃槽时要关注 WAL 风险
槽位不足并不一定意味着参数太小,也可能是旧槽没有清理。可以先列出所有非活跃槽:
SELECT
slot_name,
slot_type,
database,
active,
restart_lsn
FROM pg_replication_slots
WHERE NOT active
ORDER BY slot_type, slot_name;
但“非活跃”不等于“无用”。消费者可能只是暂时断开,删除复制槽会破坏它原本依赖的恢复位置。只有在确认对应备库、订阅或 CDC 任务已经永久下线后,才应执行类似操作:
SELECT pg_drop_replication_slot('replace_with_verified_unused_slot');
复制槽还可能导致所需 WAL 被持续保留,所以容量审计不应只统计槽的个数,也要检查消费者是否持续推进以及磁盘空间是否异常增长。
上线前的检查清单
- 用
pg_replication_slots统计全部槽,而不只是active = true的槽; - 同时计算物理槽、逻辑槽、迁移期间临时槽和未来增长;
- 为突发操作保留合理余量,但避免无依据地设置超大值;
- 修改后检查
pending_restart,并安排受控重启; - 删除非活跃槽前,先确认其对应消费者已经永久退役;
- 将槽数量、活跃状态和 WAL 保留情况纳入监控。
理解 max_replication_slots 的关键,是把它看作实例启动时确定的复制槽共享内存容量,而不是“当前同时在线的复制任务数”。一旦这个模型明确,容量规划和故障排查都会简单得多。