PostgreSQL 复制槽耗尽问题排查与修复:从配置到监控

主题: postgres-replication-slot-exhaustion-fix更新于: 2026/7/16作者:AgentFactory 技术团队

快速答案

  • 核心结论:PostgreSQL 复制槽(Replication Slot)是确保备库不丢失 WAL 日志的关键机制,但若备库宕机或网络中断,主库的 WAL 日志会持续堆积,最终导致磁盘写满(即“复制槽耗尽”问题)。
  • 首要检查:执行 SELECT slot_name, active, restart_lsn FROM pg_replication_slots; 确认复制槽是否活跃;检查主库磁盘使用率(df -h)和 WAL 目录大小(du -sh $PGDATA/pg_wal)。
  • 最小修复命令:若备库永久下线,立即执行 SELECT pg_drop_replication_slot('slot_name'); 删除对应复制槽以释放 WAL 空间;若备库临时故障,设置 max_slot_wal_keep_size(PostgreSQL 13+)限制 WAL 保留量。
  • 适用环境:PostgreSQL 9.4+ 流复制生产环境,尤其金融、电商等对数据零丢失要求高的场景;不适用于单机测试或小型应用。

它解决什么问题 / 适用场景

PostgreSQL 复制槽(Replication Slot)是流复制中自动管理 WAL 日志保留的机制。它的核心作用是:确保主库在备库尚未消费完 WAL 日志之前,不会回收这些日志。这解决了传统 wal_keep_segments 手动配置的盲目性——既可能浪费磁盘(设置过大),又可能导致备库因 WAL 被回收而无法同步(设置过小)。

适用场景

  • 高可用流复制:主库需要保证所有备库都成功接收 WAL 后才进行日志回收,防止备库滞后导致数据丢失。
  • 逻辑复制 / CDC:使用逻辑复制槽进行数据分发或变更数据捕获(Change Data Capture),同样依赖复制槽保留 WAL。
  • 零数据丢失要求:金融、电商、SaaS 等业务,不允许因备库落后而丢失事务。

不适用场景

  • 单机部署或测试环境:无需复制槽,可关闭 wal_level = replica 以节省资源。
  • 小型应用:对 WAL 管理不敏感,使用 wal_keep_segments 即可满足需求。

核心配置 / 参数说明

复制槽的配置主要涉及主库和备库两端的参数。以下为关键参数及其说明:

参数名必需说明默认值建议值
primary_conninfo备库连接主库的连接字符串,包含 host、port、user 等'host=主库IP port=5432 user=repl password=xxx'
primary_slot_name备库使用的复制槽名称,必须与主库已创建的槽名一致'replicationServer1'
trigger_file触发备库提升为主库的文件路径(用于手动故障切换)'/tmp/promote_trigger'
max_slot_wal_keep_size单个复制槽最大允许保留的 WAL 大小(PostgreSQL 13+)-1(无限制)根据磁盘空间设置,如 '1GB'
wal_level必须设为 replicalogical 以启用复制槽replicareplica(物理复制)或 logical(逻辑复制)

配置步骤

  1. 主库创建复制槽

    SQL
    SELECT pg_create_physical_replication_slot('replicationServer1');
    
  2. 备库配置 recovery.conf(PostgreSQL 12 之前)或 postgresql.conf(PostgreSQL 12+)

    INI
    primary_conninfo = 'host=192.168.1.100 port=5432 user=repl password=secret'
    primary_slot_name = 'replicationServer1'
    trigger_file = '/tmp/promote_trigger'
    
  3. 重启备库

    BASH
    pg_ctl restart -D /var/lib/postgresql/data
    

与同类方案对比

对比维度复制槽方案wal_keep_segments 手动配置pgBackRest 等备份工具
核心目标自动保留备库未消费的 WAL手动指定保留的 WAL 段数全量/增量备份与恢复
WAL 管理方式自动,基于备库消费进度手动,固定段数不管理在线 WAL,仅备份归档
资源浪费风险低(仅保留必要 WAL)高(可能保留过多或过少)不适用
备库滞后保护强(防止 WAL 被回收)弱(若备库滞后超过段数则断连)不适用
故障切换后处理需手动清理或使用 Patroni无需额外处理需重建备库
与 Patroni 集成底层机制,Patroni 可自动管理不推荐,Patroni 推荐复制槽独立工具

结论:复制槽是流复制中 WAL 管理的最佳实践,尤其适合需要高可用和数据一致性的生产环境。Patroni 等集群管理工具会在此基础上提供自动故障转移和复制槽清理。

常见报错与排查

以下为复制槽相关的最常见错误及其解决方案:

错误 1:复制槽已存在

ERROR:  replication slot "slot_name" already exists

解决方案:删除现有槽后重新创建,或使用不同的槽名称。

SQL
SELECT pg_drop_replication_slot('slot_name');
SELECT pg_create_physical_replication_slot('new_slot_name');

错误 2:主库连接失败

FATAL:  could not connect to the primary server: could not connect to server: Connection refused

排查步骤

  1. 检查主库是否运行:systemctl status postgresql
  2. 检查监听地址:grep listen_addresses /etc/postgresql/*/main/postgresql.conf
  3. 检查 pg_hba.conf 是否允许复制连接:
    host replication repl 备库IP/32 md5
    
  4. 检查防火墙:ufw statusiptables -L

错误 3:备库找不到复制槽

LOG:  started streaming WAL from primary at ... but replication slot "slot_name" does not exist

解决方案:在主库上创建对应的复制槽。

SQL
SELECT pg_create_physical_replication_slot('slot_name');

错误 4:复制槽非活跃但 WAL 被保留

WARNING:  wal_keep_segments is 0 but ... replication slot "slot_name" is inactive

排查步骤

  1. 检查备库是否运行:pg_isready -h 备库IP
  2. 检查网络连通性:ping 备库IP
  3. 如果备库永久下线,手动删除复制槽:
    SQL
    SELECT pg_drop_replication_slot('slot_name');
    

常见问题 FAQ

Q: 如果备库宕机了,主库的复制槽会怎样?如何防止磁盘被写满?

A: 备库宕机后,复制槽保持打开状态,主库会继续保留所有未被该备库消费的 WAL 日志,导致 WAL 持续堆积,最终可能占满磁盘。防止措施:

  1. 设置监控告警:监控 pg_replication_slots 视图中的 active 列和 WAL 目录大小。
  2. 限制 WAL 保留量(PostgreSQL 13+):设置 max_slot_wal_keep_size = '1GB'
  3. 手动清理:如果备库无法恢复,执行:
    SQL
    SELECT pg_drop_replication_slot('slot_name');
    

Q: 逻辑复制槽和物理复制槽在故障切换(Failover)时有什么区别?

A:

  • 物理复制槽:故障切换后,原主库上的物理复制槽不会自动迁移到新主库。新主库需要重新创建复制槽,原主库上的槽需要手动清理。
  • 逻辑复制槽:故障切换后,逻辑复制槽通常不会自动迁移,导致订阅端无法继续接收变更。解决方案包括使用 pg_failover_slots 扩展(支持逻辑复制槽在故障切换后迁移),或在切换后手动重建订阅。

Q: 如何监控复制槽的健康状态和 WAL 堆积情况?

A: 通过以下 SQL 查询监控:

  1. 查看所有复制槽状态
    SQL
    SELECT slot_name, slot_type, active, restart_lsn, confirmed_flush_lsn 
    FROM pg_replication_slots;
    
  2. 查看 WAL 堆积量(字节)
    SQL
    SELECT slot_name, 
           pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS wal_accumulated 
    FROM pg_replication_slots 
    WHERE slot_type = 'physical';
    
  3. 设置告警:当 wal_accumulated 超过阈值(如 1GB)时触发告警。建议使用 Prometheus + postgres_exporter 或 Zabbix 等监控工具自动化此过程。

生产环境实践与注意事项

生产部署限制

  1. 磁盘空间耗尽风险:复制槽阻止 WAL 回收,备库长时间断开会导致 WAL 堆积。务必设置 max_slot_wal_keep_size 和磁盘监控。
  2. 槽名称唯一性:复制槽名称在集群内必须唯一,创建后不能重命名。
  3. 故障切换后槽不迁移:原主库上的物理复制槽不会自动迁移到新主库,需手动清理或使用 Patroni 等工具管理。
  4. 逻辑复制槽故障切换:需要额外处理,建议使用 pg_failover_slots 扩展或手动重建订阅。

安全性建议

  1. 最小权限原则:复制用户仅授予 REPLICATION 权限,避免使用超级用户。
    SQL
    CREATE USER repl WITH REPLICATION PASSWORD 'strong_password';
    
  2. 加密连接:在 pg_hba.conf 中强制使用 SSL:
    hostssl replication repl 备库IP/32 md5
    
  3. 监控与告警:监控复制槽活跃状态和 WAL 堆积量,设置告警阈值。
  4. 定期清理:定期检查并删除不再使用的复制槽:
    SQL
    SELECT pg_drop_replication_slot('obsolete_slot');
    

相关深度解决方案

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 PostgreSQL 死锁检测与自动恢复:MCP 工具实战配置与排坑

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 PostgreSQL 复制延迟排查与修复:从诊断到应急操作