适用于: Azure Database for PostgreSQL - 灵活服务器
本文可帮助你解决在针对只读副本执行查询期间发生的问题。
现象
- 尝试对只读副本执行查询时,查询意外终止。
- 日志或查询输出中显示“由于与恢复发生冲突而取消语句”等错误消息。
- 从主服务器复制到只读副本时可能存在明显的延迟或滞后。
在提供的屏幕截图中,左侧是主 Azure Database for PostgreSQL 灵活服务器实例,右侧是只读副本。
- 只读副本控制台(上面的屏幕截图右侧)
- 我们可以观察到一个长时间运行的
SELECT
语句正在进行。 关于 SQL,要注意的一个重要方面是数据的一致视图。 执行 SQL 语句时,它实质上会“冻结”其数据的视图。 在整个执行过程中,SQL 语句始终看到的是数据的一致快照,即使更改同时发生在其他位置也是如此。
- 我们可以观察到一个长时间运行的
- 主控制台(上面的屏幕截图左侧)
- 已执行
UPDATE
操作。 虽然UPDATE
本身并不一定会中断只读副本的行为,但后续操作却会如此。 更新后,执行了VACUUM
操作(在本例中,该操作是手动触发的,以用于演示目的,但值得注意的是,也可以自动启动一个自动清理进程)。 VACUUM
的作用是通过删除旧版本的行来回收空间。 鉴于只读副本运行的是一个长时间运行的SELECT
语句,它当前正在访问作为VACUUM
的删除目标的一些行。VACUUM
操作启动的这些更改(包括删除行)将记录到预写日志 (WAL
)。 由于 Azure Database for PostgreSQL 灵活服务器只读副本利用本机 PostgreSQL 物理复制,因此这些更改稍后会发送到只读副本。- 问题的关键在于:
VACUUM
操作(不知道只读副本上正在进行的SELECT
语句)会删除只读副本仍然需要的行。 此方案会导致所谓的复制冲突。
- 已执行
此方案的后果是,由于 VACUUM
操作删除了这些行,只读副本会遇到复制冲突。 默认情况下,只读副本会尝试在 30 秒内解决此冲突,因为 max_standby_streaming_delay
的默认值设置为 30 秒。 在此持续时间之后,如果冲突仍未解决,则会取消对只读副本的查询。
原因
此问题的根本原因是 Azure Database for PostgreSQL 灵活服务器中的只读副本是一个持续恢复的系统。 这种情况意味着,虽然该副本正在赶上主服务器的进度,但它本质上处于持续恢复的状态。 如果对只读副本的查询尝试读取恢复过程同时更新的行(因为主服务器已更改),Azure Database for PostgreSQL 灵活服务器可能会取消查询,以允许恢复在不中断的情况下继续。
解决方法
- 调整
max_standby_streaming_delay
:提高只读副本上的max_standby_streaming_delay
参数。 提高该设置的值可使此副本在决定取消查询之前有更多的时间来解决冲突。 但是,这可能会增加复制滞后时间,因此这是一种权衡。 此参数是动态的,这意味着无需重启服务器,更改就会生效。 - 监视和优化查询:查看针对只读副本运行的查询的类型和频率。 长时间运行的查询或复杂查询可能更容易受冲突影响。 以不同的方式优化或计划它们会有所帮助。
- 非高峰查询执行:考虑在非高峰时段运行繁重或长时间运行的查询,以减少发生冲突的可能性。
- 启用
hot_standby_feedback
:请考虑在只读副本上将hot_standby_feedback
设置为on
。 启用后,它会通知主服务器当前正在由该副本执行的查询。 这样可以防止主服务器删除该副本仍然需要的行,从而减少发生复制冲突的可能性。 此参数是动态的,这意味着无需重启服务器,更改就会生效。
注意
启用 hot_standby_feedback
可能会导致以下潜在问题:
- 调整
max_standby_archive_delay
:max_standby_archive_delay
服务器参数指定在读取存档的WAL
数据时服务器允许的最大延迟。 如果 Azure Database for PostgreSQL 灵活服务器实例的副本从流式处理模式切换到基于文件的日志传送(尽管很少见),则调整此值有助于解决查询取消问题。