了解 PG 的朋友应该知道 PG 的主备切换并不容易,步骤较严谨,在激活备节点前需主动关闭主节点,不然再想以备节点角色拉起主节点会比较困难,以前博客介绍过主备切换,PostgreSQL HOT-Standby 的主备切换 ,PG 9.5 版本已经将 pg_rewind 加入到源码,当主备发生切换时,能够将原来主库经过同步模式恢复,避免重作备库。这样对于较大的库来讲,节省了大量重作备库时间。html
pg_rewind 会将目标库的数据文件,配置文件复制到本地目录,因为 pg_rewind 不会读取全部未发生变化的数据块,因此速度比重作备库要快不少,sql
流复制环境
192.168.2.37/1931 主节点(主机名 db1)
192.168.2.38/1931 备节点(主机名 db2)
备注:流复制环境参考 PostgreSQL:使用 pg_basebackup 搭建流复制环境 , 本文略。数据库
--pg_rewind 前提条件
1 full_page_writes
2 wal_log_hints 设置成 on 或者 PG 在初始化时开启 checksums 功能app
--备节点 recovery.conf 配置: db2 上操做ide
[pg95@db2 pg_root]$ grep ^[a-z] recovery.conf recovery_target_timeline = 'latest' standby_mode = on primary_conninfo = 'host=192.168.2.37 port=1931 user=repuser' # e.g. 'host=localhost port=5432'
--激活备节点: db2 上操做post
[pg95@db2 pg_root]$ pg_ctl promote -D $PGDATA server promoting [pg95@db2 pg_root]$ pg_controldata | grep cluster Database cluster state: in production
--备节点激活后,建立一张测试表并插入数据测试
[pg95@db2 pg_root]$ psql psql (9.5alpha1) Type "help" for help. postgres=# create table test_2(id int4); CREATE TABLE postgres=# insert into test_2(id) select n from generate_series(1,10000) n; INSERT 0 10000
--停原来主节点: db1 上操做ui
[pg95@db1 ~]$ pg_controldata | grep cluster Database cluster state: in production [pg95@db1 ~]$ pg_ctl stop -m fast -D $PGDATA waiting for server to shut down....... done server stopped
备注:停完原主库后,千万不能当即以备节点形式拉起老库,不然在执行 pg_rewind 时会报,"target server must be shut down cleanly" 错误。this
--pg_rewind: db1 上操做idea
[pg95@db1 pg_root]$ pg_ctl stop -m fast -D $PGDATA waiting for server to shut down......... done server stopped [pg95@db1 pg_root]$ pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.2.38 port=1931 user=postgres dbname=postgres' -P connected to server target server needs to use either data checksums or "wal_log_hints = on"
备注:执行 pg_rewind 抛出以上错误,错误内容很明显。
--pg_rewind 代码分析
364 /* 365 * Target cluster need to use checksums or hint bit wal-logging, this to 366 * prevent from data corruption that could occur because of hint bits. 367 */ 368 if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION && 369 !ControlFile_target.wal_log_hints) 370 { 371 pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"\n"); 372 } 373
备注:数据库在 initdb 时须要开启 checksums 或者设置 "wal_log_hints = on", 接着设置主,备节点的 wal_log_hints 参数并重启数据库。
--再次 pg_rewind, db1 上操做
[pg95@db1 pg_root]$ pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.2.38 port=1931 user=postgres dbname=postgres' -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 文件: db1 操做
[pg95@db1 ~]$ cd $PGDATA
[pg95@db1 pg_root]$ mv recovery.done recovery.conf
备注:注意是否须要修改 primary_conninfo 配置。
[pg95@db1 pg_root]$ grep ^[a-z] recovery.conf recovery_target_timeline = 'latest' standby_mode = on primary_conninfo = 'host=192.168.2.38 port=1931 user=repuser' # e.g. 'host=localhost port=5432'
--启动原主库, db1 上操做
[pg95@db1 pg_root]$ pg_ctl start -D $PGDATA server starting [pg95@db1 pg_root]$ pg_controldata | grep cluster Database cluster state: in archive recovery
--数据验证, db1 上操做
[pg95@db1 pg_root]$ psql psql (9.5alpha1) Type "help" for help. postgres=# select count(*) from test_2; count ------- 10000 (1 row)
备注:pg_rewind 成功,原主库如今是以备库角色启动,并且数据表 test_2 也同步过来了。
The basic idea is to copy everything from the new cluster to the old cluster, except for the blocks that we know to be the same. 1)Scan the WAL log of the old cluster, starting from the last checkpoint before the point where the new cluster's timeline history forked off from the old cluster. For each WAL record, make a note of the data blocks that were touched. This yields a list of all the data blocks that were changed in the old cluster, after the new cluster forked off. 2)Copy all those changed blocks from the new cluster to the old cluster. 3)Copy all other files like clog, conf files etc. from the new cluster to old cluster. Everything except the relation files. 4) Apply the WAL from the new cluster, starting from the checkpoint created at failover. (Strictly speaking, pg_rewind doesn't apply the WAL, it just creates a backup label file indicating that when PostgreSQL is started, it will start replay from that checkpoint and apply all the required WAL.)
PostgreSQL HOT-Standby 的主备切换
PostgreSQL:使用 pg_basebackup 搭建流复制环境
pg_rewind