KingbaseES V8R6 集群中复制槽非活跃状态的可能原因
背景
此问题环境是一主五备物理集群,其中node1是主节点,node2,3是集群同步节点,node4,5是集群异地异步节点,由于异地和主节点不同网段,网速非常慢。
kdts-plus工具纯迁数据,每分钟3G数据左右,单机迁移到集群主库再同步到备库。
问题现象:node4,5的复制槽active字段非活跃状态,lsn_lag过大,大于650GB且延迟间隙还在增长,restart_lsn过于陈旧。
备库有如下报错:
could not receive data from WAL stream: ERROR: requested WAL segment 0000000B000003C40000005E has already been removed
可能原因:
1、迁移过程中主库产生大量wal日志导致磁盘满,经了解前端人员手工删除wal日志,这个误操作导致流复制中断,repmgr cluster show命令查看 node4,5异地节点和集群主库失去通讯,从而导致复制槽失效非活跃状态。
2、设置了wal_keep_segments,由于备库同步速度很慢,导致备库落后于主库设置的wal_keep_segments保留的wal日志,则主库可能就删除备库需要的wal日志,导致备库node4,5节点流复制中断。
主备流复制关键参数说明和复制槽说明
wal_keep_segments:设置为较大值,保证pg_wal目录下保留较多的wal日志,主库上wal日志留存越多,允许备库宕机的时间越长,设置此参数需要注意不要将pg_wal目录撑满。或者在主库上开启归档,如果没有足够的硬盘空间保留wal归档,至少在备库停机维护时临时开启主库归档。如果备库落后主库wal_keep_segments数量的wal,则主库可能会删除备用服务器仍需要的wal,这种情况下,流复制就会中断。
hot_standby_feedback:备库定时将最小活跃事务ID(xmin)告诉master,使得 master在执行vacuum 时对备库还需要的tuple进行保留,但这样可能会导致主库膨胀,在每个wal_receiver_status_interval定义的周期内发送的频率不超过一次,并且此设置不会覆盖在主数据库上的old_snapshot_threshold行为。当设置这个参数后,pg_replication_slots视图可以看到xmin值,表示备库进行查询的快照版本。
max_standby_streaming_delay:通常会将一些执行时间较长的分析任务、统计SQL跑在备库上。在备库上执行长时间的查询,由于涉及的记录有可能在主库上被更新或删除,主库上对更新或删除数据的老版本进行vacuum后,备库上也会执行这个操作,从而与备库上的当前查询产生冲突。此参数默认为30s,当备库执行SQL时,有可能与正在应用的WAL发生冲突,此查询如果30s没有执行完就被中止,注意30s不是备库上单个查询允许的最大执行时间,是指当备库上应用WAL时允许的最大WAL延迟应用时间,因此备库上查询的执行时间有可能不到这个值就被中止了,此参数可以设置为-1,表示当从库上的WAL应用进程与从库上执行的查询冲突时,WAL日志一直等待直到从库查询执行完成。这个参数不好计量。
old_snapshot_threshold:单位为min,最大可以设置为60天,当vacuum回收垃圾时,遇到垃圾记录的xmax大于数据库中现存的最早未提交事务xmin时,不会对其进行回收。因此当数据库中存在很久为结束的事务时,可能会导致数据库膨胀。此参数意义是强制删除为过老的事务快照保留的死元组。这会导致长事务无法读取已被删除的事务快照。
vacuum_defer_cleanup_age:指定vacuum延迟清理死亡元组的事务数,vacuum会延迟清除无效的记录,延迟的事务个数通过vacuum_defer_cleanup_age参数进行设置。默认为0,在主库上设置一个稍大的值也可以减少冲突的发生,但是这个参数并不好计量设置多大。
max_standby_archive_delay:备库因为处理归档的wal日志产生查询冲突而取消查询之前的等待时间,和上面的参数类似。
recovery_min_apply_delay:延迟备库设置备库延迟重做WAL的时间,而备库依然及时接收主库发送的WAL日志流,只是不是一接收到WAL后就立即应用,而是等待此参数设置的值再应用。使用此功能将延迟hot_standby_feedback,当synchronous_commit设置为remote_apply时,同步复制也会受此设置的影响,每个commit都需要等待。
复制槽作用:
以上很多参数,只有在主备集群正常时才能起到作用,而replication slot能够确保在主备断连后主库的wal仍不被清理,因为replication slot的状态信息是持久化保存的,即使备库断掉或主库重启,这些信息仍然不会丢掉或失效。
replication slots主要是提供了一种自动化的方法来确保主库在所有的备库收到wal日志之前不会删除它们,并且主库也不会移除可能导致复制冲突的行(需要配合hot_standby_feedback使用),即使备库断开也是如此。
在没有启用replication slots的环境中,如果碰到 ERROR: requested WAL segment xxxx has already been removed 的错误,解决办法是要么提前开启了归档,要么重做备库,另外还可以在主库上设置wal_keep_segments 为更大的值。当然,如果备库停机时间太长,可能主库的WAL日志目录会被撑满,如果设置了复制槽,建议将WAL日志目录放在大容量硬盘上。
以上有些流复制有关的参数可能与本案无关,但这些都是需要掌握的,非常重要的参数。
解决措施
我们分析一下。如果把迁移速度降下来,复制槽重建,重新开始迁移并传输,这种情况同步的wal日志速度要快于迁移产生的wal速度,假如wal日志传输速度很慢,则又会出现主库产生大量wal导致磁盘满,因为未同步的wal日志在主库保留。
所以网络问题没有解决的前提,这个方案行不通,因为异地的同步速度太慢了。目前看lsn_lag有800GB以上。
换个解决方案
停掉异地备库node4,5节点,迁移完再克隆备库。这样就不会由于网络原因导致主库wal日志占用的磁盘空间满。node2,3节点是集群同网段,不存在网络延迟,所以理论上可以跟得上迁移速度。主库会根据检查点自动清理wal日志,不能手工删除wal日志。
复制槽视图sys_replication_slots中restart_lsn意思就是主库checkpoint的时候不会删除这个lsn之后的wal日志,以及过早的归档出去,为备库保留着。
如果restart_lsn不变了就说明没收到备库的reply,复制槽不活动,造成主库会一直保留本地日志,可能导致日志磁盘满。如果发现wal日志不同步了,node4,5的节点和主库失去连接。这时需要查看备库集群日志和主库失去连接的原因,node4,5的数据库日志。
可与i设置较小的wal_sender_timeout,默认为60s,及早发现备库断掉的情况。
总结
1.可以增加wal日志个数的监控,当wal日志数量超过正常值则告警,不要手工删除主库wal日志。
2.做好对每个复制槽同步状态的监控,出现某个槽同步状态异常要及时处理,同步异常会造成lsn不向前推进,导致主库wal堆积。
3.增加pg_replication_slot视图中restart_lsn的监控,对于落后较大和长期不推进的lsn进行告警,说明主库wal堆积。