PostgreSQL物理同步 12.2-阿里云开发者社区

开发者社区> 数据库> 正文

PostgreSQL物理同步 12.2

简介: 本文探讨: 流复制,复制槽,wal日志传送,同步复制,异步复制,级联复制,多同步备用,多异步备用,规划高可用,待机中的连续归档,故障切换、切换后如何重建备库(pg_rewind)

相关:

1. 能够修改数据的服务器被称为读写、主控、主要服务器
2. 跟踪主控机改变的服务器被称为后备或次级服务器。
3. 如果一台后备服务器只有被提升为一台主控服务器才能被连接,它称之为温备服务器
4. 一台总是能够接受连接,并且提供只读查询的后备服务器称为热备服务器。
5. 同步复制指的是一个数据修改事务只有所有服务器都提交了该事务之后才被认为是提交成功的。这表示故障转移不会丢失任何数据,并且所有主、备服务器都将返回一致的结果,不管哪台服务器被查询。
6. 异步复制允许在一次提交和它被传播到其他服务器之间有一些延迟,这时切换到一个备服务器会有丢失某些事务的可能性,并且备库返回的结果会略微陈旧。
7. 物理复制指的是只能处理一整个数据库服务器
8. 逻辑复制指的是允许在每个表或每个数据库的级别上进行控制。
9. pg中的wal日志传送来达到的同步,可以是同步或者异步,并且只能用于整个数据库服务器。
10. 逻辑复制允许数据库服务器发送数据流修改给另一台服务器。
11. pg的逻辑复制从wal中构建出一个逻辑数据修改流。且允许复制个体表中的数据更改,逻辑复制不要求特定服务器作为什么角色(比如说主或者备),它允许数据以多方向流动
12. 基于触发器的主备复制是:会把所有的数据修改发送到主服务器,主异步的将数据修改发送给后备服务器,后备只可以只读查询。例如Slony-I 就是用的这种方式,支持多个后备服务器,但是故障转移可能会丢失数据。
13. 基于语句的复制中间件:一个程序拦截每一个sql查询并把它发送给一个或所有服务器,每一个服务器独立的操作。读写查询必须被发送给所有服务器,这样每一个服务器都能接受到任何修改。但只读查询可以被只发送给一个服务器,这样允许读负载在服务器之间分布。
如果主库有random(),current_timestamp之类的函数以及序列,会在不同的服务器上有不同的值。如果接受不了这种数据改变,中间件必须设置为当遇到这种不确定值的时候,直接查询到语句的结果,然后把语句的结果同步给其他服务器,而不是在其他机器上再执行一次;要么所有事务在所有服务器上都提交,要么所有服务器上都中止。Pgpool-II 和continuent Tungsten是这种复制类型的例子。
14. 同步多主控机复制:每一个服务器都可以读写,并且在每一个事务提交之前,被修改的数据会从主机发送到其他服务器。可是当繁重的写活动会导致非常多的锁定(表行和行锁),其他机器啥的都要等待,导致很差的性能,写操作的性能往往比只有一个单一服务器写还要差。数据修改结果被从一个服务器发送到另一个服务器,不会有非确定函数random的问题。
pg中不提供这种复制类型,但是其他自己写的程序可以用pg的两阶段提交来实现这种复制。
15. 当你的数据需要划分成一块块的,每一块放到自己的服务器上;一个应用查询,要查询多个服务器的时候,就不再适用于1-14的同步方法
16. 多服务器并行查询:跟15类似 允许多个服务器在一个单一查询上并发的工作,每个服务器计算一部分,结果返回给中心服务器由它整合结果并发给用户,这种也不适用于1-14的同步方法,你可以用greenplum,或者pgpool - ll , PL/Proxy,都可以实现这种多服务器并行查询。

pg中的wal日志主备同步:

1. 从一个数据库服务器移动wal记录到另一台服务器同城被描述为日志传送。主库在连续归档模式下操作,而每一个后备服务器在连续恢复模式下操作并且持续从主服务器读取wal文件。
2. 日志传送是异步的,即wal记录是在事务提交后才被传送,如果主库突然发生灾难,还没有被传送的事务将会丢失,可以通过使用参数archive_timeout(强制让pg切换wal段文件)进行限制,它可以被设置为低至数秒。但是会增大带宽。
3. 如果你希望数据更快的从主服务器复制到备用服务器,你应该用流复制,而不是用wal归档。
4. 流复制和wal归档同步不是一个东西,但是一般结合起来用。
5. wal日志主备同步,备库只需片刻就可以激活达到完全可用,类似于oracle备库激活为主库。
6. wal日志只是提供了一种方案,它并不是高可用
7. 备机可以被用于只读查询
8. 如果你用了自定义表空间,则操作系统路径和表空间,主备库都要完全一致。你在主库上create tablespace之前,你的主备库的表空间对应的操作系统路径都应该存在并有相同的正确权限。
9. 主备机的硬件不需要完全相同,但是32位系统无法同步到64位系统,且PG的版本要尽可能的相同(大版本)
10. 当想对主的pg升级,最安全的策略是先升级备用服务器在给主的升。
11. 在使用异步复制时,如果用户在主库发出fast shutdown,在所有未解决的wal记录被传输到当前连接的后备服务器之前,主库将不会被关闭。

备用服务器:
备服务器中,服务器持续的从主控服务器接收wal日志。后备服务器可以从一个wal归档(restore_command参数)或者通过一个TCP IP连接直接从主控机读取wal(这种方法就叫流复制)。后备服务器也会尝试恢复在备机上的$PGDATA/pg_wal目录中找到的wal日志,不过这一般发生在数据库重启发生后,备机将重新应用从主控机复制过来的wal。但是你也可以在任何时候拷贝wal文件到pg_wal目录下,以便pg可以读取应用。

备机查找日志通过3个方面:
有先后顺序的
(1)restore_command里面写的归档位置,一旦应用到归档位置的末尾并且restore_command失败。将会进行第二步
(2)读取pg_wal目录中任何可用的wal(pg自然会认得它需要啥,不需要啥,所以你不用担心),如果这也失败且你配置了流复制,则进行第三步
(3)备机将尝试连接到主服务器从归档位置archive_command或者pg_wal中找到最后一个可用记录,开始流式传输wal;如果这样也失败了或者你没有配置流复制或者网络连接断开,后备服务器将会返回步骤1,将再次执行1、2、3步骤直到服务器停止,或者触发了一个触发器进行了故障转移。

pg建议:
在主服务器上设置连续归档到一个后备服务器可以访问的目录。即使主服务器垮掉,该归档位置也应该是后备服务器可以访问的。那它应当位于后备服务器本身或者另一个可信赖的服务器,而不是位于主控服务器上。

(比如说

123是主库,124是备库;
先配置123到124 postgres用户的互信,让scp和ssh都不用通过密码就可以发文件、连接,参考本笔记中文章“scp互信”
这样wal日志一份存123本地,一份通过scp发给124备库本地目录中。脚本中test这行千万别改动,比如说想把他变成两行啥的,改了find命令就开始报错了。test这行就这样,你新增命令就在scp下面的空行新增。)

如果要用流复制,在主库上设置pg_hba.conf认证允许来自后备服务器发起的复制连接。即创建一个角色并且在pg_hba.conf中提供一个或多个数据域被设置为replication的设置。
还要保证主服务器配置文件中的max_wal_senders被设置为足够大的值。
如果要使用复制槽,请确保max_replication_slots也被设置的足够高。

如何创建一个后备服务器:
PG11(包含)之前:

1. 恢复从主服务器取得的基础备份
2. 在备服务器的$PGDATA下新建recovery.conf
3. 在recovery.conf中设置standby_mode='on'
4. 将restore_command设置为从一个wal归档中复制文件的命令
5. 如果为了高可用建立多个后备服务器,将recovery_target_timeline设置为latest,以便故障转移后能够应用时间线的改变。
6. 如果要同时要用流复制,则需要在备参数文件中的参数项primary_conninfo中写一个libpq字符串,其中包括主机名/IP,端口,用户,密码啥的,备机会自动连接到主库,从主库获取当前wal日志的变化从而应用到备库。
7. 如果以后主备要故障切换,则你备库也得建立wal归档,连接,认证啥的主库那一套,因为你得要故障切换,备库变为主库,也得像主库一样往备库同步。
8. 如果你正在用wal归档,那你的备机上日志的自动删除可以通过参数archive_cleanup_command参数来自动删除。一般备库自动删除是archive_cleanup_command参数和pg_archivecleanup工具相互配合起来用的。后面会有示例。

举例:

Pg11(不包含)之后,比如说本版本12.2:

1. 恢复从主服务器取得的基础备份
2. 在备用数据库的$PGDATA下创建文件standby.signal
3. 将restore_command设置为从一个wal归档中复制文件的命令
4. 如果为了高可用建立多个后备服务器,将recovery_target_timeline设置为latest,以便故障转移后能够应用时间线的改变。
5. 如果要同时要用流复制,则需要在备参数文件中的参数项primary_conninfo中写一个libpq字符串,其中包括主机名/IP,端口,用户,密码啥的,备机会自动连接到主库,从主库获取当前wal日志的变化从而应用到备库。
6. 如果以后主备要故障切换,则你备库也得建立wal归档,连接,认证啥的主库那一套,因为你得要故障切换,备库变为主库,也得像主库一样往备库同步。
7. 如果你正在用wal归档,那你的备机上日志的自动删除可以通过参数archive_cleanup_command参数来自动删除。一般备库自动删除是archive_cleanup_command参数和pg_archivecleanup工具相互配合起来用的。后面会有示例。

primary_conninfo就是流复制的参数,是数据库集簇内的连接获取当前正在使用的wal日志信息。
Wal_sender_timeout
终止不活动时间超过此时间的复制连接,如果你指定5000而不指定单位,则默认单位为毫秒,这里就是5秒(1秒=1000毫秒);如果你啥也不写,则默认为60秒。
Primary_conninfo详细内容https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-WAL-SENDER-TIMEOUT
restore_command就不说了
archive_cleanup_command,就是后面写个命令来自动清除备库的无用归档,那清理的话就得用到pg_archivecleanup这个工具。
%r 代表包含最后一个可用的wal日志文件,改文件是一次恢复中可重启的必须被保留的最早的文件,任何早于%r的文件都是可以被删除的。
Pg_archivecleanup是清理wal归档的工具。这本来是个单独删除归档的工具,也可以用作archive_cleanup_command中。
当它用在archive_cleanup_command中时,逻辑是%r参数之前的wal文件都将被删除。
当用作独立删除归档工具时,请参考 http://www.postgres.cn/docs/11/pgarchivecleanup.html

流复制:

1. 流复制是备用数据库连接到主数据库,主库在生成wal记录时将其流式传输到备库,而无需等待wal文件被装满了切换,才传输到备库。
2. 默认下,流复制是异步的,虽然是异步但是延迟非常小,一般延迟不到1秒钟,而且你不需要设置archive_timeout来强制让主库归档。
3. 流复制一般跟wal日志结合起来用。如果你只用了流复制而没用wal归档,则主库wal归档删掉或回收后,你只能重新恢复主库的基础备份了。

使用流复制:

1. 在备机上设置primary_conninfo设置为指向主服务器。
2. 在主服务器上设置listen_addresses和pg_hba.conf以便备机可以通过replication连接到主服务器上的伪数据库,不是真正的数据库上。
3. 设置备库的max_wal_senders,主库最好也设的大一点,备库的该值必须跟主库相同或者比主库更高。否则备库将无法查询。因为备库要去主库通过流复制取数据占用了很多连接数。
4. 启用备库并primary_conninfo正确设置后,备库在恢复完所有wal可用归档文件后,将连接到主库上获取当前wal变化。此时主库会有一个walsender进程;备库有walreceiver进程。可以看到。

pg_hba.conf文件认证

1. 备用服务器必须作为超级用户或者具有replication和login权限的用户才能去通过流复制去连接主库。
2. pg建议你创建一个replication和login权限的用户去连接主库,而不要用超级用户。因为对主库的连接应该万分注意,超级用户可以更改主库的数据,而replication权限和login权限只能用作流复制而没有权限去更改主库的任何数据。

示例:
123主库,124备库,用户是gaorp,密码是oracle

主库

TYPE DATABASE USER ADDRESS METHOD

host replication gaorp 192.168.31.124 md5

备库
primary_conninfo = 'host=192.168.31.123 port=5432 user=gaorp password=oracle'

监控方式

1. 流复制的重要健康指标是指在主库中生成但尚未在备用数据库中应用的wal记录的数量。
2. 你可以通过对比主数据库上的当前wal写入位置与备库接收到的最后一个wal位置进行比较来计算延迟。主库上查看pg_current_wal_lsn,获取当前的预写日志写入位置;备库上查看pg_last_wal_receive_lsn,接收到的最后一个wal日志位置,并通过流复制同步到备机的磁盘上;两个函数具体的功能请查看
pg_current_wal_lsn
https://www.postgresql.org/docs/12/functions-admin.html#FUNCTIONS-ADMIN-BACKUP-TABLE
pg_last_wal_receive_lsn
https://www.postgresql.org/docs/12/functions-admin.html#FUNCTIONS-RECOVERY-INFO-TABLE
3. 备库最后一个wal接收位置也显示在wal接收器进程的进程状态中。
比如说
ps -ef |grep postgres

主库高负载:
当pg_current_wal_lsn与视图sent_lsn字段之间的差异较大的时候可能主库正处于高负载状态。

网络延迟或备库高负载:
备用数据库之间sent_lsn和pg_last_wal_receive_lsn之间的差异可能是网络延迟了,或者备库正处于高负载状态。

wal接受速度快于应用速度:
pg_last_wal_replay_lsn和received_lsn视图之间的巨大差异表名wal接收速度快于应用速度。

主库:
可以通过pg_stat_replication视图查看wal发送者进程列表。
备库:
备库上查看pg_stat_wal_receiver视图查看wal接收器进程状态。

复制插槽
背景:
有时候备库在接收到wal段之前,主机就把wal日志给删掉了,比如说主备断开的情况下。oracle这种事情就非常多。
还有一种主库与备库之间有可能会导致恢复冲突的行,主库也会删掉,比如说主备连接断开了。

原来的解决办法:

1. 通过使用wal_keep_segments(保留多少个wal日志文件)和archive_command将这些wal存储到归档目录下,来防止删除旧的wal日志。但是这样通常会导致保留的日志比所需要的的日志多很多的情况。
2. 使用hot_standby_feedback和vacuum_defer_cleanup_age提供保护,可以防止相关行被主库删除,但是前者在主备库无法连接的时候不提供数据的保护,后者通常需要设置较高的值以提供足够的保护。
hot_standby_feedback
备库是否将有关当前备库上执行查询的反馈发送到主库或者自己的上游数据库(级联的情况下);此参数可用于消除,在备库上查询数据没查完,结果主库上把相关记录删了,备库无法查询导致查询取消的问题。但是会导致主库上的数据膨胀还不能vacuum回收
vacuum_defer_cleanup_age
指定一个事务的数量,通过该事务数,vacuum和hot 更新将延迟清除dead line。默认为0事务,这表示主库将尽可能快的删除死行版本,但是有可能备库还需要这些数据进行查询。增大该值可以为备用数据库上的查询留出更多时间来完成。而不会主库删了备库无法查了。但是很难确定该值具体应该是多少,能给备库查询提供多少额外的时间。

为了解决以上的问题,pg推出了复制插槽的概念。
复制插槽完美的避开了上面的两个问题。

功能:

1. 复制插槽提供了一种自动方式,以确保在所有备库都接收到wal段之前,主库不会删除它们,即使主库与所有备库都断开了网络连接。
2. 主库也不会删除可能导致恢复冲突的行。
3. 复制插槽仅保留已知需要的段数,不会多也不会少。
4. 每个备库对应主库上的1个复制槽

查询和操作复制槽

1. 每个复制槽都有一个名称,该名称可以包含小写字母,数字和下划线
2. 在pg_replication_slots视图可以看到现有复制槽及其状态。
3. 可以通过流复制协议或者sql函数来创建删除插槽
流复制协议:https://www.postgresql.org/docs/12/protocol-replication.html
sql函数:https://www.postgresql.org/docs/12/functions-admin.html#FUNCTIONS-REPLICATION

举例:
在主库创建

备库:
primary_conninfo='host=192.168.31.123 port=5432 user=gaorp password='oracle'
primary_slot_name='node_a_slot'

删除复制槽
pg_drop_replication_slot(slot_name name)
From https://www.postgresql.org/docs/12/functions-admin.html

异步复制实操
环境
主: 192.168.31.123 gao
备1:192.168.31.124 standby01
备2:192.168.31.125 standby02
备3:192.168.31.126 standby03
备4:192.168.31.127 standby04

1. 主库做基础备份

2. 备库安装操作系统版本和主库一致,安装postgresql软件,版本和主库一致,安装到postgresql需要initdb为止。比如说本笔记中的“源码编译(自写)”中的1-9步。第10步initdb就不要做了。
3. 主库的基础备份scp到备库,备库的目录结构要跟主库一致,比如说创建自定义表空间目录并赋权啥的,然后恢复该基础备份。
先拷贝

再恢复$PGDATA

再恢复两个自定义表空间gao_ts和jia_ts
首先是gao_ts

然后是jia_ts

归档目录的话,我这里是主库产生两份归档,1份存本地,1份发送给124机器的/pg/pg12/arch目录下,所以基础备份的pg_wal.tar.gz就不用了解压缩复制到/pg/pg12/arch目录下了。
不过这里我们还是解压缩出来,放到/pg/pg12/arch目录下,该目录是我自定义wal归档文件的目录。

这里解压缩出来了3个文件,都拷贝到124机器上的$PGDATA/pg_wal下,如果pg_wal下已经有archive_status目录了就删掉,本例中就有该目录。

现在看看主库上是如何自己本地存一份,还发往备库一份的。
先看看archive_command

再看脚本怎么写的

本脚本就两行,第一行是test这行,本地存储一份;第二行是scp这行,发往124的。
可以删除备机上的这俩文件,没啥用

4. 修改备库的postgresql.conf文件
注释掉archive_command因为我们不想让这个备机产生自己的wal归档。这里archive_mode设置为on,在备机处于后备模式和恢复模式的时候是不会生效的,只有当备机升级成主库才开始产生归档,那个时候你也得改archive_command。

设置下面这两个参数,这里restore_command是必须的,设计上这个备库会用复制槽,所以archive_cleanup_command到不是很必要,你可以设置也可以不设置,我这里设置上了,为了防止以后该备库升级为主库后日志可以自动清理。

其他的recovery参数都注释掉,只开一个下图这个

standby配置里设置2个参数,如下图,primary_conninfo中最后面有三个单引号,需要注意一下。备库这里写主库的复制槽名字,每个备库对应主库1个复制槽。虽然现在主库还没创建standby01_slot复制槽,待会就创建。备库流复制连接主库用的是postgres用户,没有选择新建一个用户去专门管复制。

其他参数比如说wal设置如下,就按照主库的参数来的,这里备机没有更改这些配置。

保存退出,这里备机的postgresql.conf就修改好了。
5. 更改主库的pg_hba.conf,让备库能够流复制连接上。
在主库增加备库124的replication连接设置,并对主库pg_ctl reload。

6. 在主库创建复制槽
连接到哪个数据库都无所谓。


7. 在备库上创建standby.signal文件
在$PGDATA下创建空文件

8. 修改$PGDATA下的/data路径,一定要让该路径是700权限,你给成755,777啥的都不行
chmod 700 $PGDATA/data
当然如果你的路径已经是700权限了就不用改了。
这里放一个主库的data路径的权限图,可供参考。

9. 如果主备库不故障切换,则到这里就设置完成了,如果要主备库故障切换,则备库需要设置pg_hba.conf,并像主库的参数中那样去设置。
10. 打开主备库的log日志(当然这时备库还没有log文件生成),pg_ctl start 备库
11. 确认

主库日志:
可以看到主库上已经有备库的walreceiver连接来要日志了。

124日志:
可以看到已经是开始streaming了

主库查询复制槽
发现复制槽的活跃状态已经变成了t

主库查看进程,发现多了个walsender进程。

备库查看进程已经有了walreceiver接收进程

主库查看:

备库查看:

到这里就结束了,要想监控更多,请看本文章中关于监控的内容。
此时你的主库切换wal日志,124备机的/pg/pg12/arch目录下没有wal日志,而主机中的archive_command中的命令应该还是会把wal日志拷贝到124的/pg/pg12/arch目录下的。但是有archive_cleanup_command的设置,估计被pg_archivecleanup自动删了。因为现在有用复制槽,所以一点wal日志都不缺,那pg_archivecleanup工具就把没用的wal日志都删掉了,也是合乎情理的。此时124备机的$PGDATA/pg_wal目录下还是有4个归档的。应该是留作备库异常崩溃恢复用。

12. 再新增一个异地备库,看看有什么不同

首先主库的archive_command要scp两份,分别给两个备库
主库创建两个复制槽
pg_hba.conf中要有两个备机的授权
其他好像没了,都差不多
此时123为主机,124为备机1,125位备机2,124和125是同级别的关系,星型架构。所有的数据都需要从主库单独发送两份。

级联复制

1. 级联复制允许备用服务器接收复制连接(流复制),并将wal记录流传输到其他备用服务器,充当中继站角色。这可以减少多台备机都与主机的直接连接数,减少使用主机和备机间的网络带宽。
2. 同时充当接收方和发送方的备机被称为级联备用数据库。
3. 与主服务器直接连接的备机称为上游服务器,而距离较远的那些备机称为下游服务器。
4. 下游服务器的数量不限,如何排列不限。
5. 尽管每个备机只能连接到一个上游服务器,但备库一连串的连接最终都是1个连接1个,直到连接到主服务器。
6. 级联复制是异步的,即使你在一个级联体系里设置了同步复制的设置,但是不会起任何作用。
7. 无论级联如何安排备库连接顺序,热备都会向上游传播。
8. 如果将上游备机升级为新主服务器,那你其他下游服务器的recovery_target_timeline一定要设置为latest(不过该参数默认就是latest),则下游服务器将继续从新主库接收流式复制。

配置级联

1. 修改备机的max_wal_senders
2. 修改备机的hot_standby=on(其实默认就是on)
3. 配置上下游服务器的pg_hba.conf
4. 备机的primary_conninfo在下游备用数据库中设置指向上游服务器。
5. 完成

可以看到级联复制很简单,主要是primary_conninfo设置为连接上游服务器(备机)就可以了。

级联复制实操

环境:
此时123为主,124和125为它的异步同步备机。
此时让126级联124机器,形成123主,124为级联备1,125为级联备2;理论上来说这么搞是不会破坏123和124、125之间的异地同步备机关系的。那现在就来试试看。
1. 主库基础备份恢复到126
2. 126的primary_conninfo写124的
3. 126的复制槽用124创建的
4. 124的archive_command把归档日志scp发送给126一份。而124是由主库archive_command scp发送给124的。下图为124 archive_command,前提是你得在124上配置通往126的互信,他俩之间scp发文件不需要密码

5. 这样复制槽和wal归档传输都有了,再修改124的pg_hba.conf允许126访问就可以了。
6. 如果想查看126的上游服务器同步状态啥的,就把124当成主库查就可以了。
7. 其他参数啥的跟搞异步备机一样。

同步复制

pg流复制默认是异步的。如果主库挂了,有些已提交的事务未复制到备机,则数据丢失。所以提出了同步复制。
1. 同步复制提供了确认事务所做的所有更改都已转移到一个或多个同步备用服务器的能力。
2. 当你设置了同步复制,则写入事务的每个提交将一直等待,直到收到确认已将提交写入主和备磁盘上的wal日志的确认消息。
3. 唯一可以丢失数据的可能性是主和所有备机同时数据崩溃。
4. 只读事务和事务回滚无需等待备用服务器的答复
5. 子事务提交不等待备机的回应。
6. 仅仅等待最上层的提交。
7. 长时间的运行操作(例如数据加载copy或索引构建、索引重建)不会等待最后的提交消息。
8. 所有两阶段提交的动作都会造成等待,包括预备和提交。
9. 同步备机可以是物理复制,也可以是逻辑复制。因为pg的程序很智能懂得如何发送恰当的反馈消息。
10. 有些第三方复制的程序,pg也可以支持他们的同步复制。

配置同步复制

配置好流复制后,配置同步复制只需要2个额外的步骤,在主库上设置
1. 设置好synchronous_standby_names就可以了。
synchronous_standby_names参数后面跟的standby_name必须用双引号引起来,而且standby_name应该是备库的primary_conninfo中要设置的参数application_name的值。
比如说主库如下:

这里在举一个standby01是从哪里来的例子
某个同步备机器的primary_conninfo参数如下

其中standby01就是设置的application_name的值。

2. synchronous_commit设置为on(默认就是on)

同步复制原理:

1. 如果照上面1和2这样设置好,将导致每一次提交都等待确认消息,以保证后备服务器已经将提交记录写入到持久化存储中。
2. 在一个提交记录在主库上被写入到磁盘后,wal记录接着被发送到备机,每次一批新的wal数据在备机上被写入磁盘后,备机都会发送给主机回复消息,但是如果你把备机的wal_receiver_status_interval被设置为0的时候,备机将不会给主机回复自己已经完成写入磁盘的消息。
3. 如果主库的synchronous_commit被设置为remote_apply,将导致每一次提交都会等待,直到当前同步后备服务器说它们已经应用了该事务,当提交记录在备库应用后备机将发送回应消息,这会让该事务在备库上可以被查询到。
4. 如果主库的synchronous_commit设置为remote_write将导致每次提交都等待后备服务器已经接收并提交记录并将它写出到其自身所在的操作系统上的确认,但并非等待数据都被写入到后备服务器上的磁盘上。该remote_write的设置提供了比on要弱一些的持久性保障;remote_write这种设置是可能会丢数据的,当主备库操作系统同时崩溃的时候;不过这个参数也是有其意义的,它可以减少事务的响应时间。
5. 如果根据主服务器的synchronous_standby_names设置选中该备机作为一个同步后备,主机将会根据来自该后备服务器和其他同步后备的回应消息来自动决定何时释放正在等待确认提交记录被收到的事务。
6. 同步复制的配置要写在主机上
7. 后备机必须直连到主机上,同步复制不支持级联

多个同步后备

1. 同步复制支持一个或者多个同步后备服务器,主库提交事务,事务将会等待,直到所有同步后备服务器都确认收到了它们的数据为止。
2. 事务必须等待哪些备机回复消息才可以可见,由synchronous_standby_names来决定。这个参数还指定一个后备服务器的名称和方法(FIRST和ANY)的列表从列出的多台后备中选取同步后备。
3. 方法FIRST指定一种基于优先级的同步复制并且让事务处于等待中,知道它们的wal记录被复制到基于优先级选中的所要求数量的同步后备上为止。
4. 在列表中出现较早的后备给予较高的优先级,并且将考虑为同步后备。
5. 其他在这个列表中位置靠后的后备服务器表示可能的同步后备
6. 如果任何当前的同步后备由于任何原因断开网络连接,它将立刻被下一个最高优先级的后备所代替。
7. 方法any指定一种基于规定数量的同步复制并且让事务保持等待,知道它们的wal记录至少被复制到列表中所要求数量的同步后备上为止。
8. 后备服务器同步状态可以使用pg_stat_replication视图查看。该视图的官方介绍:https://www.postgresql.org/docs/12/monitoring-stats.html#PG-STAT-REPLICATION-VIEW

多同步备举例:
FIRST:

下面也可以写成synchronous_standby_names = 'FIRST 2 (s1,s2,s3)'

上面的例子中,如果有四个备机s1,s2,s3,s4都在运行,s1,s2,s3都是同步备,s4是异步备。
本例中两个后备s1和s2将被选中为同步后备,因为他们出现在后备服务器名称列表的前部。
s3是一个潜在的同步后备,当s1和s2中任何一个失效,s3将会取而代之。s4是一个异步备,所以它的名字不在同步备的列表中。

ANY:

在这个例子中,如果有四台备服务器s1、s2、s3、s4正在执行,s1、s2、s3都是同步备,s4是异步备。
本例中事务提交将会等待来自列表中任意两台备机的回复。s4是一台异步后备,所以名字不在同步备列表中。

参数介绍
synchronous_standby_names
官档详细描述为:https://www.postgresql.org/docs/12/runtime-config-replication.html#GUC-SYNCHRONOUS-STANDBY-NAMES
synchronous_commit
官档详细描述为:https://www.postgresql.org/docs/12/runtime-config-wal.html

多同步备实操:
环境:
此时123主,124和125是异步同步备;123、124、126之间是级联复制;
搞成123为主,124、125、126为同步备,直连123主;127为123的异步备;

1. 停止124-126,新做一个备库127
2. 修改124-127的primary_conninfo都指向主库,其中124-126的是同步备用的,127是异步备用的所以他们的primary_conninfo并不一样
同步备124举例:

跟异步备不同的是,同步备要多一个application_name的参数,写上自己的操作系统的主机名,当然你也可以写别的唯一名字。该参数用在后面主库指定的synchronous_standby_names中。
124和125和126是同步备,所以都得这么设置。

异步备127举例:
异步备就简单多了。

3. 主库要新建所有备机的复制槽,每个备机都用123的复制槽。其他多余的复制槽(比如说之前124上有一个126搞级联的时候使用的复制槽)删除。
4. 主库archive_command命令修改为发送归档到每一个备机,同时你要保证123给他们scp发东西不需要输入yes和密码。修改好后重启123。

5. 同时123的pg_hba.conf中要有所有备机的允许设置,pg_ctl reload

6. 修改123主库的synchronous_standby_name参数

这里standby_name必须用双引号引起来,standby01的名字是124机器的primary_conninfo参数中设置的application_name的值,如果不这样设置,那你配出来的是sync_state=async(异步同步的)
7. 启动主库和备库,打开主库和备库的日志,这里先查看主库的log日志

如果你的同步备配置的没问题,那么主库log应该显示上图中的红框中的信息,表示standby01已经是一个sync(同步备模式)的standby了
在本例中,standby01和standby02是同步备,因为我们用了FIRST 2的参数;standby03虽然连上了主库,但是它是一个预备同备库;当standby01和standby02有任意一个挂了,standby03将自动变成同步备。
standby04就是个异备库。
8. 查看主库的视图看看这几个库都是什么状态。

可以看到每个数据库的状态都如我们想的那样。
sync表示同步备
async表示异步备
potential表示此备用服务器现在是异步的,但是如果当前同步服务器之一发生故障,则有可能变为同步服务器。
具体的请查看pg_stat_replication视图https://www.postgresql.org/docs/12/monitoring-stats.html#PG-STAT-REPLICATION-VIEW
还有一个状态是quorum,是ANY模式才会变成这样。
quorum:该备用服务器被认为是仲裁备用的候选服务器。
9. 主库插入数据看看

插入数据很快就提交了,看来主库往备库发送wal数据,需要等待备库接收到数据,应用,提交,把数据存到硬盘上,返回成功消息给主库;这整个流程还是很快的
而且我这是有两个同备库124和125
10. FIRST模式的就做完了。补充一下,主库修改synchronous_standby_name,pg_ctl reload就可以了。备库的primary_conninfo想改还得重启。
11. 现在做ANY模式的。

然后pg_ctl reload就可以了,备库啥的都不用修改。
看看主库的log显示啥

看看主库查询出来是啥

都变成了quorum
12. 主库插入数据看看

也很快,至此any模式也结束了。

故障转移

在某个备库执行这个,就把备库激活成主库了。完成了pg的故障转移。

此时你的主库查询为

standby01已经被激活成主库了,所以主库的复制视图中没有了该信息。
补充
pg并不像oracle那样有switchover和failover,pg只有failover,因为pg的开发团队不如oracle,也没有oracle投入的资金多,所以种种原因吧。

重建备库

当故障转移后,某个备库被启用,当成了主库来使用。此时你需要重建备库,把原来的主库当成备库,且把原来跟主同步的备库,划分为新主库的备库。
pg重建备库可以用两种方法
第一种:使用老方法基础备份+恢复
第二种:用pg_rewind工具。
这里只讨论第二种pg_rewind的用法

1. pg的效果是把目标数据目录替换成源数据目录,关系文件中只有更改过的块才会被拷贝,其他文件会整个拷贝,包括配置文件。
2. pg_rewind工具比基础备份+恢复的有点在于,pg_rewind不要求通过读集簇中未更改的块,这让它在数据库非常大的时候,并且集簇间只有小部分块不同的时候速度非常快。
3. pg_rewind工具通过检查源集簇和目标集簇上的时间线历史文件来判断他们在哪一点分叉了,并且期望在目标集簇的pg_wal目录中找到可用wal来让目标集簇返回到分叉点。
4. 理论上你执行pg_rewind的时候,会自动把源的wal可用文件拷贝到目标的pg_wal目录下。
5. 当目标集簇在分叉后运行了很长时间,以至于旧的wal文件可能已经不存在了,那你可以手工拷贝源wal归档到目标集簇的pg_wal下,或者配置restore_command的时候取得。
6. pg_rewind可用在,想在主库做测试,那就把某个备库故障切换做测试,然后数据倒退回分叉点,再次成为主库的后备。(这点跟oracle dg的备库创建强制闪会点,做完测试再回退到闪会点很像)
7. pg_rewind要求目标服务器在postgres.conf中启用了wal_log_hints选项,full_page_writes必须设置为on

重建备库实操

环境:
目前123为主库,124已经被故障切换。125、126还是主库的同步备,127是123的异步备。
1. 124修改postgresql.conf文件

这里改了这三个值,改完要重启124,然后再关闭124
2. 确保关闭124
pg_ctl stop
确保123是启动状态
3. 在124执行

--target写的是124的路径是啥
--source-server写的是源端连接的是哪个机器
-P是显示详细输入,如上图
4. 由于124$PGDATA整个都是拷贝的123机器的,拷贝完成后postgresql.conf中的参数都跟123一模一样。
所以你的124要想跟123同步,还得更改相关的参数。想让124变为同备库就按同备库的参数设置,想级联和想异步同步同理。
5. 124的参数文件改好后,你还得在$PGDATA下创建standby.signal空文件,否则不行哦。
6. pg_ctl start   124
7. 查看123的复制视图
8. 失败了待补充

1231231231
高可用规划

1. 高可用的最佳方案是有足够数量的同步后备,比如说你有4个备机,3个作为同步备,1个作为异步备;那3个同步备可以用FIRST方法或者ANY方法。
2. 当一个后备服务器第一次加入到主备库体系中时,它处于一种还没完全同步的状态,称为catchup(追赶的意思)状态,该状态可以在pg_stat_replication中查看到,当它第一次跟主库之间的延迟变为0的时候,就变为了实时同步的状态,称为streaming状态。
3. 备库一旦达到streaming状态,就只能称为同步备库了。
4. 如果提交正在等待确认时主库重启,则那些正在等待的事务将在主数据库恢复时被标记为完全提交的。但是这时无法确认所有的后备服务器都收到了主崩溃时所有未处理的wal数据。某些事务可能不会在后备服务器上显示为已提交,即使他们在主库上已经显示为提交。
5. 如果你的同步后备机的数量不够,那应该减少synchronous_standby_names中指定的事务提交应该等待其回应的同步后备的数量,比如说设置为1;或者干脆禁用掉synchronous_standby_names参数。然后reload配置文件。
6. 如果你在主库事务等待的时候要对主库做基础备份,则你的pg_start_backup和pg_stop_backup必须运行在一个synchronous_commit=off的会话中。否则你的基础备份命令将永远等待后备服务器出现。

后备机上的连续归档

一般来说备机使用连续归档的情况有两种。
1. 备机用的wal归档都是主库发过来的,自己不产生归档。级联也是如此,主机的归档发给第一个备,第一个备发给第二个备。
2. 备机即用主库的归档,又自己产生归档。

这里主要探讨第二种情况,即备库即用主库的归档应用,还自己产生归档
当你的备库处于这种情况时,要把archive_mode设置为always,不能设置为on;后备机将在收到每个wal段时调用archive_command命令,不管它是从归档恢复还是使用的流复制。
不过你的备机的archive_command要注意几点,你从主库拷贝过来的wal日志,和自己生成的日志很可能会重名,所以你最好把备库的归档格式改改,改成跟主库不一样的,如果不能改,那你必须在脚本里处理这种情况。不要覆盖具有不同内容的名字相同的wal段文件,如果你是级联那你覆盖了不就下游服务器无法同步了嘛。

你把备机的archive_mode设置为on,备机在恢复模式或者后备模式下并不会产生自己的归档,如果该备机被升级为主库,则开始产生归档。该备机不会产生不是它自身的wal归档。image.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
数据库
使用钉钉扫一扫加入圈子
+ 订阅

分享数据库前沿,解构实战干货,推动数据库技术变革

其他文章