系列文章目录
第一章 《PostgreSQL高可用之主备复制》
第二章 《PostgreSQL高可用之主备切换》
第三章 《PostgreSQL高可用之故障转移》
1.前言
在主库宕机等情形下,可能存在备库升级为主库的需求,此时原主库在修复后一般会作为新备库重新加入到集群当中,从而恢复主备复制状态。在正常情况下,备库完整复制了主库的所有内容,此时原主库作为新备库重新加入到集群中相对简单。而在某些特殊场景下,如备库可能还没有来的急完整复制主库内容,主库就发生了宕机,这时备库在提升为主库后插入数据就会产生数据"分叉"问题,在本文中也将介绍如何在特殊场景下进行主备切换。
2.环境准备
按第一章 《PostgreSQL高可用之主备复制》准备主备复制基础测试环境。
3.主备切换
# 主库关闭
# 在主库所在服务器执行
$ docker-compose down
# 备库退出备用模式
# 在备库所在服务器执行
$ docker exec -i postgres14 /bin/bash -c 'su - postgres -c "/usr/lib/postgresql/14/bin/pg_ctl promote -D /var/lib/postgresql/data"'
# 原主库设置为备库
# 在主库所在服务器执行
# postgresql.conf中配置primary_conninfo
$ vi /home/shfirm/postgresql/data/postgresql.conf
primary_conninfo = 'host=192.168.241.136 port=5432 user=replicauser password=111111'
# 创建standby.signal文件
$ touch /home/shfirm/postgresql/data/standby.signal
# 启动原主库(现备库)
$ docker-compose up -d
查询主备库日志命令
$ docker logs -f -t --tail 100 postgres14
正常情况下启动新备库后的日志输出
4."数据分叉"情形下的主备切换
4.1.产生原因
备库升级为主库提供对外服务时,原主库有概率可能存在部分数据没有同步到原备库的情况,如原主库所在服务器突然断电、原备库在升级为主库后原主库依然在写入数据等等。这种情况下原主库想作为备库加入集群,搭建流复制时会出错。模拟"数据分叉"可在备库升为主库后,分别向原主库与现主库分别插入一条数据,以下是该情形下新备库启动后的日志输出:
在当前情况下,备库无法同步主库数据。
4.2.pg_rewind使用方法
pg_rewind是PostgreSQL提供的一款集群同步工具,可以用来解决上述"数据分叉"问题。生产环境在执行前建议对数据库做完整备份。官网地址:https://www.postgresql.org/docs/14/app-pgrewind.html
# 原主库开启wal_log_hints
# When this parameter is on, the PostgreSQL server writes the entire content of each disk page to WAL during the first modification of that page after a checkpoint
$ vi /home/shfirm/postgresql/data/postgresql.conf
wal_log_hints = on
# 重启原主库使配置生效
# 重启前保证data目录中不包含standby.signal否则会重启失败,有该文件的话就删掉
$ docker restart postgres14
# 关闭原主库
$ docker-compose down
# 原主库执行同步命令
# -P 启用进程报告
# -R 自动创建standby.signal文件并将连接信息写入postgresql.auto.conf,standby.signal文件用于标识备库,加入此命令后无需再手动创建
# 如果提示wal日志缺失,可查看是否是wal日志被删除,这种情况可以尝试从新主库拷贝到原主库的pg_wal文件夹。这也说明配置合适的wal保留大小或者进行wal归档十分必要。
$ docker run -it -v /home/shfirm/postgresql/data:/var/lib/postgresql/temp -e POSTGRES_PASSWORD=111111 postgres:14.1 su - postgres -c "/usr/lib/postgresql/14/bin/pg_rewind --target-pgdata=/var/lib/postgresql/temp --source-server='host=192.168.241.136 port=5432 user=replicauser password=111111 dbname=postgres' -P -R"
# 启动原主库
$ docker-compose up -d
pg_rewind执行成功后的日志输出:
在启动后可查看到主备两库数据已同步。这里需要注意一点,原主库会舍弃掉分叉点之后的提交,按照新主库进行回退(从新主库向原主库复制已改变的数据块的方式进行)并通过复制使主备库数据一致。此工具较重新完整还原新主库的好处在于,对于数据文件只需比对改变过的数据块进行复制,当数据库数据量很大且主备库之间只有少量数据块不一致时可以提供更快的恢复速度。
4.3.pg_rewind工作原理
其基本思想是从源库向目标库复制所有文件系统级别的更改内容。在这里源库指新主库,目标库指想要作为备库重新加入到集群中的原主库。
- 从源库与目标库时间线出现分叉的最近一个检查点开始,扫描目标库的wal日志,生成一个目标库更改过的数据块列表。
- 从源库向目标库复制上述更改过的数据块。完成该步骤后"relation files"的状态相当于在数据分叉前,最近一个完成的检查点那个时刻的状态。经过这一步骤也相当于完成了原主库对分叉点后更改的回退。
- 从源库向目标库复制包括"new relation files, WAL segments, pg_xact"和配置文件在内的其它文件,有部分文件是不进行复制的,具体参见官网"How it Works"的对应部分。
- 创建一个"backup_label"文件,以便在故障转移时创建的检查点开始wal日志"重放",并且在"pg_control"文件中配置"一个最小一致性LSN"。如果通过运行的源库执行目标库回退,这个LSN的数值通过pg_current_wal_insert_lsn()获取,否则LSN的数值是最近一次检查点的LSN。
- 当启动目标库,PostgreSQL将"重放"所有必要的wal日志,最终使目标库与源库处于一致状态。