暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PG数据库主服务器和后备服务器如何处理查询冲突

PostgreSQL数据库工作学习随笔 2022-05-21
628

    主服务器和后备服务器在多方面都是连接在一起。主服务器上的动作将在后备服务器上产生效果。结果是在它们之间有潜在的负作用或冲突。最容易理解的冲突是性能:如果在主服务器上发生一次大数据量的载入,那么这将在后备服务器上产生一个相似的 WAL 记录流,因而后备服务器查询可能要竞争系统资源(例如 I/O)。

    随着热备发生的还可能有其他类型的冲突。对于可能需要被取消的查询和(某些情况中)解决它们的已断开会话来说,这些冲突是硬冲突。用户可以用几种方式来处理这种冲突。冲突情况包括:

    • 在主服务器上取得了访问排他锁(包括显式LOCK命令和多种DDL动作)与后备查询中的表访问冲突。

    • 在主服务器上删除一个表空间与使用该表空间存储临时工作文件的后备查询冲突。

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

    • 从 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 规则的正确的数据可见性。不过,这个规则只能被应用于执行在主控机上的事务。因此有可能主控机上的清除会移除对一个后备服务器事务还可见的行版本。

    有经验的用户应当注意行版本清除和行版本冻结都可能与后备查询冲突。即便在一个没有被更新或被删除行的表上运行一次手工VACUUM FREEZE也可能导致冲突。

    用户应当清楚,主服务器上被正常和重度更新的表将快速地导致后备服务器上长时间运行的查询被取消。在这样的情况下,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 项导致的快速取消。

    另一个选项是增加主服务器上的vacuum_defer_cleanup_age,这样死亡行不会像平常那么快地被清理。这将允许在后备服务器上的查询能在被取消前有更多时间执行,并且不需要设置一个很高的max_standby_streaming_delay。但是,这种方法很难保证任何指定的执行时间窗口,因为vacuum_defer_cleanup_age是用主服务器上被执行的事务数来衡量的。

    查询取消的数量和原因可以使用后备服务器上的pg_stat_database_conflicts系统视图查看。pg_stat_database系统视图也包含汇总信息。

    vastbase=# select * from pg_stat_database where datname='vastbase';
    -[ RECORD 1 ]--+-----------------------------
    datid | 14812
    datname | vastbase
    numbackends | 2
    xact_commit | 1465
    xact_rollback | 11
    blks_read | 723
    blks_hit | 24599
    tup_returned | 179076
    tup_fetched | 9281
    tup_inserted | 2962
    tup_updated | 7
    tup_deleted | 93
    conflicts | 0
    temp_files | 0
    temp_bytes | 0
    deadlocks | 0
    blk_read_time | 0
    blk_write_time | 0
    stats_reset    | 2022-05-15 20:30:58.55023+08


    vastbase=#
    文章转载自PostgreSQL数据库工作学习随笔,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论