RDS Postgres只读副本old_snapshot冲突原因排查
confl_snapshot冲突的常见原因 针对你遇到的ERROR: canceling statement due to conflict with recovery且冲突类型为confl_snapshot的问题,结合你提供的热备节点配置,我整理了以下核心原因:
备库长运行查询持有过旧快照
你的备库配置hot_standby = on但hot_standby_feedback = off——这个参数关闭后,主库无法感知备库上正在运行的查询需要保留哪些旧行版本。如果备库存在长时间运行的只读查询(比如批量报表、数据导出),它们会持续持有一个旧的事务快照;而主库的VACUUM进程会定期清理已被提交事务覆盖的行版本,当这些被清理的版本恰好是备库查询需要的时,就会触发confl_snapshot冲突,导致查询被终止。主库VACUUM无延迟清理策略
配置vacuum_defer_cleanup_age = 0意味着主库的VACUUM不会延迟清理旧行版本:一旦事务提交,对应的旧行版本就会被标记为可立即清理。在hot_standby_feedback = off的前提下,主库完全不知道备库是否还依赖这些旧数据,因此会直接执行清理操作,进而与备库的旧快照查询产生冲突。未限制旧快照的生存时间
你设置了old_snapshot_threshold = -1(默认值),这表示PostgreSQL不对旧快照的存活时间做任何限制。如果备库上存在长时间未终止的事务(比如某个会话开启事务后一直未提交/回滚),它持有的快照会越来越旧;主库持续推进事务ID并清理旧行版本,最终会覆盖这个快照所需的数据,引发冲突。主库写入量过大导致事务ID快速推进
当主库有大量写入操作时,事务ID会快速增长,VACUUM清理旧行版本的频率也会提升。如果备库的查询运行速度跟不上主库的清理节奏(比如查询耗时过长),就很容易出现快照与已清理数据的冲突。
内容的提问来源于stack exchange,提问作者alt-f4

