POSTGRESQL 在主从流复制中,在主库失败切换后,从库变为主库后,如果主库不是因为硬件的原因,想继续拉起来,并且加入到新的复制关系中,一般都会通过pg_rewind的程序来进行拉起来. 但不少问题反馈对pg_rewind在重新拉起旧主库出现问题,到底有什么情况下pg_rewind对你的数据库重新建立复制关系"力不从心", 怎么去避免这样的情况是这篇文字要讨论和提到的.
对于对pg_rewind不熟悉的小伙伴,这里在重新解释,一下PG_REWIND的工作主要是针对源数据目录与目的数据目录的同步,通过拷贝的方式,包含配置文件,PG_REWIND不需要读取所有的未改变的文件,只需要读取变化的文件. 这样将一个失败的主库恢复为从库的速度和效率都是最高的. pg_rewind 会评估源和目的集群的时间轴信息,以及偏离点的信息. 另外pg_rewind主要的针对的场景就是主从切换后,主重新加入到新的集群的场景,在wal 日志丢失和不全的情况下,是无法来进行相关的复制的工作的.
另外使用pg_rewind时必须要启用, FPW 和 wal_ log_hint 这两个是必然要开启的选项,否则系统是无法正常使用pg_rewind的.
另外有两点注意,当pg_rewind操作失败后,则目标系统文件损坏,此时只能通过备份的方式来重建"从库",同时对于数据目录中一些"只读文件",使用pg_rewind 时会失败,常见与使用了ssl key 证书的时候.
工作原理:
1 扫描源于目的数据库中最后一次相同的checkpoint点之后的信息,并根据开始不同的信息来组织相关的数据块列表,通过wal log中的进行查找
2 针对列表中的数据块通过拷贝的方式,直接在文件系统级别拷贝,其中还包含pg_xact中的文件以及配置文件等等
3 开始应用在切换点后创建的checkpoint点后的wallog数据并进行重放,pg_rewind本身是不会进行相关的工作,而是通过打入一个备份的标签,在节点开启后重放日志,达到最终的一致性.
1 正常停止主库
2 提升从库
此时需要注意,如果使用了物理复制槽,则必须确认(新主上也有物理复制槽,否则在此设置连接会失败)
SELECT * FROM pg_create_physical_replication_slot('slot_s1');
以下为手动恢复的过程
一 情况 (在主库和从库都不修改数据的情况下)
在原主新从执行pg_rewind命令,连接
1 pg_rewind --target-pgdata=/pgdata/data --source-server='host=192.168.198.101 port=5432 user=repl password=repl dbname=postgres' -P
2 在原主新从,添加recovery.conf文件, 具体可以从原从库,上的recovery.done 中拷贝并修改文件,文件的内容
standby_mode = 'on'
primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=192.168.198.101 port=5432 sslmode=prefer sslcompression=1 target_session_attrs=any'
primary_slot_name='slot_s1'
recovery_target_timeline='latest'
3 启动主库
4 查询复制建立的情况
二 情况 (主库和从库,新主修改了数据的情况)
1 主库关机
2 提升新从变为新主,并插入数据
3 在新"从"上运行pg_rewind命令
pg_rewind --target-pgdata=/pgdata/data --source-server='host=192.168.198.101 port=5432 user=repl password=repl dbname=postgres' -P
4 重建recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=192.168.198.101 port=5432 sslmode=prefer sslcompression=1 target_session_attrs=any'
primary_slot_name='slot_s1'
recovery_target_timeline='latest'
5 启动新从库并在新的从库上查询新添加的数据
三, (主库和从库,新从库修改了数据的情况)
1 关闭主库
2 将新的从库变为主库
3 启动DOWN及的原主库,并添加数据库,在关闭他
4 pg_rewind --target-pgdata=/pgdata/data --source-server='host=192.168.198.101 port=5432 user=repl password=repl dbname=postgres' -P
5 添加recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=192.168.198.101 port=5432 sslmode=prefer sslcompression=1 target_session_attrs=any'
primary_slot_name='slot_s1'
recovery_target_timeline='latest'
6 启动新的从库,查看刚才添加的数据库tt5是否存在, 可以看到原有的tt5已经不存在了.
四, (在主库DOWN机后,DOWN机后的主库和新的主库均变动了数据)
1 关闭主库
2 从库提升为主库
3 在"新主" 上插入数据
4 在"旧主上插入数据"
5 关闭"旧主"
6 执行pg_rewind
pg_rewind --target-pgdata=/pgdata/data --source-server='host=192.168.198.101 port=5432 user=repl password=repl dbname=postgres' -P
7添加recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=192.168.198.101 port=5432 sslmode=prefer sslcompression=1 target_session_attrs=any'
primary_slot_name='slot_s1'
recovery_target_timeline='latest'
8 启动新从库(旧主), 查看从库的数据状态
复制状态
以上情况中,pg_rewind都可以将失败的主, 拉起来并和"新主"进行数据同步.
最后我们模拟一下,突然掉电的情况,看看是否有其他的变化. 并且在主库上加大压力,通过pg_bench 对数据库进行压力测试
在大量插入数据的过程中直接直接将虚拟机硬关机
此时我们将从库变为主库
然后启动已经变成孤家寡人的"主库", 然后他将刚才在掉电情况下为写入的数据进行了redo
然后我们重复上面的工作
pg_rewind --target-pgdata=/pgdata/data --source-server='host=192.168.198.101 port=5432 user=repl password=repl dbname=postgres' -P
配置好复制,启动新的从库
总结: 整体pg_rewind 在多种情况下,都可以保证失败后的数据库重新拉起来并进入新的复制, 但需要注意的两点
1 如果添加的物理复制槽的,那就需要在新的主库上添加,或确认复制槽的存在
2 加入的从库的数据与主库不一致的会全部被抹去,所以在重新加入的过程中需要注意是否有必要要保留"新从"不一致的数据.