PostgreSQL 复制槽是什么?为什么复制槽可能导致磁盘被 WAL 撑满?
简化版
复制槽用于让 PostgreSQL 保留下游还没消费的 WAL,保证物理或逻辑复制客户端断开后还能继续追上。风险是下游长期不消费时,WAL 不能被清理,磁盘可能被撑满。
详细版
没有复制槽时,下游断开太久,主库可能已经清理旧 WAL,导致下游无法继续复制。复制槽记录消费位置,主库会保留该位置之后的 WAL。
这提高了复制可靠性,但也把下游故障转化成主库磁盘风险。逻辑订阅、CDC、Debezium、备库都可能使用复制槽。
治理重点是监控槽的延迟、WAL 保留量、磁盘空间和失效槽,设置合理告警,停用不用的槽。
完整版教学
一、复制槽解决什么问题
复制依赖 WAL。下游消费 WAL 才能追上主库。如果下游断开很久,而主库已经把旧 WAL 清理掉,下游就会断档。
复制槽像一个书签,告诉主库“这个消费者还读到这里,请不要删后面的日志”。
WAL: 100 --- 200 --- 300 --- 400
slot confirmed at 200
主库必须保留 200 之后的 WAL
二、为什么会撑满磁盘
复制槽保护的是下游消费能力,而不是主库磁盘。如果下游停止消费,槽的位置不前进,主库就必须持续保留 WAL。
假设主库每小时产生 20GB WAL,下游故障 10 小时,可能额外保留 200GB WAL。如果磁盘只剩 100GB,就会出现严重风险。
这类事故很典型:真正坏的是下游 CDC 或订阅程序,但最后报警的是主库磁盘。
三、物理槽和逻辑槽
物理复制槽通常服务于流复制备库,保留物理 WAL。逻辑复制槽用于逻辑解码,把 WAL 转成表级变更事件。
| 类型 | 常见用途 | 风险 |
|---|---|---|
| 物理槽 | 备库复制 | 备库断开导致 WAL 堆积 |
| 逻辑槽 | CDC、逻辑订阅 | 消费程序慢导致 WAL 堆积 |
| 临时槽 | 临时复制任务 | 连接断开自动清理 |
逻辑槽在数据同步系统里很常见,也更容易因为消费程序异常被忽视。
四、如何监控复制槽
可以查看 pg_replication_slots。关注槽是否 active、restart_lsn、confirmed_flush_lsn 以及与当前 WAL 的差距。
SELECT slot_name, slot_type, active, restart_lsn, confirmed_flush_lsn
FROM pg_replication_slots;
还要结合磁盘空间和 WAL 目录大小监控。只看槽 active 不够,因为慢消费的 active 槽也可能大量滞后。
五、如何治理和预防
不用的槽要删除,不能让历史测试槽留在线上。下游故障时,要尽快恢复消费或评估是否丢弃槽重新全量同步。
新版本 PostgreSQL 可以通过参数限制 slot 保留 WAL 的上限,降低磁盘被无限撑满风险。但设置上限也意味着下游可能复制失败,需要重新初始化。
这就是取舍:要么主库为下游保留更多恢复能力,要么保护主库磁盘优先。
六、常见误区与追问
- 误区:复制槽只会让复制更可靠,没有副作用。 它会保留 WAL,下游不消费就占磁盘。
- 误区:槽 active 就一定安全。 active 但消费慢,也会产生大量 WAL 滞后。
- 误区:删除槽没有影响。 删除后下游可能无法继续增量复制,需要重新同步。
- 追问:如何查看复制槽? 查询
pg_replication_slots并计算 WAL 滞后。 - 追问:CDC 停了为什么主库磁盘涨? 逻辑复制槽阻止旧 WAL 清理,WAL 不断堆积。
七、加强记忆
记忆钩子:复制槽是给消费者留书签;读者不回来,图书馆就一直不敢清掉后面的旧报纸,仓库迟早堆满。
回答这题时讲清“保留 WAL 的可靠性收益”和“下游停滞导致主库磁盘风险”。这比只背物理复制和逻辑复制更贴近线上事故。