Postgresql 查询报错ERROR: canceling statement due to conflict with recovery

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

  1. 要避免DDL发生,那么需要设置参数max_standby_streaming_delay为-1,这样就会一直等待查询的语句结束为止。如果是从归档中回放产生的冲突,那就max_standby_archive_delay设置为-1。
  2. 要避免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章节

这个错误提示意味着无法连接到 PostgreSQL 服务器。这可能是由于以下原因导致的: 1. PostgreSQL 服务器未启动或已关闭。 2. PostgreSQL 服务器正在运行,但其套接字文件(socket file)的路径不正确。 3. PostgreSQL 服务器正在运行,但是未设置正确的连接参数。 为了解决这个问题,你可以尝试以下步骤: 1. 确认 PostgreSQL 服务器是否已经启动。你可以使用以下命令检查服务器状态: ``` $ systemctl status postgresql ``` 如果服务器未启动,你可以使用以下命令启动它: ``` $ sudo systemctl start postgresql ``` 2. 确认 PostgreSQL 服务器的套接字文件路径是否正确。默认情况下,套接字文件的路径为 `/var/run/postgresql/.s.PGSQL.5432`。你可以使用以下命令检查套接字文件的路径: ``` $ sudo lsof -i -P -n | grep LISTEN | grep postgres ``` 如果套接字文件的路径不正确,你可以尝试在连接参数中指定正确的路径。例如,如果套接字文件的路径为 `/tmp/.s.PGSQL.5432`,则可以在连接参数中指定: ``` $ psql -h /tmp dbname ``` 3. 确认连接参数是否正确。你可以使用以下命令连接到 PostgreSQL 服务器: ``` $ psql -h hostname -p port -U username -d dbname ``` 其中,`hostname` 是 PostgreSQL 服务器的主机名或 IP 地址,`port` 是 PostgreSQL 服务器的端口号(默认为 5432),`username` 是连接 PostgreSQL 服务器的用户名,`dbname` 是要连接的数据库名称。你需要根据实际情况修改这些参数。如果连接参数正确,但仍然无法连接到 PostgreSQL 服务器,则可能是由于防火墙或网络问题导致的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值