PostgreSQL 教程: 检查恢复冲突

八月 2, 2024

摘要:在本教程中,您将学习如何检查 PostgreSQL 中的恢复冲突。

目录

什么是恢复冲突?

每当恢复进程,因为应用更改会中断在进行的查询处理,无法将来自主服务器的 WAL 信息应用到备用服务器时,就会发生恢复冲突。这些查询冲突不会在主服务器上发生,但它们会发生在流复制中的备用服务器上,因为主服务器对备用服务器上发生的情况了解有限。

有几种类型的恢复冲突:

快照恢复冲突

这是最常见的恢复冲突。

如果VACUUM处理过一个表并删除了死元组,则可能会发生快照冲突。删除操作将在备用数据库上重做。现在,备用数据库上的一个查询,可能已在主数据库进行VACUUM之前启动(它具有较老的快照),因此它仍然可以看到应删除的元组。这样就构成了快照冲突。

锁恢复冲突

备用服务器上的查询,会对它们正在读取的表进行ACCESS SHARE锁定。因此,主服务器上的任何ACCESS EXCLUSIVE锁定(与ACCESS SHARE冲突),都必须在备用服务器上重放,以防止在表上出现不兼容的操作。PostgreSQL 对与SELECT冲突的操作都会进行这样的锁定,例如DROP TABLETRUNCATE和许多ALTER TABLE语句。如果备用数据库需要在一个查询使用的表上重放这样的锁定,就会出现锁冲突。

缓冲页销恢复冲突

减少VACUUM工作量的一种方法是使用 HOT(heap-only tuples)更新。然后,当主节点上的任何查询,访问带有死去的堆元组的页面,并可以在其上获得排他锁时,都可以修剪 HOT 链。PostgreSQL 只会在短时间内保持这样的页面锁定,从而跟主数据库上的处理不会冲突。页面锁定还有其他原因,但这可能是最常见的原因。

当备用服务器需要重放此类排他性页面锁定,并且有查询正在使用该页面时(在 PostgreSQL 术语中为 “页面已上销”),您将收到缓冲页销恢复冲突。页面可能会上销一段时间,例如,在对嵌套循环连接的外侧表进行顺序扫描期间。

当然,HOT 链修剪也会导致快照恢复冲突。

罕见的恢复冲突类型

以下类型的冲突很少见,不太会干扰您:

  • 死锁恢复冲突:在共享缓冲页上面重放来自主数据库的 WAL 时,备用数据库上的查询访问该缓冲页会阻塞。PostgreSQL 将立即取消此类查询。
  • 表空间恢复冲突:在备用服务器上temp_tablespaces中有一个表空间,并且有查询在那里有临时文件。当主服务器上发生DROP TABLESPACE操作时,我们会遇到冲突。在这种情况下,PostgreSQL 会取消备用服务器上的所有查询。
  • 数据库恢复冲突:如果备用服务器在数据库上有活动会话,DROP DATABASE操作的复制会发生冲突。在这种情况下,PostgreSQL 会终止与备用服务器上的数据库的所有连接。

备用服务器如何解决恢复冲突?

参数 max_standby_streaming_delay 确定当 WAL 重放遇到恢复冲突时会发生什么情况(有一个类似的参数max_standby_archive_delay,对于归档恢复进行相同的处理)。PostgreSQL 暂停 WAL 信息的重放,最多max_standby_streaming_delay毫秒。如果冲突的查询在该时间之后仍在运行,PostgreSQL 会取消它,并显示类似下面内容的错误消息:

ERROR:  canceling statement due to conflict with recovery
DETAIL:  User query might have needed to see row versions that must be removed.

详细信息显示,这是由快照恢复冲突产生的错误。

max_standby_streaming_delay默认值为 30 秒,因此,备用数据库上的查询,有半分钟的“宽限时间”来完成,如果它们引起了恢复冲突,它们会被取消掉。这是底限值 0(PostgreSQL 立即取消查询,无重放延迟)和特殊值 -1(PostgreSQL 从不取消查询,重放延迟可以任意长)之间的中间取值。

查询 pg_stat_database 视图

统计信息视图 pg_stat_database_conflicts 包含了,自上次统计信息重置以来,发生的所有恢复冲突的详细说明。您必须在备用服务器(而不是主服务器)上查看该视图,因为只有那里才会发生恢复冲突。

请注意,此视图不会显示发生的所有恢复冲突,它仅显示导致备用数据库上查询被取消的冲突。我们可以使用下面的查询,来检查恢复冲突:

SELECT conflicts FROM pg_stat_database
  WHERE datname = current_database();

一旦发现有许多恢复冲突,您就可以找到那些导致恢复冲突的查询,并调整它们。

了解更多

PostgreSQL 监控