在 PostgreSQL 主备切换(Failover)后,旧的主库因为数据可能领先或与新主库(原备库)产生了分歧,无法直接启动同步。pg_rewind 的作用是对比两者的 WAL 日志,将旧主库"回滚"到分叉点,使其能够以增量同步的方式重新加入集群,避免了全量重做数据(pg_basebackup)的巨大开销。
一、实现流程
pg_rewind 的工作可以分为五个关键阶段:
1. 扫描新主库的 WAL 日志
pg_rewind 首先读取新主库 的 WAL 日志,从当前时刻向上追溯,直到找到与旧主库最后一次同步时的共同时间线位置。
2. 扫描旧主库的数据文件
这是最关键的一步。pg_rewind 会读取旧主库从分叉点开始之后的所有 WAL 日志。
- 它会解析这些 WAL 记录中的 Data Page ID。
- 记录下哪些数据页(Page)在分叉后被修改过了。
- 将这些被修改过的块编号放入一个散列表中。
3. 从新主库获取对应数据块
一旦确定了旧主库中哪些块是"脏"的(即分叉后修改过的),pg_rewind 就会连接到新主库,仅请求这些特定块的最新副本。
- 此时它会利用新主库的
wal_log_hints参数或数据校验和,因为这些机制强制 PostgreSQL 在 checkpoint 后的第一次修改时记录整个数据页的内容(Full Page Writes)。
4. 覆盖旧主库的数据块
将从新主库拷贝过来的"正确"数据页,直接写入到旧主库对应的文件位置中。同时,它还会同步一些系统文件(如 pg_control、pg_xact 等)。
5. 复制新主库的 WAL 日志
最后,它会从新主库拷贝分叉点之后的所有 WAL 日志到旧主库的 pg_wal 目录。这是为了确保旧主库在下次启动时,可以通过重放这些 WAL 日志来实现数据的最终一致性。
二、pg_rewind 恢复示例
以下是使用 pg_rewind 恢复旧主库为新从库的详细步骤:
2.1 前提条件
- 配置要求:主库在故障前必须开启了 wal_log_hints = on,或者数据库初始化时开启了数据校验和(data checksums)。
- 状态确认 :
- 新主库(原备库)已提升并处于读写状态。
- 旧主库(待恢复库)必须已经彻底停止(干净关闭或宕机后未再写入)。
2.2 操作步骤
假设:
- 新主库 IP:192.168.1.102
- 旧主库 IP:192.168.1.101 (当前操作在该机器上执行)
- 数据目录:/var/lib/postgresql/data
2.2.1. 停止旧主库(如果还在运行)
确保旧主库完全停止
systemctl stop postgresql
2.2.2. 执行 pg_rewind
在 旧主库 节点上,使用 postgres 用户执行以下命令:
pg_rewind --target-pgdata=/var/lib/postgresql/data \
--source-server="host=192.168.1.102 user=postgres dbname=postgres password=your_password" \
--progress
- --target-pgdata:旧主库的数据目录。
- --source-server:指向新主库的连接字符串。
- 注意:连接用户需具备超级用户权限或 pg_rewind 所需的特定权限。
2.2.3. 配置为从库模式
pg_rewind 只负责同步数据文件,不会自动开启流复制。你需要将其设置为备库:
- 创建从库标记文件:
touch /var/lib/postgresql/data/standby.signal
- 修改连接信息 : 编辑 /var/lib/postgresql/data/postgresql.auto.conf,更新 primary_conninfo 指向新主库:
primary_conninfo = 'host=192.168.1.102 port=5432 user=replica_user password=your_password'
2.2.4. 启动旧主库(此时作为新从库)
systemctl start postgresql
2.3 验证状态
- 检查同步状态: 在新主库执行:
SELECT * FROM pg_stat_replication;
- 查看日志: 检查旧主库(现从库)日志,确认是否出现 started streaming WAL from primary at ... 的字样。
三、核心注意事项
- WAL 保留:pg_rewind 需要新主库上保留自"分叉点"以来的所有 WAL 日志。可以调大 max_slot_wal_keep_size 或使用 WAL 归档。如果日志已被清理,pg_rewind 会失败,此时只能通过 pg_basebackup重新做全量备份。
- 配置文件:pg_rewind 默认会覆盖 postgresql.conf 等配置文件。如果主从配置有细微差异(如内存分配),建议执行后检查一下。
- 复制槽:如果使用了物理复制槽,在新主库上可能需要重新创建对应新从库的复制槽。