PostgreSQL逻辑复制订阅端批量数据更新后出现duplicate key错误求助
问题成因
- PostgreSQL 13.1存在已知逻辑复制重试缺陷:当WAL传输过程中出现网络断连、超时等异常时,发布端的walsender进程不会正确标记已成功发送到订阅端的WAL偏移量,重试传输时会重复推送已被订阅端应用过的事务片段,直接触发主键/唯一键冲突报错。你在发布端看到的
could not send data to client: Connection reset by peer就是传输超时触发的TCP断连日志,断连后的无校验重试是重复写入的核心原因。 - 每月执行的批量删除+90GB数据导入操作会在短时间内生成巨量WAL日志,订阅端的apply进程消费速度跟不上WAL发送速度时,会进一步触发传输超时,放大上述缺陷的触发概率。
- 5个订阅端并发占用发布端的walsender资源,资源争抢会随机导致某几个订阅端的传输断连,因此出错的订阅端并不固定。
修复方案
临时规避方案(无需升级数据库版本)
- 每月执行批量数据更新前,先暂停所有订阅端的复制链路:
ALTER SUBSCRIPTION 你的订阅名称 DISABLE;,等发布端全量数据导入完成、WAL写入回归正常水平后,再重新启用订阅:ALTER SUBSCRIPTION 你的订阅名称 ENABLE;。 - 调整两侧数据库的逻辑复制超时参数,降低断连概率:
发布端postgresql.conf修改配置:
订阅端postgresql.conf修改配置:wal_sender_timeout = 5min # 默认为1min,适配大流量批量传输场景 max_wal_senders = 10 # 取值至少大于订阅端数量+3的预留值,避免资源不足wal_receiver_timeout = 5min max_logical_replication_workers = 10 - 拆分单次批量导入的事务大小,避免单事务产生GB级以上的WAL日志,降低订阅端消费卡顿概率。
永久修复方案
将所有节点的PostgreSQL小版本升级至13.4及以上,该版本已官方修复逻辑复制重试时重复推送WAL片段的BUG,从根源避免重复键冲突问题。
内容的提问来源于stack exchange,提问作者Giles
相关产品推荐
相关产品推荐

