
介绍
这篇博客是为了帮助初学者理解和使用故障转移和故障恢复。在PostgreSQL中设置服务器复制。网上关于这个话题的很多信息虽然详细,但已经过时了。在最近的PostgreSQL版本中,对故障转移和故障恢复的配置进行了许多更改。在这篇博客中,我不仅要介绍如何设置故障转移和故障恢复的步骤,还要介绍可能出现的常见陷阱。让我们首先对将要使用的这些恢复方法做一个简单的定义。
故障转移
故障转移操作是当发生一些计划外错误或计划内维护时,我们将主服务器切换到副本。这通常是通过pg_ctl promote这样的工具完成的。主服务器被关闭,一个最新的副本作为新的主服务器接管。这允许在服务器维护失败的情况下提供更多可用性。之前的主服务器还可以被提升回来。
故障恢复
故障恢复操作是指将所需数据从源数据库复制到目标数据库以恢复镜像。这是为了确保两个数据库都是同步的,以便镜像可以继续。这通常是在故障转移操作之后发出的,以便在任何一个方向上重新启动镜像,通常使用pg_rewind之类的工具。
开始
在本教程中,我们假设您已经安装了PostgreSQL,并且知道如何使用流设置物理复制。所有这些步骤都是在Ubuntu 22.10上使用PostgreSQL 16(开发版本)执行的。我们使用$HOME/pg/作为我们的工作目录,$HOME/pg/data, $HOME/pg/rep和$HOME/pg/archive分别作为我们的主数据,副本数据和存档目录。
术语
在本文中,我们将介绍主服务器和副本服务器的不同阶段。由于我们正在讨论的主题的动态性,当主服务器更改为副本,然后再更改时,这可能会变得相当混乱。为了解决这个问题,我将简要总结一下我使用的服务器状态的不同名称。
•主/主服务器:这是我们开始使用的服务器,该服务器的副本。后来,它被称为“旧主/主”或“新副本/辅助/备用”服务器,但它仍然是同一台服务器。
•副本/辅助/备用服务器:此服务器是第二台服务器,用于复制主服务器。之后,它被称为“新的主/主”或“旧的副本/辅助/备用”服务器。
使用故障转移和故障恢复来恢复数据库
首先创建一个主服务器。在启动主服务器之前,将以下内容添加到主服务器的postgresql.conf中:
archive_mode = onwal_level = hot_standbymax_wal_senders = 10hot_standby = onwal_log_hints = onarchive_command = 'cp %p $HOME/pg/archive/%f'restore_command = 'cp $HOME/pg/archive/%f %p'
完成后,继续像往常一样设置复制服务器。
如果您正确地遵循了副本服务器设置,那么它应该与主服务器同步。一旦确认了这一点,将此备用服务器提升为主服务器。
$ pg_ctl promote -D $HOME/pg/repwaiting for server to promote.... doneserver promoted
故障切换
这是流程的故障转移部分,因为副本现在充当主服务器。如果我们的主数据库损坏或崩溃,我们可以使用我们的副本来确保尽可能少的停机时间。但是,仅仅因为我们将这个副本设置为主服务器并不意味着我们的旧主服务器不再接收请求。这是一个真实的问题,以后可能会导致问题,所以让我们添加一些数据来模拟这种情况,这样我们就可以看到如何修复它。
postgres=# insert into t1 values (7,8);INSERT 0 1postgres=# select * from t1;a | b---+---1 | 23 | 45 | 67 | 8(4 rows)
检查新的主服务器是否被更改:
postgres=# select * from t1;a | b---+---1 | 23 | 45 | 6(3 rows)
所以我们可以看到服务器现在不同步了。PostgreSQL经常说他们的“时间线”已经不同了。让我们关闭旧的主服务器:
$ pg_ctl -D $HOME/pg/data stopwaiting for server to shut down.... doneserver stopped
然后我们需要更新旧的主服务器的postgresql.conf文件:
recovery_target_timeline = 'latest'primary_conninfo = 'user=postgres host=localhost port=5433'primary_slot_name = 'main'port = 5432
槽位" main "还不存在,所以我们将在新的主服务器中创建它:
$ psql -d postgres -U postgres -c "select * from pg_create_physical_replication_slot('main');" -p 5433slot_name | lsn-----------+-----main |(1 row)$ psql -d postgres -U postgres -p 5433 -c "select * from pg_replication_slots;" -x-[ RECORD 1 ]-------+---------slot_name | mainplugin |slot_type | physicaldatoid |database |temporary | factive | factive_pid |xmin |catalog_xmin |restart_lsn |confirmed_flush_lsn |wal_status |safe_wal_size |two_phase | f
另外,不要忘记我们的旧主服务器是新的备用服务器,所以我们必须创建一个虚拟备用服务器。signal文件。
$ touch $HOME/pg/data/standby.signal
现在让我们试着启动旧的主服务器:

看起来我们的服务器无法启动!要特别注意这句话:
2023-04-03 11:43:00.122 PDT [69833] FATAL: requested timeline 2 is not a child of this server's history
故障恢复功能
这表明我们的旧主服务器不能作为新主服务器的副本启动,因为它们不同步。我们怎么让它们恢复同步?这就是故障恢复部分发挥作用的地方!首先,我们必须确保我们的档案已经恢复。我们既可以依赖于restore_command,也可以像这样手动执行:
cp -n $HOME/pg/archive/* $HOME/pg/data/pg_wal/
pg_rewind将不能工作,除非我们有正确的档案恢复。一旦完成,我们就可以倒带,将旧main恢复到原始状态。要小心,因为这将删除旧主分区上的所有数据,并复制新主分区的postgresg .conf文件。因此,如果您希望使用特定的端口或配置,请记住在发出pg_rewind之后更改它们。
$ pg_rewind --target-pgdata=data --source-server="port=5433 user=postgres dbname=postgres"pg_rewind: servers diverged at WAL location 0/3000000 on timeline 1pg_rewind: rewinding from last common checkpoint at 0/2000060 on timeline 1pg_rewind: Done!
我们还将在postgresql.conf中添加以下内容,因为它被新的main覆盖了:
primary_slot_name = 'main'recovery_target_timeline = 'latest'primary_conninfo = 'user=postgres host=localhost port=5433 sslmode=prefer sslcompression=0 gssencmode=disable target_session_attrs=any'port = 5432postgresql.auto.conf文件添加以下内容primary_conninfo = 'user=postgres host=localhost port=5433 sslmode=prefer sslcompression=0 gssencmode=disable target_session_attrs=any'port = 5432
现在我们应该能够启动旧的主服务器:
$ pg_ctl -D $HOME/pg/data -l data.log startwaiting for server to start.... doneserver started
一旦启动,让我们检查一下,以确保它的内容实际上回滚:
$ psql -d postgres -c "select * from t1;"a | b---+---1 | 23 | 45 | 6(3 rows)
正如我们所看到的,在提升副本后插入的元组(7,8)已经不在表中了。因此,我们的数据库成功回滚。
现在我们的旧主服务器与新主服务器同步,可以用作副本。如果你的旧主服务器没有与新主服务器同步,这可能是由于旧主服务器的数据目录中的postgresql.auto.conf。这个文件用一些默认值覆盖我们放在postgresql.conf中的内容,所以要么删除这个文件,要么在其中添加正确的primary_conninfo和端口号。
恢复旧主服务器
现在,假设我们想要将旧的主服务器(当前的副本)恢复为集群的主服务器(就像它最初一样)。如果我们在提升副本后不向当前主服务器写入任何数据,那么这很简单,因为我们不需要pg_rewind。
首先,停止新的主服务器:
$ pg_ctl -D $HOME/pg/rep stop
然后用新复制品:
$ pg_ctl -D $HOME/pg/data promote
不要忘记添加备用程序。向原始副本发送虚拟文件信号:
$ touch $HOME/pg/rep/standby.signal
现在,让我们启动副本:
$ pg_ctl -D $HOME/pg/rep -l rep.log start
我们应该在日志文件的某个地方看到下面的行,让我们知道这个副本服务器已经以备用模式启动:
但是在使用副本服务器之前,我们必须更新我们的副本槽。具体来说,我们需要在旧的主服务器上创建一个复制槽,并在旧的复制服务器上删除现有的“主”复制槽。
$ psql -U postgres -c "select * from pg_create_physical_replication_slot('replica');" -p 5432$ psql -U postgres -c "select * from pg_drop_replication_slot('main');" -p 5433
现在,我们应该看到插入到原始主数据库中的任何值都被复制到原始副本服务器中,就像以前一样!
$ psql -d postgres -c "insert into t1 values (0,0);" -p 5432INSERT 0 1$ psql -d postgres -c "select * from t1;" -p 5433a | b---+----1 | 23 | 45 | 69 | 100 | 0(5 rows)
就是这样!我们通过以下方式成功恢复了原始数据库:首先回退到副本,恢复主数据库,将主数据库转换为替换它的服务器的副本,然后将主数据库恢复到原始状态。

PG考试咨询

PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL认证考试,2023春节特惠,开始啦!
PostgreSQL-PCP认证专家-上海站、广州站 PGCCC,公众号:PostgreSQL考试认证中心开班通知-PCP认证专家(上海站)培训开班1106
PostgreSQL-PCP认证专家-北京站-精彩花絮 PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL认证专家考试(培训)(10月16日北京站)精彩花絮
PostgreSQL-PCP认证专家-成都站 公众号:PostgreSQL考试认证中心开班通知-PCP认证专家(成都站)培训开班1016
PostgreSQL-PCP认证专家考试-北京站-考试风采 PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL认证专家考试(培训)-北京站-成功举办
PostgreSQL-PCA认证考试-贵阳站-考试风采 PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL PCA+PCP认证考试在贵阳成功举办
PostgreSQL-PCP认证专家考试-上海站-考试风采 PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL PCP认证考试(上海站)成功举办
PostgreSQL认证专家考试-学员考试总结 薛晓刚,公众号:PostgreSQL考试认证中心难考的PostgreSQL认证考试
PostgreSQL-PCM认证大师考试-天津站-考试风采 PGCCC,公众号:PostgreSQL考试认证中心PostgreSQL-PCM认证大师考试(天津站)成功举办
如何在工业和信息化部教育与考试中心官网查询证书 PG考试认证中心,公众号:PostgreSQL考试认证中心如何在工业和信息化部教育与考试中心查询PostgreSQL证书
中国PostgreSQL考试认证体系 PG考试认证中心,公众号:PostgreSQL考试认证中心中国PostgreSQL考试认证体系




