max_replication_slots 决定共享内存中复制槽数组的长度,仅此而已。它不决定谁能创建槽、槽能钉住多少 WAL、废弃槽何时清理。数组在启动时一次性分配,因此不改它就得重启。默认值 10,上下文为 postmaster,取值范围 0 到 262,143(即 MAX_BACKENDS)。任何类型的槽都要求 wal_level 为 replica 或更高。9.4 到 9.6 默认值为 0;PostgreSQL 10 把默认值提到 10,目标是让全新安装无需重启即可备份并搭建备库。条目本身几乎不花钱:在 18.6 上,10,000 个条目多 3 MB,合法上限 262,143 个多 72 MB,约合每个 300 字节。条目便宜,槽不便宜:槽的真实成本是它钉住的 WAL 和压住的 xmin horizon,那是 max_slot_wal_keep_size 的职责,18 时代还有 idle_replication_slot_timeout 兜底。
凡是 pg_replication_slots 里有行的都占座,不论类型、状态或创建者:每个设置 primary_slot_name 的备库一个物理槽,每个被指定槽的 pg_receivewal 一个;发布端每个订阅一个逻辑槽,初始拷贝期间每个表同步 worker 再多一个,拷贝完成即删除,所以默认 max_sync_workers_per_subscription = 2 的订阅者在追赶期间可在发布端占三个条目。临时槽:pg_basebackup 自 10 起默认创建一个,wal_receiver_create_temp_slot 会为没有永久槽的备库创建一个,随会话消亡但会话存续期间占座。备库上 sync_replication_slots = on 时会复制主库上每个 failover 槽。第三方创建的每个槽同样占座。失效槽显示 wal_status = 'lost',不再保留任何东西,但在被删除前仍占座。截至 18,replication origins 不在列表内,18 把这项工作移交给 max_active_replication_origins。PostgreSQL 19 增加两个变化:订阅设置 retain_dead_tuples = on 时,launcher 会在订阅者上创建名为 pg_conflict_detection 的持久物理槽;REPACK ... CONCURRENTLY 则从新的 max_repack_replication_slots(默认 5)池中取用。
差一个等于没有。报错是 all replication slots are in use。把参数设为 0,pg_basebackup 会报同样的错。发布端 max_replication_slots = 1 时,订阅槽占掉唯一条目,之后每个 tablesync worker 创建槽失败、退出并被反复重启,表无限期停留在 srsubstate = 'd',而订阅本身看起来正常。备库情况更安静:18.6 上主库有三个 failover 槽、备库上限为 2 时,槽同步 worker 创建前两个后触限退出,且未持久化任何东西,备库一个槽都没同步成。反方向至少够响:把值降到磁盘上槽数以下,服务器拒绝启动,报 FATAL: too many replication slots active before shutdown。pg_upgrade 迁移逻辑槽时适用同样规则。
设置时,要数下一次故障切换后这台服务器上会有多少槽,而不是今天有多少。算完总数后放一边,在集群每个节点(含备库)上都设 50,因为它们终将成为主库,且槽同步现在就需要空间。五十个条目花 15 KB。如果已经用了三十个,就设 100。算术不是重点,重启才是。另外,max_wal_senders 至少应为该值加上物理备库数,它同样是 postmaster 上下文,应在同一次重启中一起提高。还要盯差距而非数量:当槽数接近上限时告警,任何失效数大于零都应视为待删除而非保留。