27.4. 热备用#
热备用是用于描述在服务器处于归档恢复或备用模式时连接到服务器并运行只读查询的能力的术语。这对于复制目的和以极高的精度将备份还原到所需状态都非常有用。术语热备用还指服务器从恢复到正常操作的能力,同时用户继续运行查询和/或保持其连接处于打开状态。
在热备用模式下运行查询与正常查询操作类似,但有以下几个使用和管理方面的区别。
27.4.1. 用户概述#
当备用服务器上的hot_standby参数设置为 true 时,一旦恢复将系统恢复到一致状态,它将开始接受连接。所有此类连接都严格为只读;甚至不能写入临时表。
备用服务器上的数据需要一段时间才能从主服务器到达,因此主服务器和备用服务器之间会有可衡量的延迟。因此,在主服务器和备用服务器上几乎同时运行相同的查询可能会返回不同的结果。我们说备用服务器上的数据与主服务器是最终一致的。一旦事务的提交记录在备用服务器上重放,则该事务所做的更改将对在备用服务器上获取的任何新快照可见。快照可以在每个查询的开始或每个事务的开始获取,具体取决于当前的事务隔离级别。有关更多详细信息,请参见第 13.2 节。
在热备用期间启动的事务可以发出以下命令
查询访问:
SELECT
、COPY TO
游标命令:
DECLARE
、FETCH
、CLOSE
设置:
SHOW
、SET
、RESET
事务管理命令
BEGIN
、END
、ABORT
、START TRANSACTION
SAVEPOINT
、RELEASE
、ROLLBACK TO SAVEPOINT
EXCEPTION
块和其他内部子事务
LOCK TABLE
,但仅当明确处于以下模式之一时:ACCESS SHARE
、ROW SHARE
或ROW EXCLUSIVE
。计划和资源:
PREPARE
、EXECUTE
、DEALLOCATE
、DISCARD
插件和扩展:
LOAD
取消监听
热备期间启动的事务永远不会被分配事务 ID,并且无法写入系统预写日志。因此,以下操作将产生错误消息
数据操作语言 (DML):
INSERT
、UPDATE
、DELETE
、MERGE
、COPY FROM
、TRUNCATE
。请注意,没有允许的操作会导致在恢复期间执行触发器。此限制甚至适用于临时表,因为无法在不分配事务 ID 的情况下读取或写入表行,而这在热备环境中当前不可行。数据定义语言 (DDL):
CREATE
、DROP
、ALTER
、COMMENT
。此限制甚至适用于临时表,因为执行这些操作需要更新系统目录表。SELECT ... FOR SHARE | UPDATE
,因为无法在不更新基础数据文件的情况下获取行锁。生成 DML 命令的
SELECT
语句的规则。LOCK
明确请求高于ROW EXCLUSIVE MODE
的模式。短默认形式的
LOCK
,因为它请求ACCESS EXCLUSIVE MODE
。明确设置非只读状态的事务管理命令
BEGIN READ WRITE
、START TRANSACTION READ WRITE
SET TRANSACTION READ WRITE
、SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE
SET transaction_read_only = off
两阶段提交命令:
PREPARE TRANSACTION
、COMMIT PREPARED
、ROLLBACK PREPARED
,因为即使是只读事务也需要在准备阶段(两阶段提交的第一阶段)写入 WAL。序列更新:
nextval()
、setval()
LISTEN
、NOTIFY
在正常操作中,““只读””事务可以使用LISTEN
和NOTIFY
,因此热备会话的操作限制比普通只读会话略微严格。未来版本中可能会放宽其中一些限制。
在热备期间,参数transaction_read_only
始终为 true,并且不能更改。但是,只要不尝试修改数据库,热备期间的连接就会像任何其他数据库连接一样。如果发生故障转移或切换,数据库将切换到正常处理模式。会话将在服务器更改模式时保持连接。热备完成后,可以启动读写事务(即使是从热备期间开始的会话)。
用户可以通过发出SHOW in_hot_standby
来确定当前会话是否已激活热备用。(在 14 之前的服务器版本中,in_hot_standby
参数不存在;适用于较旧服务器的可行替代方法是SHOW transaction_read_only
。)此外,一组函数(表 9.92)允许用户访问有关备用服务器的信息。这些函数允许您编写了解数据库当前状态的程序。这些程序可用于监控恢复进度,或允许您编写将数据库恢复到特定状态的复杂程序。
27.4.2. 处理查询冲突#
主服务器和备用服务器在很多方面是松散连接的。主服务器上的操作会对备用服务器产生影响。因此,主服务器和备用服务器之间可能会出现负面交互或冲突。最容易理解的冲突是性能:如果主服务器上正在进行大量数据加载,那么这将在备用服务器上生成类似的 WAL 记录流,因此备用查询可能会争用系统资源,例如 I/O。
热备用还可能发生其他类型的冲突。这些冲突是硬冲突,因为可能需要取消查询,在某些情况下,需要断开会话才能解决这些冲突。为用户提供了多种处理这些冲突的方法。冲突案例包括
在主服务器上获取的独占锁,包括显式
LOCK
命令和各种 操作,与备用查询中的表访问冲突。在主服务器上删除表空间与使用该表空间作为临时工作文件的备用查询冲突。
在主服务器上删除数据库与在备用服务器上连接到该数据库的会话冲突。
从 WAL 应用真空清理记录与备用事务冲突,备用事务的快照仍然可以 “看到”任何要删除的行。
从 WAL 冲突中清理真空记录的应用程序与访问备用服务器上目标页面的查询冲突,无论要删除的数据是否可见。
在主服务器上,这些情况只会导致等待;用户可以选择取消任一冲突操作。然而,在备用服务器上没有选择:WAL 记录的操作已在主服务器上发生,因此备用服务器不能不应用它。此外,允许 WAL 应用程序无限期等待可能非常不受欢迎,因为备用服务器的状态将越来越落后于主服务器。因此,提供了一种机制来强制取消与待应用 WAL 记录冲突的备用查询。
问题情况的一个示例是主服务器上的管理员对备用服务器上当前正在查询的表运行DROP TABLE
。显然,如果在备用服务器上应用DROP TABLE
,则备用查询无法继续。如果这种情况发生在主服务器上,则DROP TABLE
将等待其他查询完成。但是,当在主服务器上运行DROP TABLE
时,主服务器没有关于备用服务器上正在运行哪些查询的信息,因此它不会等待任何此类备用查询。WAL 更改记录在备用查询仍在运行时会传送到备用服务器,从而导致冲突。备用服务器必须延迟应用 WAL 记录(以及它们之后的所有内容),或者取消冲突的查询,以便可以应用DROP TABLE
。
当一个冲突查询很短时,通常最好允许它完成,方法是稍微延迟 WAL 应用;但通常不希望 WAL 应用延迟很长时间。因此,取消机制具有参数max_standby_archive_delay和max_standby_streaming_delay,它们定义了 WAL 应用中允许的最大延迟。一旦应用任何新接收的 WAL 数据花费的时间超过相关延迟设置,冲突查询将被取消。有两个参数,以便可以为从归档中读取 WAL 数据(即,从基本备份中进行初始恢复或“赶上”远远落后的备用服务器)的情况指定不同的延迟值,而不是通过流复制读取 WAL 数据。
对于主要用于高可用性的备用服务器,最好将延迟参数设置得相对较短,以便服务器不会因备用查询引起的延迟而远远落后于主服务器。但是,如果备用服务器用于执行长时间运行的查询,则可能更喜欢较高的甚至无限的延迟值。但是,请记住,如果长时间运行的查询延迟了 WAL 记录的应用,则它可能会导致备用服务器上的其他会话看不到主服务器上的近期更改。
一旦超过max_standby_archive_delay
或max_standby_streaming_delay
指定的延迟,冲突查询将被取消。这通常只会导致取消错误,尽管在重放DROP DATABASE
的情况下,整个冲突会话将被终止。此外,如果冲突是关于空闲事务持有的锁,则冲突会话将被终止(此行为将来可能会更改)。
取消的查询可以立即重试(当然,在开始新事务后)。由于查询取消取决于正在重放的 WAL 记录的性质,因此,如果重新执行,则被取消的查询很可能会成功。
请记住,延迟参数与备用服务器收到 WAL 数据以来的经过时间进行比较。因此,备用服务器上任何一个查询允许的宽限期永远不会超过延迟参数,并且如果备用服务器已经因等待先前的查询完成或无法跟上繁重的更新负载而落后,则宽限期可能会大大缩短。
备用查询和 WAL 重放之间发生冲突的最常见原因是“早期清理”。通常,PostgreSQL允许在没有事务需要查看旧行版本以确保根据 MVCC 规则正确查看数据时清理这些旧行版本。但是,此规则仅可应用于在主服务器上执行的事务。因此,主服务器上的清理可能会删除备用服务器上的事务仍然可见的行版本。
行版本清理并不是与备用查询发生冲突的唯一潜在原因。所有仅限索引的扫描(包括在备用服务器上运行的扫描)都必须使用与可见性映射“一致”的MVCC快照。因此,每当VACUUM
将页面设置为可见性映射中的全可见,其中包含一行或多行时,都会发生冲突,而所有备用查询不可见这些行。因此,即使对没有需要清理的已更新或已删除行运行VACUUM
,也可能导致冲突。
用户应该清楚,在主服务器上定期大量更新的表将很快导致备用服务器上运行时间较长的查询被取消。在这种情况下,为max_standby_archive_delay
或max_standby_streaming_delay
设置有限值可以认为类似于设置statement_timeout
。
如果备用查询取消的数量被发现不可接受,则存在补救措施。第一个选项是设置参数hot_standby_feedback
,这将阻止VACUUM
删除最近死亡的行,因此不会发生清理冲突。如果您这样做,您应该注意这将延迟主服务器上死亡行的清理,这可能会导致不希望的表膨胀。但是,清理情况不会比备用查询直接在主服务器上运行时更糟,并且您仍然可以从将执行卸载到备用服务器中受益。如果备用服务器频繁连接和断开连接,您可能需要进行调整以处理未提供hot_standby_feedback
反馈的时期。例如,考虑增加max_standby_archive_delay
,以便在断开连接期间 WAL 存档文件中的冲突不会快速取消查询。您还应该考虑增加max_standby_streaming_delay
,以避免重新连接后新到达的流式 WAL 条目快速取消查询。
可以在备用服务器上使用pg_stat_database_conflicts
系统视图查看查询取消的数量及其原因。pg_stat_database
系统视图还包含摘要信息。
当 WAL 重放等待冲突的时间超过deadlock_timeout
时,用户可以控制是否生成日志消息。这由log_recovery_conflict_waits参数控制。
27.4.3. 管理员概述#
如果hot_standby
在postgresql.conf
中为on
(默认值),并且存在standby.signal
文件,则服务器将以热备用模式运行。但是,可能需要一些时间才能允许热备用连接,因为服务器在完成足够的恢复以提供查询可以运行的一致状态之前不会接受连接。在此期间,尝试连接的客户端将被拒绝并显示错误消息。要确认服务器已启动,请循环尝试从应用程序连接,或在服务器日志中查找以下消息
LOG: entering standby mode
... then some time later ...
LOG: consistent recovery state reached
LOG: database system is ready to accept read-only connections
一致性信息在主服务器上每次检查点记录一次。当读取在wal_level
未在主服务器上设置为replica
或logical
的时间段内编写的 WAL 时,无法启用热备用。在满足以下这两个条件的情况下,达到一致状态也可能会延迟
写事务有超过 64 个子事务
持续时间很长的写事务
如果您正在运行基于文件的日志传送(“热备用”),则可能需要等到下一个 WAL 文件到达,该文件可能与主服务器上的archive_timeout
设置一样长。
某些参数的设置决定了用于跟踪事务 ID、锁和已准备事务的共享内存的大小。为了确保备用服务器在恢复期间不会用尽共享内存,备用服务器上的这些共享内存结构必须不小于主服务器上的共享内存结构。例如,如果主服务器使用了已准备事务,但备用服务器未分配任何共享内存来跟踪已准备事务,则在更改备用服务器的配置之前,恢复将无法继续。受影响的参数为
max_connections
max_prepared_transactions
max_locks_per_transaction
max_wal_senders
max_worker_processes
确保这不成为问题的最简单方法是将这些参数在备用服务器上设置为等于或大于主服务器上的值。因此,如果您想增加这些值,您应该先在所有备用服务器上这样做,然后再将更改应用到主服务器。相反,如果您想降低这些值,您应该先在主服务器上这样做,然后再将更改应用到所有备用服务器。请记住,当备用服务器被提升时,它将成为后续备用服务器所需参数设置的新参考。因此,为了避免在切换或故障转移期间出现此问题,建议在所有备用服务器上保持这些设置相同。
WAL 跟踪主服务器上这些参数的更改。如果热备用服务器处理的 WAL 指示主服务器上的当前值高于其自身的值,它将记录警告并暂停恢复,例如
WARNING: hot standby is not possible because of insufficient parameter settings
DETAIL: max_connections = 80 is a lower setting than on the primary server, where its value was 100.
LOG: recovery has paused
DETAIL: If recovery is unpaused, the server will shut down.
HINT: You can then restart the server after making the necessary configuration changes.
此时,需要更新备用服务器上的设置并重新启动实例,然后才能继续恢复。如果备用服务器不是热备用服务器,那么当它遇到不兼容的参数更改时,它将立即关闭而不暂停,因为此时没有必要保持其运行。
管理员为max_standby_archive_delay和max_standby_streaming_delay选择适当的设置非常重要。最佳选择因业务优先级而异。例如,如果服务器主要用作高可用性服务器,那么您将需要低延迟设置,甚至可能是零,尽管这是一个非常激进的设置。如果备用服务器用作决策支持查询的附加服务器,那么可以将最大延迟值设置为很多小时,甚至 -1,这意味着永远等待查询完成。
在主服务器上写入的事务状态“提示位”不会记录在 WAL 中,因此备用服务器上的数据可能会在备用服务器上再次重写提示。因此,即使所有用户都是只读的,备用服务器仍会执行磁盘写入;数据值本身不会发生任何更改。用户仍会写入大型排序临时文件并重新生成 relcache 信息文件,因此在热备用模式下,数据库的任何部分都不是真正的只读。另外请注意,即使事务在本地是只读的,仍然可以使用dblink模块写入远程数据库,以及使用 PL 函数在数据库外部执行其他操作。
在恢复模式下不接受以下类型的管理命令
数据定义语言 (DDL):例如,
CREATE INDEX
权限和所有权:
GRANT
、REVOKE
、REASSIGN
维护命令:
ANALYZE
、VACUUM
、CLUSTER
、REINDEX
同样,请注意,其中一些命令实际上在主服务器上的“只读”模式事务期间是允许的。
因此,您无法创建仅存在于备用服务器上的其他索引,也无法创建仅存在于备用服务器上的统计信息。如果需要这些管理命令,则应在主服务器上执行它们,最终这些更改将传播到备用服务器。
pg_cancel_backend()
和pg_terminate_backend()
将在用户后端上运行,但不会在执行恢复的启动进程中运行。pg_stat_activity
不会将恢复事务显示为活动事务。因此,pg_prepared_xacts
在恢复期间始终为空。如果您希望解决有疑问的已准备事务,请在主服务器上查看pg_prepared_xacts
并发出命令来解决事务,或在恢复结束之后解决它们。
pg_locks
将显示后端持有的锁,这很正常。pg_locks
还显示由启动进程管理的一个虚拟事务,它拥有正在由恢复重放的事务持有的所有AccessExclusiveLocks
。请注意,启动进程不会获取锁来进行数据库更改,因此AccessExclusiveLocks
以外的锁不会在启动进程的pg_locks
中显示;它们只是被假定存在。
Nagios插件check_pgsql将会正常工作,因为它检查的简单信息存在。check_postgres监控脚本也将正常工作,尽管一些报告的值可能会给出不同的或令人困惑的结果。例如,上次真空时间将不会被维护,因为备用服务器上不会发生真空。在主服务器上运行的真空仍然会将它们的更改发送到备用服务器。
WAL 文件控制命令在恢复期间将不起作用,例如,pg_backup_start
、pg_switch_wal
等。
动态可加载模块可以工作,包括pg_stat_statements
。
咨询锁在恢复期间正常工作,包括死锁检测。请注意,咨询锁永远不会被 WAL 记录,因此主服务器或备用服务器上的咨询锁不可能与 WAL 重放冲突。也不可能在主服务器上获取咨询锁并让它在备用服务器上启动类似的咨询锁。咨询锁仅与获取它们的服务器相关。
基于触发器的复制系统,例如Slony、Londiste和Bucardo,根本不会在备用服务器上运行,尽管只要更改不被发送到备用服务器以应用,它们将在主服务器上愉快地运行。WAL 重放不是基于触发器的,因此您无法从备用服务器中继到任何需要其他数据库写入或依赖于触发器使用的系统。
无法分配新的 OID,尽管一些UUID生成器可能仍然可以工作,只要它们不依赖于向数据库写入新状态。
目前,在只读事务期间不允许创建临时表,因此在某些情况下,现有脚本将无法正确运行。此限制可能会在以后的版本中放宽。这既是一个 SQL 标准合规性问题,也是一个技术问题。
DROP TABLESPACE
只有在表空间为空时才能成功。一些备用用户可能正在通过他们的temp_tablespaces
参数主动使用表空间。如果表空间中有临时文件,则所有活动查询都会被取消以确保删除临时文件,以便可以删除表空间并继续 WAL 重放。
在主服务器上运行DROP DATABASE
或ALTER DATABASE ... SET TABLESPACE
将生成一个 WAL 条目,该条目将导致连接到备用服务器上该数据库的所有用户被迫断开连接。此操作会立即发生,无论max_standby_streaming_delay
的设置如何。请注意,ALTER DATABASE ... RENAME
不会断开用户连接,在大多数情况下这将不会被注意到,尽管在某些情况下,如果程序以某种方式依赖于数据库名称,则可能会导致程序混乱。
在正常(非恢复)模式下,如果您在用户仍然连接时为具有登录功能的角色发出DROP USER
或DROP ROLE
,则连接的用户不会发生任何情况——他们仍然保持连接。但是,用户无法重新连接。此行为也适用于恢复,因此主服务器上的DROP USER
不会断开备用服务器上的该用户连接。
累积统计系统在恢复期间处于活动状态。所有扫描、读取、块、索引使用等都将在备用服务器上正常记录。但是,WAL 重放不会增加关系和数据库特定计数器。即重放不会增加 pg_stat_all_tables 列(如 n_tup_ins),启动进程执行的读取或写入也不会在 pg_statio 视图中进行跟踪,也不会增加关联的 pg_stat_database 列。
自动清理在恢复期间不处于活动状态。它将在恢复结束时正常启动。
检查点进程和后台写入进程在恢复期间处于活动状态。检查点进程将执行重新启动点(类似于主服务器上的检查点),而后台写入进程将执行正常的块清理活动。这可能包括备用服务器上存储的提示位信息的更新。在恢复期间接受CHECKPOINT
命令,尽管它执行重新启动点,而不是新的检查点。
27.4.4. 热备用参数参考#
上面在第 27.4.2 节和第 27.4.3 节中提到了各种参数。
在主服务器上,可以使用wal_level参数。如果在主服务器上设置,max_standby_archive_delay和max_standby_streaming_delay不起作用。
在备用服务器上,可以使用参数hot_standby、max_standby_archive_delay和max_standby_streaming_delay。
27.4.5. 注意事项#
热备用有一些限制。这些限制在将来的版本中可能会得到修复
在拍摄快照之前,需要充分了解正在运行的事务。使用大量子事务(当前大于 64)的事务将延迟只读连接的启动,直到最长的正在写入的事务完成。如果出现这种情况,将向服务器日志发送解释性消息。
备用查询的有效起始点在主服务器上的每个检查点生成。如果在主服务器处于关闭状态时关闭备用服务器,则可能无法重新进入热备用状态,直到主服务器启动,以便在 WAL 日志中生成更多起始点。在最常见的可能发生这种情况的情况下,这种情况并不是问题。通常,如果主服务器关闭并且不再可用,则可能是由于严重故障,需要将备用服务器转换为以新主服务器身份运行。在故意关闭主服务器的情况下,协调以确保备用服务器顺利成为新主服务器也是标准程序。
在恢复结束时,准备好的事务持有的
AccessExclusiveLocks
将需要两倍于正常数量的锁表条目。如果您计划运行大量通常获取AccessExclusiveLocks
的并发准备好的事务,或者计划拥有一个获取许多AccessExclusiveLocks
的大型事务,建议您选择一个较大的max_locks_per_transaction
值,可能达到主服务器上参数值的两倍。如果您的max_prepared_transactions
设置为 0,则根本无需考虑这一点。热备用中尚未提供可串行化事务隔离级别。(有关详细信息,请参见 第 13.2.3 节 和 第 13.4.1 节。)尝试在热备用模式下将事务设置为可串行化隔离级别将生成错误。