本文可帮助你解决在针对只读副本执行查询期间出现的问题。
症状
- 尝试对只读副本执行查询时,查询意外终止。
- 日志或查询输出中出现类似“由于与恢复冲突而正在取消语句”的错误消息。
- 从主服务器到只读副本的复制可能存在明显的延迟或滞后。
在提供的屏幕截图中,左侧是主 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 灵活服务器实例的副本从流式处理模式切换到基于文件的日志传送(尽管很少见),则调整此值有助于解决查询取消问题。