最近在研究备机查询时间长报错的问题
ERROR: canceling statement due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.
示例:
主:
create table test_per2 ( id int , flag int);
insert into test_per2 (id) select * from generate_series(1,1000000) ;
vim test.sql
下边两行是test.sql文件的内容
\set v_id random(1,1000000)
update test_per2 set flag='1' where id=:v_id;
然后执行下边的命令
kbbench -c 8 -T 120 -d test -U system -n N -M prepared -f test.sql
最后备机执行select sys_sleep(12),* from test_per2 limit 10 ; 等待一段时间
有两种办法可以解决此问题。
1、修改max_standby_streaming_delay
这个参数默认是30s,也就是说备机执行的sql时间大于30秒后就会报错。
代价就是备机查询到的数据不是最新的
2、修改hot_standby_feedback=on 规避
如果激活此参数,如果备库进行长查询,则会从备库发送反馈消息给主库,其中包含最旧活动事务的信息;因此,主库做update操作,同时要保留备库正常查询的这些垃圾版本。
代价如下:
主库膨胀,因为垃圾版本延迟回收。
- 重复扫描垃圾版本,重复耗费垃圾回收进程占用CPU资源。(n_dead_tup会一直处于超过垃圾回收阈值状态,从而autovacuum不断唤醒worker进行回收动作,做无用功)
- 当主库的 autovacuum_naptime很小,同时autovacuum_vacuum_scale_factor很小时,尤为明显。
- 如果期间发生大量垃圾,垃圾版本可能会在事务完成后,集中爆炸性的被回收,产生大量的WAL日志,从而造成WAL写的IO高峰。