流复制集群的故障恢复
1. 数据库宕掉,但主机还正常
不管是主库还是备库,如果只是数据库宕掉,主机还正常的情况,这时集群软件会检查到这个数据库出现了问题,但因为主机还是正常运行的,集群软件会自动把数据库拉起来,这种故障不需要人工参与。
2. 库的机器宕掉
当主库的机器宕掉后,CLup会检测到这个主数据库出现了问题,同时这台机器也连接不上了。CLup会从备库中挑选一个作为新主库,原主库会标记为“Fault”。
等原主库的机器恢复后,这台机器想加入集群,只能作为备库加入了,通常我们不能把这个数据库直接转成备库,因为旧的主库是异常宕机,有可能WAL日志超前原先的备库(即使是同步复制也是如此)。这时如果我们手工把其作为备库加入(如PostgreSQL 12版本之前,是添加recovery.conf,PostgreSQL 12后是修改postgresql.conf,添加standby.signal文件),启动这个原主库时,发现无法与新主库建立流复制,同时会在数据库日志文件中上看到类似如下的日志:
2022-05-11 10:23:09.298 UTC [297] DETAIL: End of WAL reached on timeline 14 at 0/18BAA30.
2022-05-11 10:23:09.298 UTC [293] LOG: new timeline 15 forked off current database system timeline 14 before current recovery point 0/18BAAA0
2022-05-11 10:23:14.285 UTC [297] LOG: restarted WAL streaming at 0/1000000 on timeline 14
2022-05-11 10:23:14.300 UTC [297] LOG: replication terminated by primary server
2022-05-11 10:23:14.300 UTC [297] DETAIL: End of WAL reached on timeline 14 at 0/18BAA30.
2022-05-11 10:23:14.300 UTC [293] LOG: new timeline 15 forked off current database system timeline 14 before current recovery point 0/18BAAA0
2022-05-11 10:23:19.291 UTC [297] LOG: restarted WAL streaming at 0/1000000 on timeline 14
2022-05-11 10:23:19.310 UTC [297] LOG: replication terminated by primary server
2022-05-11 10:23:19.310 UTC [297] DETAIL: End of WAL reached on timeline 14 at 0/18BAA30.
2022-05-11 10:23:19.311 UTC [293] LOG: new timeline 15 forked off current database system timeline 14 before current recovery point 0/18BAAA0
上面的信息中“new timeline X forked off current database system timeline Y before current recovery point 0/XXXXXXX”这样的信息,就表明这个新主库与旧主库走到了不同的分支上,旧主库不能再做为新主库的备库使用了。同时在CLup管理界面中的详情中的主备数据界面中看到这个节点的流复制的状态不是正常的“streaming”,可能是一个“startup”状态,也可能是一个其它的异常状态。
如果我们设置的是自动加回集群,则CLup会自动处理此故障。如果没有设置自动加回集群,则可以手工到界面中点“加回集群”。
如果机器是永久故障,此可以把此节点永久的从集群中移除。后续换新机器后,可以把新机器做为一个新备库加入到集群中。
如果机器是临时故障,之后恢复正常后,clup-agent程序会自动启动。后续的恢复操作分两种情况:
- 如果没有配置自动加回集群,则需要手工的到CLup的管理界面中,把此备库重新加入集群。重新加入集群的处理流程为:会先尝试使用pg_rewind恢复备库,如果pg_rewind无法恢复备库,则会重新搭建备库。在界面上有一个选项,是选择在重新搭建备库中是把旧数据目录和表空间目录删除还是改名保留。
- 如果集群中配置了自动加回集群,CLup会把此失败的备库自动重新加入集群。加入的过程是:启动备库,备库到主库的流复制是否正常,如果不正常,则会先尝试使用pg_rewind恢复备库,如果pg_rewind无法恢复备库,则会使用pg_basebackup重新搭建备库(旧的数据目录和表空间目录会被重命名)。
手工把失败的节点加回集群的方法如下:
机器故障后,在HA集群-> HA管理中看到的状态如下图:
上图中列“HA状态”显示是“Fault”表示是备库故障,而列“数据库状态”是“agent异常”,表示是无法连接到此台机器上测clup-agent。当机器恢复后,在此数据库代表的行后面“操作”列中出现了“加回集群”的按钮,如下图所示:
点“加回集群”的按钮后,出现一个选择框界面,让我们选择此备库使用那个库做为它的流复制上级库:
根据实际需要选择一个上级库,然后点“确定”按钮,出现一个加回集群的选择框:
上面的选择项目中,需要选择是否使用pg_rewind,是否重新搭建备库。如果选择pg_rewind则会尝试用pg_rewind修复此备库,而选择“重新搭建备库”的选择框后,则会如果前面失败后,会使用重新搭建备库的方式恢复此节点。当然如果我们不选择“重新搭建备库”的此框时,备库如果无法连接到主库时,则加回集群的操作会失败。一般的恢复,我们都会把“使用pg_rewind”的框和“重新搭建备库”的框都选上,系统在用普通的方式恢复不了是,会自动使用pg_rewind和重新搭建备库的方式恢复此节点。
当选择“重新搭建备库”后,还有一个选项需要选择,是把数据库的目录重命令还是删除,如果机器上有足够空间,可以限制重命名,如果没有空间,只能选择删除后重建。
做好上面的选择后,点确定,就开始恢复此节点了:
3. 备库的机器宕掉
这时集群软件会检测到这个备数据库出现了问题,同时也会发现机器出问题了,集群软件会自动把此数据库标记为坏,机器的Agent状态置为Down。
如果机器是永久故障,此可以把此节点永久的从集群中移除。后续换新机器后,可以把新机器做为一个新备库加入到集群中即可。
如果机器是临时故障,之后恢复正常后,clup-agent程序会自动启动。后续的节点加回集群的处理流程与主库节点失败后重新加入集群的处理流程一致。只是备库临时失败后,大概率不会重新搭建,只要启动后,把上级库指向新备库即可以恢复。但如果故障停的时间太久,导致备库落后主库太多,备库需要的WAL日志没有了,此时就会使用重新搭建备库的方式加回集群。
4. 注意事项
主备库之间WAL落后太多,导致备库失效的问题。
通常主库发生一次checkpoint点之后,这个checkpoint点之前的WAL日志会被删除掉,但这些日志如果还没有来得及传到备库,会导致备库失效掉。这导致发生故障时无法让备库成为主库。
解决办法:
PostgreSQL 12及之前的版本配置合理的wal_keep_segment参数,而PostgreSQL 13及之后的版本设置合理的wal_keep_size, 让主库保留较多的WAL日志。
示例配置:
在PostgreSQL 12及之前版本配置:
wal_keep_segments = 2048
wal_keep_segments表示保留wal日志文件的个数,默认单个wal日志文件为16MB,因此设置此值后wal日志文件最大为2048*16MB=32GB,通常32GB的量对一般的数据库都足够了。
从PostgreSQL13版本开始,wal_keep_segments改为wal_keep_size(单位MB),即wal日志文件保留大小,超出此值PostgreSQL会将旧的wal日志删除。
在PostgreSQL 13及之后版本配置:
wal_keep_size = 32GB
通常我们保留的WAL日志的量为总数据库大小的5%~10%。
当然我们也可以使用复制槽来防止主库把备库需要的WAL日志移除了。但我们一般不建议使用复制槽,因为当忘记删除失败节点的复制槽,容易把主库的空间撑爆。