近期在一个国产化数据库highgoDB的数据库环境,一主三从架构,主库的归档产生的较为频繁,且主库的参数关于wal的保留时间配置(wal_keep_size)也偏低, 后来因为备库有重建需求,在重建时发现主库的WAL日志缺失了,重建前也并未手动清理对应的物理槽。难道HighgoDB可以自动清理?
1. 什么是复制槽?
众所周知在Postgresql系的数据库,配置如像oracle的Dataguard环境,需要创建一种叫做复制槽的路径,简单来说,复制槽是一个用于记录逻辑或物理复制流中进度的核心机制。它最主要的作用是:
防止主节点在备节点或客户端尚未确认接收的情况下,过早地删除那些可能仍然需要的 WAL 日志文件。
你可以把它想象成一个“预订”系统。备节点(或逻辑订阅者)通过复制槽向主节点“预订”WAL 日志,告诉主节点:“我正在处理这个位置的日志,请为我保留之后的所有日志,直到我通知你我处理完了。”
2. 为什么需要复制槽?
在没有复制槽的时代,PostgreSQL 依赖两个参数来管理 WAL 日志的清理:
wal_keep_segments(现在叫wal_keep_size):指定要保留的过去 WAL 文件的最小数量/大小。max_slot_wal_keep_size:指定为 WAL 文件保留的最大磁盘空间。
这种方式存在明显问题:
- 难以配置:如果备节点停机时间较长,或者主节点产生了大量 WAL 日志,你设置的保留量可能不够,导致 WAL 被删除,复制中断。
- 资源浪费或风险并存:设置得太大浪费磁盘空间;设置得太小则有复制中断的风险。
复制槽通过基于消费状态的精确跟踪解决了这个问题。只要备节点(通过其复制槽)没有确认,主节点就会无限期地保留所需的 WAL 文件,确保复制永远不会因为 WAL 被删除而中断。
3. 复制槽的类型
PostgreSQL 支持两种主要类型的复制槽,对应两种复制模式:
a. 物理复制槽
- 用途:用于物理流复制 和 PITR。
- 工作方式:与一个备用服务器 关联。它记录的是备机在 WAL 流中已经接收并刷新到磁盘的位置(LSN – Log Sequence Number)。
- 典型场景:构建主从高可用集群。
b. 逻辑复制槽
- 用途:用于逻辑复制。
- 工作方式:与一个逻辑订阅 关联。它记录的是逻辑解码插件已经处理并发送给订阅者的位置。这个位置是在事务层面的,而不是物理字节位置。
- 典型场景:将数据更改实时同步到数据仓库(如 ClickHouse)、缓存(如 Redis),或实现不同版本 PostgreSQL 之间的数据同步。
4.查看复制槽状态
系统视图是 pg_replication_slots。创建与删除的函数pg_create_physical_replication_solt\pg_create_logical_replication_slot, pg_drop_replication_slot.
SELECT slot_name, slot_type, plugin, database, active, active_pid,
restart_lsn, confirmed_flush_lsn, wal_status
FROM pg_replication_slots;
slot_name: 复制槽的名称。
slot_type: physical 或 logical。
active: 是否为“活动”状态(即是否有消费者正在连接并使用它)。这是一个非常重要的指标。
restart_lsn: 这是复制槽最关键的字段之一。表示如果客户端断开重连,它需要从哪个 LSN 开始重新读取 WAL。主节点必须至少保留从这个 LSN 开始的 WAL 文件。
confirmed_flush_lsn: (主要用于逻辑复制槽)表示客户端已确认接收到的 LSN。
wal_status: 显示所需的 WAL 文件的状态,例如 reserved(已保留)、extended(已保留但需要计算时间线历史文件)或 lost(所需的 WAL 文件已被删除,说明复制槽已经失效)。
5. 重要注意事项和风险
- 磁盘空间耗尽风险:这是使用复制槽最大的风险。
- 如果一个非
active的复制槽长时间存在(例如,备节点崩溃且无法恢复),主节点会一直为其保留 WAL 日志。 - 这会导致
pg_wal目录不断增长,最终耗尽磁盘空间,使主数据库不可用。 - 监控方案:必须持续监控
pg_replication_slots视图中的active状态和restart_lsn,并设置警报。同时监控pg_wal目录的磁盘使用情况。
- 如果一个非
-- 监控非活跃的复制槽
SELECT slot_name, slot_type, active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as wal_retained
FROM pg_replication_slots
WHERE active = false;
-- 监控复制槽保留的WAL大小
SELECT slot_name,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as retained_wal
FROM pg_replication_slots;
2.逻辑复制槽与事务:长时间打开的事务会阻塞逻辑复制槽的进度,因为解码需要确定性的快照。同样会导致 WAL 堆积。
6. HighgoDB 与PostgreSQL的改变
postgresql 在重建流复制的备库时,主库的物理复制槽不会自动清理。这是一个非常重要且容易出错的地方。PostgreSQL 无法区分”临时断开”和”永久重建”,仅在备库断开连接后,对应的复制槽 active 字段会变为 false,但复制槽本身仍然存在,继续占用资源。所以可能会导致WAL日志耗尽磁盘空间。
HighgoDB虽然内核上与Postgresql相同,但在HGHA的集群组件层有变动,为了防止上面PG的问题,在重建备库时,会自动删除主库的物理复制槽, 所以就出现了我们开始遇到的问题,因主库配置的wal保存策略有问题,因复制槽占用主库不能删除wal,但是当重建备库时或过程中,因slot被集群件删除,主库会根据参数自动清理WAL日志,出现了重建后缺失日志的问题。解决方法当然可以从其他备库查看是否有该wal,手动修复,或增加主库的Wal保留时间max_slot_wal_keep_size参数后,再次重建备库。
— over —