支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0

26.4. 热备 #

热备是指当服务器处于归档恢复或备用模式时,连接到服务器并运行只读查询的能力。这对于复制目的以及将备份精确地恢复到所需状态都很有用。热备这个术语还指服务器在用户继续运行查询和/或保持其连接打开的情况下,从恢复移动到正常操作的能力。

在热备模式下运行查询与正常的查询操作类似,尽管下面解释了几个使用和管理上的差异。

26.4.1. 用户概述 #

当备用服务器上的 hot_standby 参数设置为 true 时,一旦恢复将系统带到一致状态,它将开始接受连接。所有此类连接都是严格只读的;甚至不允许写入临时表。

备用服务器上的数据需要一些时间才能从主服务器到达,因此主服务器和备用服务器之间会存在可衡量的延迟。因此,几乎同时在主服务器和备用服务器上运行相同的查询可能会返回不同的结果。我们说备用服务器上的数据与主服务器是最终一致的。一旦事务的提交记录在备用服务器上重放,该事务进行的更改将对备用服务器上任何新的快照可见。快照可以在每个查询开始时或每个事务开始时获取,具体取决于当前的事务隔离级别。有关更多详细信息,请参阅第 13.2 节

在热备期间开始的事务可能会发出以下命令

  • 查询访问:SELECTCOPY TO

  • 游标命令:DECLAREFETCHCLOSE

  • 设置:SHOWSETRESET

  • 事务管理命令

    • BEGINENDABORTSTART TRANSACTION

    • SAVEPOINTRELEASEROLLBACK TO SAVEPOINT

    • EXCEPTION 代码块和其他内部子事务

  • LOCK TABLE,但仅限于显式使用以下模式之一:ACCESS SHAREROW SHAREROW EXCLUSIVE

  • 计划和资源:PREPAREEXECUTEDEALLOCATEDISCARD

  • 插件和扩展:LOAD

  • UNLISTEN

在热备期间启动的事务永远不会被分配事务 ID,并且不能写入系统预写日志。因此,以下操作将产生错误消息

  • 数据操作语言 (DML):INSERTUPDATEDELETEMERGECOPY FROMTRUNCATE。请注意,在恢复期间不允许执行任何导致触发器执行的操作。此限制甚至适用于临时表,因为如果不分配事务 ID,则无法读取或写入表行,而这在热备环境中目前是不可能的。

  • 数据定义语言 (DDL):CREATEDROPALTERCOMMENT。此限制甚至适用于临时表,因为执行这些操作将需要更新系统目录表。

  • SELECT ... FOR SHARE | UPDATE,因为如果不更新底层数据文件,则无法获取行锁。

  • 关于生成 DML 命令的 SELECT 语句的规则。

  • LOCK 显式请求高于 ROW EXCLUSIVE MODE 的模式。

  • LOCK 以简短的默认形式,因为它请求 ACCESS EXCLUSIVE MODE

  • 显式设置非只读状态的事务管理命令

    • BEGIN READ WRITESTART TRANSACTION READ WRITE

    • SET TRANSACTION READ WRITESET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE

    • SET transaction_read_only = off

  • 两阶段提交命令:PREPARE TRANSACTIONCOMMIT PREPAREDROLLBACK PREPARED,因为即使是只读事务也需要在准备阶段(两阶段提交的第一阶段)写入 WAL。

  • 序列更新:nextval()setval()

  • LISTENNOTIFY

在正常操作中,只读事务允许使用 LISTENNOTIFY,因此热备会话的操作比普通的只读会话受到略微严格的限制。将来可能会放宽其中一些限制。

在热备期间,参数 transaction_read_only 始终为 true 并且可能不会更改。但是,只要不尝试修改数据库,热备期间的连接行为就与任何其他数据库连接非常相似。如果发生故障切换或切换,数据库将切换到正常处理模式。当服务器更改模式时,会话将保持连接。一旦热备完成,就可以启动读写事务(即使是从热备期间开始的会话)。

用户可以通过发出 SHOW in_hot_standby 来确定其会话当前是否处于活动热备状态。(在 14 之前的服务器版本中,不存在 in_hot_standby 参数;对于较旧的服务器,可行的替代方法是 SHOW transaction_read_only。)此外,一组函数(表 9.96)允许用户访问有关备用服务器的信息。这些函数允许您编写能够感知数据库当前状态的程序。它们可以用于监视恢复进度,或允许您编写将数据库恢复到特定状态的复杂程序。

26.4.2. 处理查询冲突 #

主服务器和备用服务器在很多方面是松散连接的。主服务器上的操作将对备用服务器产生影响。因此,它们之间存在负面交互或冲突的可能性。最容易理解的冲突是性能:如果主服务器上正在进行大量数据加载,则会在备用服务器上生成类似的 WAL 记录流,因此备用查询可能会争夺系统资源,例如 I/O。

热备还可能发生其他类型的冲突。这些冲突是硬冲突,因为可能需要取消查询,并且在某些情况下需要断开会话才能解决冲突。用户可以使用多种方法来处理这些冲突。冲突情况包括

  • 在主服务器上获取的独占访问锁,包括显式 LOCK 命令和各种DDL操作,与备用查询中的表访问冲突。

  • 在主服务器上删除表空间会与备用查询使用该表空间进行临时工作文件发生冲突。

  • 在主服务器上删除数据库会与备用服务器上连接到该数据库的会话发生冲突。

  • 从 WAL 应用清理记录的 vacuum 操作会与备用事务的快照仍然可以看到任何要删除的行发生冲突。

  • 从 WAL 应用清理记录的 vacuum 操作会与访问备用服务器上目标页面的查询发生冲突,无论要删除的数据是否可见。

在主服务器上,这些情况只会导致等待;用户可以选择取消任何冲突的操作。但是,在备用服务器上,别无选择:WAL 记录的操作已经在主服务器上发生,因此备用服务器不得未能应用它。此外,允许 WAL 应用无限期等待可能是非常不可取的,因为备用服务器的状态将越来越落后于主服务器。因此,提供了一种机制来强制取消与要应用的 WAL 记录冲突的备用查询。

一个问题情况的例子是,主服务器上的管理员对备用服务器上当前正在查询的表执行 DROP TABLE 操作。显然,如果 DROP TABLE 应用于备用服务器,则备用查询将无法继续。如果这种情况发生在主服务器上,DROP TABLE 将等待其他查询完成后再执行。但是,当 DROP TABLE 在主服务器上运行时,主服务器没有关于备用服务器上正在运行的查询的信息,因此它不会等待任何此类备用查询。WAL 更改记录在备用查询仍在运行时到达备用服务器,从而导致冲突。备用服务器必须延迟 WAL 记录的应用(以及它们之后的所有内容),或者取消冲突的查询,以便可以应用 DROP TABLE

当冲突查询很短时,通常希望通过稍微延迟 WAL 应用来允许其完成;但是,长时间延迟 WAL 应用通常是不希望的。因此,取消机制具有参数,max_standby_archive_delaymax_standby_streaming_delay,它们定义了 WAL 应用中允许的最大延迟。一旦应用任何新接收的 WAL 数据所花费的时间超过相关延迟设置,冲突的查询将被取消。有两个参数,以便可以为从归档读取 WAL 数据(即,从基本备份或 追赶一个落后太多的备用服务器进行初始恢复)与通过流复制读取 WAL 数据的情况指定不同的延迟值。

在主要用于高可用性的备用服务器中,最好将延迟参数设置得相对较短,这样服务器就不会因为备用查询导致的延迟而远远落后于主服务器。但是,如果备用服务器用于执行长时间运行的查询,则可能更希望使用高延迟值甚至无限延迟值。但是请记住,如果长时间运行的查询延迟了 WAL 记录的应用,则可能会导致备用服务器上的其他会话看不到主服务器上的最新更改。

一旦超过了 max_standby_archive_delaymax_standby_streaming_delay 指定的延迟,冲突的查询将被取消。这通常只会导致取消错误,尽管在重放 DROP DATABASE 时,整个冲突会话将被终止。此外,如果冲突是关于由空闲事务持有的锁,则冲突会话将被终止(此行为将来可能会更改)。

取消的查询可能会立即重试(当然,在开始新的事务之后)。由于查询取消取决于正在重放的 WAL 记录的性质,因此如果再次执行被取消的查询,则很可能会成功。

请记住,延迟参数是与备用服务器接收 WAL 数据后经过的时间进行比较的。因此,允许备用服务器上任何一个查询的宽限期永远不会超过延迟参数,并且如果备用服务器由于等待先前查询完成而已经落后,或者由于无法跟上繁重的更新负载而已经落后,则可能会明显缩短。

备用查询和 WAL 重放之间冲突的最常见原因是提前清理。通常,PostgreSQL 允许在没有事务需要查看旧行版本的情况下清理它们,以确保根据 MVCC 规则正确显示数据。但是,此规则只能应用于在主服务器上执行的事务。因此,主服务器上的清理可能会删除备用服务器上事务仍然可见的行版本。

行版本清理不是导致与备用查询冲突的唯一潜在原因。所有仅索引扫描(包括在备用服务器上运行的扫描)都必须使用一个MVCC快照,该快照与可见性映射一致。因此,每当 VACUUM 在包含一个或多个对所有备用查询不可见的行的可见性映射中将页面设置为全部可见时,都需要发生冲突。因此,即使对没有需要清理的更新或删除行的表运行 VACUUM 也可能导致冲突。

用户应该清楚,在主服务器上定期且大量更新的表将很快导致备用服务器上较长时间运行的查询被取消。在这种情况下,将 max_standby_archive_delaymax_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 参数控制。

26.4.3. 管理员概述 #

如果 hot_standbypostgresql.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 未设置为 replicalogical 期间写入的 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_delaymax_standby_streaming_delay 选择适当的设置。最佳选择因业务优先级而异。例如,如果服务器的主要任务是高可用性服务器,则您将需要低延迟设置,甚至为零,尽管这是一个非常激进的设置。如果备用服务器的任务是作为决策支持查询的附加服务器,则可以将最大延迟值设置为数小时,甚至设置为 -1,这意味着永远等待查询完成。

主服务器上写入的事务状态“提示位”不会记录在 WAL 中,因此备用服务器上的数据很可能会在备用服务器上再次重写提示。因此,即使所有用户都是只读的,备用服务器仍会执行磁盘写入;数据值本身不会发生更改。用户仍然会写入大型排序临时文件并重新生成 relcache 信息文件,因此在热备用模式下,数据库的任何部分都不是真正的只读。另请注意,使用 dblink 模块对远程数据库的写入以及使用 PL 函数在数据库外部的其他操作仍然是可能的,即使事务在本地是只读的。

以下类型的管理命令在恢复模式下不被接受

  • 数据定义语言 (DDL):例如,CREATE INDEX

  • 特权和所有权:GRANTREVOKEREASSIGN

  • 维护命令:ANALYZEVACUUMCLUSTERREINDEX

同样,请注意,其中一些命令实际上在主服务器上的“只读”模式事务中是允许的。

因此,您无法创建仅存在于备用服务器上的其他索引,也无法创建仅存在于备用服务器上的统计信息。如果需要这些管理命令,则应在主服务器上执行它们,并且最终这些更改将传播到备用服务器。

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_startpg_switch_wal 等。

动态可加载模块可以工作,包括 pg_stat_statements

咨询锁在恢复期间正常工作,包括死锁检测。请注意,咨询锁永远不会被 WAL 记录,因此主服务器或备用服务器上的咨询锁不可能与 WAL 重放冲突。也不可能在主服务器上获取咨询锁,并使其在备用服务器上启动类似的咨询锁。咨询锁仅与获取它们的服务器相关。

基于触发器的复制系统(例如 SlonyLondisteBucardo)根本不会在备用服务器上运行,但它们可以在主服务器上愉快地运行,只要更改不发送到备用服务器进行应用即可。WAL 重放不是基于触发器的,因此您不能从备用服务器中继到任何需要额外数据库写入或依赖于使用触发器的系统。

无法分配新的 OID,但一些UUID生成器可能仍然可以工作,只要它们不依赖于将新状态写入数据库。

当前,只读事务期间不允许创建临时表,因此在某些情况下,现有脚本将无法正确运行。此限制可能会在以后的版本中放宽。这既是 SQL 标准合规性问题,也是技术问题。

只有当表空间为空时,DROP TABLESPACE 才能成功。某些备用用户可能会通过其 temp_tablespaces 参数主动使用该表空间。如果表空间中存在临时文件,则所有活动查询都会被取消,以确保临时文件被删除,从而可以删除表空间并继续进行 WAL 重放。

在主服务器上运行 DROP DATABASEALTER DATABASE ... SET TABLESPACE 将生成一个 WAL 条目,这将导致备用服务器上连接到该数据库的所有用户被强制断开连接。无论 max_standby_streaming_delay 的设置如何,此操作都会立即发生。请注意,ALTER DATABASE ... RENAME 不会断开用户连接,这在大多数情况下不会被注意到,但在某些情况下,如果程序以某种方式依赖于数据库名称,则可能会导致程序混乱。

在正常(非恢复)模式下,如果您为具有登录功能的角色发出 DROP USERDROP ROLE,而该用户仍然处于连接状态,那么连接的用户不会发生任何变化,他们仍然处于连接状态。但是,该用户无法重新连接。此行为也适用于恢复,因此主服务器上的 DROP USER 不会断开备用服务器上该用户的连接。

累积统计系统在恢复期间处于活动状态。所有扫描、读取、块、索引使用等都将在备用服务器上正常记录。但是,WAL 重放不会增加关系和数据库特定的计数器。即,重放不会增加 pg_stat_all_tables 列(如 n_tup_ins),启动进程执行的读取或写入也不会在 pg_statio_ 视图中跟踪,也不会增加相关的 pg_stat_database 列。

自动清理在恢复期间不活动。它将在恢复结束时正常启动。

检查点进程和后台写入器进程在恢复期间处于活动状态。检查点进程将执行重启点(类似于主服务器上的检查点),后台写入器进程将执行正常的块清理活动。这可以包括对存储在备用服务器上的提示位信息的更新。 CHECKPOINT 命令在恢复期间被接受,尽管它执行的是重启点而不是新的检查点。

26.4.4. 热备参数参考 #

上面在 第 26.4.2 节第 26.4.3 节 中已经提到了各种参数。

在主服务器上,可以使用 wal_level 参数。如果在主服务器上设置了 max_standby_archive_delaymax_standby_streaming_delay,则无效。

在备用服务器上,可以使用 hot_standbymax_standby_archive_delaymax_standby_streaming_delay 参数。

26.4.5. 注意事项 #

热备有几个限制。这些限制可能会在未来的版本中修复

  • 在可以获取快照之前,需要了解有关正在运行的事务的完整知识。使用大量子事务(当前大于 64)的事务将延迟只读连接的启动,直到最长运行的写入事务完成。如果发生这种情况,解释性消息将发送到服务器日志。

  • 备用查询的有效起点在主服务器上的每个检查点生成。如果备用服务器在主服务器处于关闭状态时关闭,则可能无法重新进入热备用状态,直到主服务器启动,以便它在 WAL 日志中生成进一步的起点。这种情况在最常见的可能发生的情况下都不是问题。通常,如果主服务器关闭且不再可用,则可能是由于严重的故障,需要将备用服务器转换为作为新的主服务器运行。在有意关闭主服务器的情况下,协调以确保备用服务器顺利成为新的主服务器也是标准程序。

  • 在恢复结束时,预备事务持有的 AccessExclusiveLocks 将需要两倍于正常数量的锁表条目。如果您计划运行大量通常需要 AccessExclusiveLocks 的并发预备事务,或者您计划拥有一个需要许多 AccessExclusiveLocks 的大型事务,建议您选择较大的 max_locks_per_transaction 值,可能是主服务器上参数值的两倍。如果您的 max_prepared_transactions 设置为 0,则无需考虑这一点。

  • 串行化事务隔离级别在热备用中尚不可用。(有关详细信息,请参阅 第 13.2.3 节第 13.4.1 节。)在热备用模式下尝试将事务设置为串行化隔离级别将产生错误。

提交更正

如果您在文档中看到任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。