Caused by: ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed.
场景描述
这里我们是流复制环境,仓库从现网的备节点抽取数据导致以上报错。
原理很简单,就是主节点的相关表做了DDL或者DML,wal在备节点回放的时候,备节点的查询还在进行,如此就会发生冲突,干掉备节点查询的语句,报出以上错误。
下图简单演示了报错原理,这里是由DML中的UPDATE引起的冲突,行版本不一致造成相关的错误。
上图可见一个参数max_standby_streaming_delay默认为30秒,也就是说vacuum的时候,相关需要清理的数据仍有事物在使用,则认为有冲突,等待这个参数设置的值,也就是30秒,30秒后则中断连接,报出以上错误。所以这里可能是DDL,比如drop table,truncate table,drop database,drop tablespace等等,也可能是DML,delete,update等等语句都会引起错误发生。
所以这里分为两类处理方式:处理DDL和处理DML
要避免DDL发生,那么需要设置参数max_standby_streaming_delay为-1,这样就会一直等待查询的语句结束为止。如果是从归档中回放产生的冲突,那就max_standby_archive_delay设置为-1。
要避免DML,也就是VACUUM产生的冲突,当然以上的方法也是可用的,这里引入另外一个参数hot_standby_feedback,可以打开该参数(设置为on)避免。
hot_standby_feedback 的原理很简单,就是将备节点的最小活跃事务 ID 定期告知主节点,使得主节点在执行 VACUUM 时对这些事务还需要的数据手下留情。
设置 hot_standby_feedback 的好处是可以减少备节点执行查询时复制冲突的可能,但也有其弊端,即会使主节点先关表的数据延迟回收,从而导致数据膨胀;极端情况下,如果 备节点有一个很长的事务,且涉及表上 DML 操作又很频繁,则表的膨胀则会很严重。
另外也可以考虑设置vacuum_defer_cleanup_age参数,这个参数可以延迟清理dead row,使得在备节点的查询可以读取这些dead row,默认为0,这个参数是在主节点上设置,也是由主节点度量的,所以这个值很难确定设置多少为有效,如果主节点事物数增长很快,那么很快dead row就会被清理,对于备节点的查询冲突没什么效果,所以以上引发的错误,我个人不建议设置该参数解决。
总结:
开启max_standby_streaming_delay或者max_standby_archive_delay也有弊端,如果备节点有长事物,那么,备节点会长时间跟不上主节点,主备节点的数据无法一致,如果有多个级联的备节点,那后果更是不堪设想。
如果这只hot_standby_feedback,那么可能会导致相关表膨胀,如果业务频繁查询,更新,删除,那么这些膨胀的表DML处理肯定效率低下,将会影响业务响应。
另外vacuum_defer_cleanup_age觉的效果不好,主要是在主节点度量这个值,所以不建议设置,这里就不做更深的研究探讨。
参考:
https://www.postgresql.org/docs/11/hot-standby.html
26.5.2. Handling Query Conflicts章节
原文链接:https://blog.csdn.net/dazuiba008/java/article/details/104966409