必须先修改max_replication_slots参数并重启实例,否则pg_create_physical_replication_slot()会报错“replication slots can only be used if max_replication_slots > 0”;该参数需≥计划备库数,且wal_level和hot_standby也须正确配置。

必须先改 max_replication_slots 参数,否则创建直接报错
PostgreSQL 默认禁用复制槽功能,哪怕你执行 pg_create_physical_replication_slot() 也会立刻返回错误:ERROR: 55000: replication slots can only be used if max_replication_slots > 0。这不是权限或语法问题,是硬性开关未打开。
修改方式很简单,但在 postgresql.conf 中加一行:
max_replication_slots = 2
注意:这个值要 ≥ 你计划配置的备库数量(一主多备时尤其关键),改完必须重启 PostgreSQL 实例,SELECT pg_reload_conf() 不生效。
顺带确认另外两个基础参数也已启用:
-
wal_level = replica(物理复制)或logical(逻辑复制) -
hot_standby = on(备库需支持只读查询)
创建物理复制槽要用 pg_create_physical_replication_slot()
连接到主库(非备库),用有 REPLICATION 权限的用户执行:
SELECT * FROM pg_create_physical_replication_slot('my_slot');返回结果中 slot_name 和 xlog_position(现为 restart_lsn)字段有意义,其他字段可为空。此时槽已创建但尚未被使用 —— 它只是个“占位符”,主库不会立刻开始保留 WAL。
常见误操作:
- 在备库上执行创建命令 → 报错
ERROR: cannot execute CREATE_REPLICATION_SLOT in a database that is not the primary - 名字含大写字母或特殊符号 → 只允许小写字母、数字、下划线
- 重复创建同名槽 → 报错
ERROR: replication slot "xxx" already exists,不是覆盖而是拒绝
从库必须显式声明 primary_slot_name 才能激活槽
仅在主库建槽没用。备库得知道自己该用哪个槽,否则主库仍按默认策略清理 WAL —— 槽处于 inactive 状态,pg_replication_slots.active 为 f,restart_lsn 停滞不动。
在备库的 recovery.conf(PG 12+ 是 standby.signal + postgresql.auto.conf)中添加:
primary_slot_name = 'my_slot'
然后重启备库。启动后检查:
SELECT slot_name, active, restart_lsn FROM pg_replication_slots WHERE slot_name = 'my_slot';
若 active 为 t,且 restart_lsn 随时间缓慢推进,说明槽已被激活,主库开始按该槽的进度保留 WAL。
关键点:
- 一个槽只能被一个备库使用;一主多备必须建多个槽,每个备库配唯一
primary_slot_name - 如果备库连不上主库,槽仍保持 active,但
restart_lsn停止更新 —— 这就是 WAL 积压的起点 -
pg_stat_replication的sent_location和write_location应接近restart_lsn,差距过大说明同步延迟严重
不监控 pg_wal 目录大小,迟早磁盘写满
复制槽的核心代价是 WAL 不再受 max_wal_size 或 wal_keep_segments 控制,主库会一直保留从 restart_lsn 开始的所有 WAL 文件,直到备库追上。
这意味着:备库宕机 3 天,WAL 就可能涨满整个 pg_wal 分区。线上环境必须做两件事:
- 把
pg_wal放在独立大容量磁盘上,不要和数据目录混用 - 定期执行监控 SQL:
SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag_size FROM pg_replication_slots;
,对lag_size设置告警阈值(比如 > 10GB) - 发现长期 inactive 或无用槽,立刻删掉:
SELECT pg_drop_replication_slot('my_slot');,删除前务必确认没有备库还在用它
最易被忽略的一点:复制槽本身不解决网络抖动或大事务阻塞问题,它只解决“WAL 被提前删”这一个环节。如果备库因长事务卡住,restart_lsn 不前进,WAL 就持续堆积 —— 这时候得查 pg_stat_activity 找出阻塞源,而不是怪槽没配好。

















