Postgresql 中文操作指南
27.4. Hot Standby #
热备用是用来描述连接到服务器和运行只读查询的能力的术语,当服务器处于归档恢复或待机模式时。这对复制目的和以极高的精度将备份恢复到所需状态都很有用。热备用术语也指当用户继续运行查询和/或让连接保持打开时,服务器从恢复转向正常操作的能力。
在热备用模式下运行查询类似于正常查询操作,尽管有如下解释的几个使用和管理差异。
27.4.1. User’s Overview #
当在备用服务器上将 hot_standby 参数设置为 true 时,一旦恢复使系统恢复到一致状态,它将开始接受连接。所有此类连接都是严格的只读连接;甚至连临时表都不能写入。
主备服务器之间的数据传输需要一点时间,因此主备之间存在着可测量的延迟。因此,同时在主备服务器上运行相同的查询可能返回不同的结果。我们称备库上的数据与主库存在 eventually consistent 关系。一旦事务的提交记录在备库上重放,该事务所做的更改就会在备库上的任何新快照中可见。根据当前的事务隔离级别,快照可以在每个查询或每个事务开始时创建。详情请参阅 Section 13.2 。
在热备用期间启动的事务可能会发出下列命令:
在热备用期间启动的事务永远不会被分配一个事务 ID,且不能写入系统预写日志。因此,以下动作将会产生错误信息:
在普通操作中,允许“只读”事务使用 LISTEN 和 NOTIFY,因此热备用会话在比普通只读会话稍严格的限制下操作。有些限制可能会在未来的版本中放宽。
在热备用期间,参数 transaction_read_only 始终为 true,且不能被更改。但只要没有尝试修改数据库,热备用期间的连接就会像任何其他数据库连接一样。如果发生故障转移或切换,数据库将会切换到正常处理模式。会话会保持连接,而服务器切换模式。一旦热备用完成,就可以启动可读写的交易(甚至是从热备用期间开始的会话中启动)。
用户可以通过发布 SHOW in_hot_standby 来确定热备用目前是否对自己的会话处于激活状态。(在早于 14 的服务器版本中, in_hot_standby 参数不存在;适用于较旧服务器的替代方法是 SHOW transaction_read_only。)此外,一组函数( Table 9.92 )允许用户访问有关备用服务器的信息。这些函数可用于编写能够感知数据库当前状态的程序。这些函数可用于监视恢复进度,或用于编写将数据库还原为特定状态的复杂程序。
27.4.2. Handling Query Conflicts #
主备服务器在很多方面是松散连接的。主服务器上的操作将对备用服务器产生影响。结果,它们之间有可能出现负面交互或冲突。最容易理解的冲突是性能:如果在主服务器上进行巨大的数据加载,这将会在备用服务器上生成类似的 WAL 记录流,所以备用查询可能会争用系统资源,例如 I/O。
还有一些额外的冲突类型可以在热备用中发生。这些冲突 hard conflicts 在某种意义上,查询可能需要取消,并且在某些情况下,需要断开会话来解决它们。用户提供了几种处理这些冲突的方法。冲突案例包括:
在主服务器上,这些案例仅仅导致等待;用户可能会选择取消任一冲突操作。然而,在备用服务器上没有选择: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 重放之间发生冲突的最常见原因是“早期清理”。通常,当根据 MVCC 规则没有需要看到旧行版本的交易来确保数据的正确可见性时,PostgreSQL 允许清理旧行版本。但是,此规则只能应用于在主服务器上执行的交易。因此,主服务器上的清理可能会删除备用服务器上的交易仍可见的行版本。
行版本清理并不是与备用查询发生冲突的唯一潜在原因。所有仅索引扫描(包括在备用服务器上运行的扫描)都必须使用与可见性图“一致”的 MVCC 快照。因此,只要 not 包含一个或多个对所有备用查询都可见的行,就会导致发生冲突。因此,即使对没有 wymagających czyszczenia 更新或已删除行的数据表运行 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. Administrator’s Overview #
如果 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 时,无法启用热备用。在以下两种情况下,也可能会延迟达到一致状态:
如果您正在运行基于文件的日志传送(“暖备用”),则您可能需要等到下一个 WAL 文件到达,这可能与主服务器中的 archive_timeout 设置一样长。
某些参数的设置决定了用于跟踪事务 ID、锁和已准备事务的共享内存的大小。这些共享内存结构在备用服务器中的大小不得小于主服务器中的大小,以确保备用服务器在恢复期间不耗尽共享内存。例如,如果主服务器曾经使用已准备的事务,但备用服务器没有为跟踪已准备的事务分配任何共享内存,则在更改备用服务器的配置之前,恢复将无法继续。受影响的参数有:
确保这不会成为问题的最简单方法是将这些参数在备用服务器上设置为等于或大于主服务器上的值。因此,如果您要增加这些值,则应先在所有备用服务器上执行此操作,然后再将更改应用于主服务器。相反,如果您要减小这些值,则应先在主服务器上执行此操作,然后再将更改应用于所有备用服务器。请记住,当备用服务器被升级时,它将成为其后续备用服务器所需的此参数设置的新参考。因此,建议在切换或故障转移期间避免其成为问题,即保持所有备用服务器上的这些设置相同。
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 选择合适的设置。最佳选择取决于业务优先级。例如,如果服务器主要充当高可用性服务器,那么你将希望延迟设置比较低(甚至是 0),尽管这是一个非常激进的设置。如果备用服务器充当决策支持查询的备用服务器,那么将最大延迟值设置为很多小时甚至 -1(即永远等待查询完成)可能是可以接受的。
在主服务器上写入的交易状态“提示位”不会记录在 WAL 中,因此备用服务器上的数据可能在备用服务器上再次重写提示。因此,即使所有用户都是只读的,备用服务器仍将执行磁盘写入;数据值本身不会发生任何变化。用户仍然会写入大型排序临时文件并重新生成 relcache 信息文件,因此在热备份模式下,数据库的任何部分都不是真正的只读。另请注意,即使交易在本地是只读的,仍可以使用 dblink 模块对远程数据库进行写入,以及使用 PL 函数进行数据库外部的其他操作。
在恢复模式中不接受以下类型的管理命令:
请注意,其中一些命令实际上可以在主数据库上“只读”模式事务期间执行。
因此,你无法创建仅存在于备用数据库上的附加索引,也无法创建仅存在于备用数据库上的统计信息。如果需要这些管理命令,应在主数据库上执行它们,这些更改最终会传播到备用数据库。
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 监控脚本也将正常工作,尽管一些报告值可能会给出现差异或令人困惑的结果。例如,不会保留上次 vacuum 时间,因为在备用数据库上不会发生 vacuum。在主数据库上运行的 vacuum 仍然会将它们的更改发送至备用数据库。
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 列。
自动 vacuum 在恢复期间不处于活动状态。它将在恢复结束时正常启动。
检查点进程和后台写入进程在恢复期间处于活动状态。检查点进程将执行重启点(类似于主数据库上的检查点),后台写入进程将执行正常的块清理活动。这可能包括更新存储在备用服务器上的提示位信息的活动。虽然 CHECKPOINT 命令在恢复期间会被接受,但它会执行重启点而不是新的检查点。
27.4.4. Hot Standby Parameter Reference #
已经在 Section 27.4.2 和 Section 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. Caveats #
热备有一些限制。可以并且可能在未来版本中修复这些限制: