作者:瀚高PG实验室 (Highgo PG Lab)- 波罗
在主从复制的两个节点中,当主节点数据库服务访问异常的时候后,可以手动通过promote 命令在从节点执行将从节点状态切换到可读写的状态,变为新的主节点。
修复原主节点为新的从节点可以通过pg_rewind命令来实现,PG 9.5 版本已经将 pg_rewind 加入到源码,当主备发生切换时,可以将原来主库通过同步模式恢复,避免重做备库。这样对于较大的库来说,节省了大量重做备库时间。
pg_rewind 会将目标库的数据文件,配置文件复制到本地目录,由于 pg_rewind 不会读取所有未发生变化的数据块,所以速度比重做备库要快很多。
pg_rewind 前提条件
full_page_writes
wal_log_hints 设置成 on 或者 PG 在初始化时开启 checksums 功能
示例:initdb --data-checksums
主备库切换
pg_rewind是如何工作的
基本的思想是从新的集群拷贝所有的东西到老的集群,除了相同的(数据)块。
1.从最后一个检查点开始扫描老集群的WAL日志,在该检查点之前,新集群的时间线历史从老集群被创建出来。对于每一个WAL记录,做一个数据块被触及的记录。在新的集群被创建出来以后,这产生所有在老集群中被更改的数据块的列表。
2.从新集群复制所有这些被更改的数据块到老集群。
3.从新集群复制所有其它像clog,conf这样的文件等等到老集群。每个文件,除了表文件。
4.从新集群应用WAL,从故障转移创建的检查点开始。(严格的说,pg_rewind不应用WAL,它只是创建一个备份标签文件以表明PostgreSQL被启动了,它会从检查点重放并应用所有需要的WAL)
主备库切换的实现过程
1) 激活备库: db2 上操作(关键指令)
pg_ctl promote -D $PGDATA
备注:在promote模式中,运行在指定数据目录中的后备服务器被命令退出恢复并且开始读写操作。
2)验证备节点状态
pg_controldata | grep cluster
#运行在指定数据目录中的后备服务器被命令退出恢复并且开始读写操作。
此时可以验证备节点是否可以执行写入操作
create table repl_t1(id int4);
insert into repl_t1(id) select from generate_series(1,10);
主备库切换
3)停原主库
pg_controldata | grep cluster
Database cluster state: in production
pg_ctl stop -m fast -D $PGDATA
备注:停完原主库后,千万不能立即以备节点形式拉起老库!!!
否则在执行 pg_rewind 时会报,"target server must be shut down cleanly" 错误。
pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.137.221 port=1921 user=postgres dbname=testdb' -P
connected to server
target server needs to use either data checksums or "wal_log_hints = on"
备注:执行 pg_rewind 抛出以上错误,错误内容很明显。
主备库切换
pg_rewind 代码分析
if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
!ControlFile_target.wal_log_hints)
{ pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"\n"); }
备注:数据库在 initdb 时需要开启 checksums 或者设置 "wal_log_hints = on", 接着设置主,备节点的 wal_log_hints 参数并重启数据库。
此处调试过程我在测试环境的解决办法是将数据库重新做了初始化,命令参考:
initdb --data-checksums
再次 pg_rewind, 原主库上执行
pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.137.220 port=1921 user=postgres dbname=testdb' -P
-----------------
connected to server
The servers diverged at WAL position 0/1300CEB0 on timeline 5.
Rewinding from last common checkpoint at 0/1200008C on timeline 5
reading source file list
reading target file list
reading WAL in target
need to copy 59 MB (total source directory size is 76 MB)
61185/61185 kB (100%) copied
creating backup label and updating control file
Done!
------------------
pg_rewind 成功。
调整 recovery.conf 文件: 原主库 操作
cd $PGDATA
mv recovery.done recovery.conf
备注:注意是否需要修改 primary_conninfo 配置。
grep ^[a-z] recovery.conf
recovery_target_timeline = 'latest'
standby_mode = on
primary_conninfo = 'host=192.168.137.220 port=1921 user=repuse
启动原主库, db1 上操作
pg_ctl start -D $PGDATA
server starting
pg_controldata | grep cluster
Database cluster state: in archive recovery
数据验证, db1 上操作
[[email protected] pgdata]$ psql
psql (9.5.7)
Type "help" for help.
select count(*) from repl_t1;
count
-------
10
(1 row)
备注:pg_rewind 成功,原主库现在是以备库角色启动,而且数据表 test_2 也同步过来了。