目录
PostgreSQL实战之物理复制和逻辑复制(六)
6 延迟备库
6.1 延迟备库的意义
6.2 延迟备库部署
6.3 recovery_min_apply_delay参数对同步复制的影响
PostgreSQL实战之物理复制和逻辑复制(六)
6 延迟备库
延迟备库是指可以配置备库和主库的延迟时间,这样备库始终和主库保持指定时间的延迟,例如设置备库和主库之间的延迟时间为1小时,理论上备库和主库的延时始终保持在一小时左右。
6.1 延迟备库的意义
PostgreSQL流复制环境下,如果主库不是很忙并且备库硬件资源充分,通常备库和主库的延时能在毫秒级别。如果主库上由于误操作删除了表数据或删除表时,从库上的这些数据也瞬间被删除了,这时,即使对数据库做了备份,要恢复到删除前的状态也是有难度的,比如,如果使用pg_dump做了逻辑备份,通常是按天、按周、按月进行逻辑备份等,也只能恢复到最近逻辑备份时刻的数据,除非是做了基准备份并且开了归档,这时可以利用全量备份和归档恢复到删除前的状态,从而找回被删除的数据,当然这种方法维护成本较高。在这一场景下,延迟的备库在一定程度上缓解了这一问题,因为在设置的延迟时间范围内,备库上的数据还没被删除,可以在备库上找回这些数据,这节将详细介绍延迟备库的配置和使用,当然,如果超过了已设置的主备延迟时间才发现主库上的数据被删除了,这些数据在备库也找不回来了。
6.2 延迟备库部署
测试环境依然为一主一备异步流复制,pghost1为主库,pghost2为备库,延迟备库的配置非常简单,只需要配置recovery_min_apply_delay参数,此参数位于recovery.conf配置文件,语法如下:
recovery_min_apply_delay (integer)
此参数单位默认为毫秒,目前支持的时间单位如下:
ms(毫秒,默认单位)
s (秒)
min (分钟)
h (小时)
d (天)
大家知道流复制主库提交事务后,主库会将此事务的WAL日志流发送给备库,备库接收WAL日志流后进行重做,这个操作通常瞬间完成,延迟的备库实际上是设置备库延迟重做WAL的时间,而备库依然及时接收主库发送的WAL日志流,只是不是一接收到WAL后就立即重做,而是等待设置的时间再重做,假如设置此参数为一分钟,流复制备库接收到主库发送WAL日志流后需等待一分钟才重做。
我们将pghost2上备库的此参数设置成1分钟,如下所示:
recovery_min_apply_delay = 1min
以上代码将主库和备库的延迟时间设置为1分钟,之后重启备库使配置生效,如下所示:
[postgresepghost2 pg_root]$ pg_ctl restart
之后在主库上创建test_delay测试表,如下所示:
postgres=# CREATE TABLE test_delay(id int4,create_time timestamp(0) without time zone) ;
CREATE TABLE
这时备库上等了大概一分钟才看到这张表,接着在主库上插人一条数据,如下所示:
postgres=# INSERT INTO test_delay(id,create_time) VALOES (1,now()) ;
INSERT 0 1
在备库查询表test_delay数据,一开始返回为空,反复执行以下SQL直到返回以下数据:
postgres=# SELECT now() , create_time FROM test_delay;
-[ RECORD 1 ]------------------------------
now | 2017-09-10 16:18:50.414074+08
create_time | 2017-09-10 16:17:50
从以上时间看出正好相差一分钟,也就是说主库插入这条数据后,过了一分钟左右备库才能查询到这条数据。
接着模拟数据误删场景,假如由于误操作误删了这张表,是否能在备库找回数据?主库上删除这张表,如下所示:
postgres=# DROP TABLE test_delay ;
DROP TABLE
尽管主库删除了此表,但从库上这张表依然存在,并且数据也存在,如下所示:
postgres=# SELECT * FROM test_delay;
id | create_time
----+------------------
1 | 2017-09-10 16:17:50
(1 row)
这样,可以在延迟时间窗口内将表test_delay的表结构和数据进行备份,再导入到主库,从而找回误删除的表。
6.3 recovery_min_apply_delay参数对同步复制的影响
recovery_min_apply_delay参数对同步复制影响如何?大家知道同步复制synchronous_commit参数需配置成on或者remote_apply,on选项意思是主库上提交的事务后会等待备库接收WAL日志流并写入WAL日志文件后再向客户端返回成功,remote_apply则更进一步,主库上提交的事务后会等待备库接收WAL日志流并写入WAL日志文件同时应用完成WAL日志流后再向客户端返回成功。
这里对延迟备库场景下synchronous_commit配置为on和remote_apply的差异进行测试。
场景一:synchronous_commit配置为on,同时recovery_min_apply_delay配置成1分钟。
synchronous_commit参数调整完后需要执行pg_ctl reload重新载入配置使参数生效,同时recovery_min_apply_delay 配置调整后需要重启备库使配置生效。
测试前先在主库上清空表test_delay数据,之后在主库上插入一条数据,如下所示:
postgres=# INSERT INTO test_delay(id,create_time)VALUES(1,now());
INSERT 0 1
之后在备库上查询这条记录,依然需要一分钟之后这条数据才能查询到,如下所示:
postgres=# SELECT now ( ) ,create_time FROM test_delay;
-[ RECORD 1 ]-------------------------------
now | 2017-09-10 16:58:22.526087+08
create_time | 2017-09-10 16:57:22
也就是说延迟备库场景,synchronous_commit配置为on时和异步流复制一致。
场景二:synchronous_commit配置为remote_apply,同时recovery_min_apply_delay配置成1分钟。
主库上执行以下SQL,向test_delay表中插入一条数据,如下所示:
postgres=# INSERT INTo test_delay(id,create_time) VALUES(2,now()) ;--注意这条命令被阻塞
这时发现SQL处于阻塞状态,我们把SQL计时器打开,看看等了多久,主库上再插入一条数据,如下所示:
postgres=# \timing
Timing is on.
postgres=# INSERT INTO test_delay(id,create_time)VALUES (3,now()) ;
INSERT 0 1
Time: 60008.295 ms (01:00.008)
以上看出,SQL执行时间为60秒,一条普通的INSERT语句需要执行60秒的原因,根据synchronous_commit参见remote_apply选项的解释,因为主库提交INSERT语句后,会等待同步备库接收这条INSERT语句的WAL日志流并且写入备库WAL日志文件,同时备库完成应用WAL使得这条记录在备库可见后主库才向客户端返回成功,而此时同步备库又设置了WAL应用延迟一分钟,了解了这些原理之后,对于以上两个测试场景的差异就很好理解了。
根据以上测试,对于延迟备库场景,synchronous_commit配置为on时和异步流复制一致,synchronous_commit配置为remote_apply时,主库上所有的写操作将被阻塞一定时间,被阻塞的时间正好是同步备库recovery_min_apply_delay参数配置值,因此synchronous_commit参数配置为remote_apply 的同步流复制环境应避免使用延迟备库。