背景
不知道是否有人关注到下面这个错误日志,在一个异步流复制的环境中,我们在主库看到如下日志:
ERROR: requested WAL segment 00000001000000170000001C has already been removed
在从库看到如下错误日志:
FATAL: could not receive data from WAL stream:ERROR: requested WAL segment 00000001000000170000001C has already been removed
然后我们发现主从复制断开了。下面聊一下这个话题。
原因
首先说明一下如果排除vacuum等因素,只有正常业务写入的情况下,这个现象正常只会出现在异步流复制的环境,而且只有在网络状况不佳(延迟较大或者有丢包)的情况下才会出现。
笔者为了测试流复制的性能,特地对pg的异步流复制性能进行过压测,压测结果如下:pg默认安装不进行任何参数调整,主库能达到15万条/秒的插入速度,查询更是能达到惊人了90万条/秒,这个速度是很恐怖的,可以说远远高于其他几种数据库。在每秒14万条插入的时候日志产生量大概达到60M/s,即使在这么大的压力下,观察主从的lag,发现lag竟然十分稳定,一点没有增长。只有当加延迟才慢慢发现会有备库追不上主库的现象,这个延迟经过测试发现也是一个很大的值,生产环境一般不会出现如此大的延迟,所以pg的流复制性能是非常好的,只有在网络极端不好的情况下才会有lag追不上的情况。主库产生的日志备库来不及应用,而主库又有max_wal_size参数的限制,超过这个数量的日志就会被删除,所以lag越来越大的情况下备库需要的wal日志可能已经被主库删除了,造成主备断连。
同步复制为什么不会出现追不上的情况呢?因为同步复制本身就是牺牲性能保证数据的一致性,换句话说就是我宁愿降低我主库的插入速度也要等备库同步完,这样lag其实就会保持一个稳定值,不会增长。
物理复制槽
上面我们知道了主备断连的原因是因为主备lag持续增大造成备库需要的wal日志被主库清理,当然主库日志清理不止这一种情况,可能还会有vacuum等原因。那么我们可以通过物理复制槽来规避这个问题。下面看看如何使用物理复制槽。
在主库创建物理复制槽:
SELECT * FROM pg_create_physical_replication_slot('slot_s1');
备库使用该物理复制槽:
vi recovey.conf,新增如下配置:
primary_slot_name='slot_s1'
再次加延迟进行压测:
tc qdisc add dev bond0 root netem delay 1s
我们观察主库的wal日志目录大小,发现目录已经超过1G,并且在持续增长,备库需要的日志在累积。
但是复制槽的使用一定要注意风险,一定要做好redo日志个数或者大小的监控,方式主备同步异常造成主库日志堆积。