报错:
canceling statement due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.
Hot Standby 环境下的 standby 节点执行查询时报错,报错信息如下:
1、执行长时间查询时报错。
根据错误信息,初步估计当在从库上执行查询时,与主库发生了冲突。
2、网上GOOGLE ,信息如下
Long running queries on the standby are a bit tricky, because they
might need to see row versions that are already removed on the master.
备注:意思是说,长时间SQL如果跑在 standby 节点上是一个笑话,因为 standby 节点有可能需要读取主库上被 removed 的数据。
3、解决方法,修改参数
根据实际情况,调大参数:max_standby_streaming_delay = 30min;
当在 Standby 提供应用时,如果 Standby 节点上的SQL 与接收主库日志发生冲突时,
这个参数决定了从库等侍这个查询的时间,默认值为 30s, 有SQL执行时间估计在二分钟左
右,从而被 Standby库主动 Cancel 了。也可以将这个参数设置成 -1. 表示 standby 节点永远等侍这个查询,
这无疑是有风险的,如果这个查询不结束,那么从库一直处于与主库的中断状态,不会同步主库数据,而会一
直等从库这个SQL执行完成。
4、其他说明
PostgreSQL 的 Hot Standby常被用来当只读的数据库提供查询或者统计服务, 但是由于各种原因查询SQL可能被cancel掉。
例如:
1)主库执行了DROP某TABLE的操作, 而standby库上某用户正在查询这个表的数据. 当standby接收到了这些XLOG的信息并且
准备在standby库上apply的时候, 如果这个SQL还在执行, 就发生冲突了, 这个时候standby 要判断是否要cancel掉这个SQL
使得apply可以正常进行下去, 或者standby选择等待多长时间.
2)主库执行删除表空间或者删除库等相关的操作也会遇到上面的问题.
3)更隐晦的是主库上执行了vacuum操作, 这些被vacuum掉的tuple, 可能是standby库上的SQL可见的TUPLE, 也会发生冲突.
4)还有其他原因
那么Standby根据什么来判断是CANCEL SQL还是选择等待, 如果等待, 等多长时间?有两个参数控制:
max_standby_archive_delay
max_standby_streaming_delay
如果值等于-1表示永不因为recovery 和SQL冲突原因cancel standby上的SQL.
如果设置了一个值如30秒, 那么在cancel 冲突的SQL前, 会等待,通过GetStandbyLimitTime来判断是否要触发CANCEL SQL, 当GetStandbyLimitTime返回的值为0 时表示永不触发CANCEL, 如果返回的是一个时间值, 这个时间值和当前时间进行比较,如果小于当前时间则进行CANCEL操作.