公司有一台pg从数据库,链接的是位于上海的主库,最近使用过程当中遇到了一个报错:数据库
ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed
复制代码
Google一番后,总结缘由以下:bash
Pg属于经典的MVCC(multi version concurrency control)架构,在这种模式下,更新一行不是直接修改那一行的内容,而是会建立一个新的行,对应的这两行属于不一样的版本,这也就是MVCC中multi version的含义。显然,若是这么一直建立新的行,磁盘早晚会被撑爆,因此pg内部会有一个 vacuum进程,专门用来清理老数据。微信
Pg每一个row都有两个特殊的字段xmin,xmax架构
简单来讲,也就是若是该row建立时的transaction id大于当前事务的transaction id,那么将不可见;若是该row删除时的transaction id小于当前事务的transaction id,也不可见。并发
MVCC目的是提升并发度,读操做不会阻塞写操做,写操做也不会阻止读操做。函数
这一特性和从数据库放在一块儿的时候,会遇到一些问题: 好比在从数据库上有一个耗时很长的查询操做,在查询的过程当中,一些须要的row在主数据库上面已经被更新或者删除了。主数据库并不知道当前在从数据库在进行一个查询,它以为本身能够vacuum掉那些比较老的数据行。对于从数据,他必须replay这个vacuum操做,因此他必须取消全部结果包含这些数据行的查询。高并发
默认状况下,主数据库是看不到从数据库上的查询操做的,设置hot_standby_feedback为on,能够防止主数据库的vacuum操做把从数据库查询须要的数据行给清除掉。性能
可是这个方案可能会影响主数据库的性能,由于主数据库如今得考虑从数据库的查询,势必会是一种负担,如在pg官方文档中写道:ui
Well, the disadvantage of it is that the standby can bloat the master, which might be surprising to some people, too
复制代码
pg中有一个max_standby_streaming_delay参数,意思是从数据库replay主数据库操做能够等待的最长时间。默认是30s,将其设置为一个相对比较大的数,或者-1,也就是能够无限等待,能够在全部查询完成以后再replay主数据库的操做,这样长查询就不会被取消了。spa
这个参数相比hot_standby_feedback,只会影响从服务区,对主服务区没影响,可是有可能会加大主从数据不一致。
可见,从数据库长耗时查询并无一个十全十美的方案,这也算是一个困扰社区已久的难题。
关注个人微信公众号