我是一个插槽,今天我做掉了数据库。
一. 什么是复制插槽及优缺点
在没有我的时代(9.4版本之前),管理WAL文件是一个巨大的挑战。在标准的流复制环境中,在主库执行增、删、改所有操做的变更都会记录到WAL文件中,如果主库的事务比较多,每分钟就会产生数GB的WAL文件,WAL文件的名字总是按照数字序号顺序递增,并且默认文件大小总是16MB。WAL的大小在11版本之前只能通过initdb建库指定--wal-segsize设置,而在11版本之后则可以使用pg_resetwal
修改文件大小,参数wal_segment_size
可以查看WAL大小。当主备流复制环境的备库需要停机维护的时候,主库上的WAL文件必须保留住,不然主库做完检查点可能就会回收或者覆盖WAL日志。这样一旦从库维护好了需要恢复,就会遭到巨大的打击,从库会报错requested WAL segment 0000000100000000000000xxx has already been removed。
为了解决这个问题,工程师在9.4版本把我创造出来。我的主要的功能就是记录着备库需要的最老的WAL文件的地址(LSN),这样当主库回收或者覆盖WAL文件的时候,因为我的存在就会比较“克制”的清理。
而没有我的做法就比较low了。他们会选择将wal_keep_segment
参数设置的足够大,以避免WAL日志回收覆盖写,这种方法的缺点就是很难确定设置的值是对的。比如停机维护需要2小时,根据需求设置了保留4小时的量,但是突发一个情况,维护时间变成了6小时,或者此时主库正好做了一个大事务,导致WAL短时间大量增长。这些巧合可能都会击垮设置的wal_keep_segment
参数值。最终可能导致WAL文件再次被覆盖。如果设置的足够高,确实可以解决问题,但是就可能会耗尽pg_wal目录的空间,导致整个数据库hang住。还有一种做法就是设置archive_command
把WAL归档到其他位置,这倒是个好注意。一旦主库的WAL被回收了,还有WAL备份可以进行恢复。
二、取代hot_standby_feedback和vacuum_defer_cleanup_age
而我还有一些作用,就是取代hot_standby_feedback
和vacuum_defer_cleanup_age
。这里我来一一科普。
首先说说hot_standby_feedback
的故事。
有这样一种情况,开发人员或者是程序在备库执行一个较长的查询,此时在主库上有人频繁的做更新或者是删除操作,将会产生大量的dead tuple,当达到了自动auto vacumme设定的阈值,就会清理掉那些dead tuple。此时备库仍然在执行查询,而备库的回放进程应用了主库的vacumme操作时,就会检测出vacumm清理的元组仍然有事务在使用,此时就会认为有冲突错误,它会在等待max_standby_streaming_delay
(默认30秒之后)终止备库上的查询操作,然后输出下列错误信息:
ERROR: canceling statement due to conflict with recovery
Detail: Us