pg_restore后Bucardo主主复制异常:如何避免初始全量重同步?
解决Bucardo主主复制初始同步的伪变更问题
针对你遇到的Bucardo初始同步时删除源数据重插的问题,我来逐个解答你的疑问,并给出具体的解决方案:
1. Bucardo bucardo_latest策略依赖的时间戳
当使用bucardo_latest冲突解决策略时,Bucardo的判断逻辑分两种情况:
- 默认情况:它会使用自身内部表
bucardo_delta中记录的change_time字段,这个时间是Bucardo捕获到数据变更的时间点。 - 自定义时间戳字段:如果你在Bucardo中为表配置了
--last-modified-col=last_modified(添加表时的参数),那么它会优先使用你定义的last_modified字段来判断数据的新旧。
你的问题核心就在于:pg_restore恢复时触发了触发器,把所有数据的last_modified改成了恢复时的时间,导致这个时间比源数据库中数据的时间晚,Bucardo就会误判恢复节点的数据是"最新"的,进而触发全量覆盖操作。
2. 是否需要在pg_dump时设置SESSION_REPLICATION_ROLE = 'replica'?
不需要在pg_dump阶段设置,因为pg_dump本身只是读取数据,不会触发表上的触发器。但必须在pg_restore阶段设置这个参数,这样才能避免恢复过程中触发用户定义的触发器(包括维护last_modified的UPDATE触发器),让恢复的数据保留原始的last_modified值和用户追踪字段。
3. pg_restore是否支持设置SESSION_REPLICATION_ROLE?
当然支持,有几种实用的方式:
方式一:直接使用pg_restore的--set参数(PostgreSQL 9.6+)
这是最简便的方法,直接在恢复命令中指定会话级参数:
pg_restore --set SESSION_REPLICATION_ROLE=replica -d your_database -Fc your_backup.dump
这个参数会在恢复会话开始时自动执行SET SESSION_REPLICATION_ROLE = 'replica';,禁用所有用户触发器,恢复完成后会话结束,参数会自动失效。
方式二:管道配合psql(兼容旧版本)
如果你的PostgreSQL版本低于9.6,不支持--set参数,可以通过管道把pg_restore的输出传给psql,并提前设置参数:
pg_restore -f - -Fc your_backup.dump | psql -c "SET SESSION_REPLICATION_ROLE='replica';" -d your_database
方式三:生成SQL文件后修改
先把自定义格式的备份转换成纯SQL文件:
pg_restore -f restore_script.sql -Fc your_backup.dump
然后在restore_script.sql的最开头添加一行:
SET SESSION_REPLICATION_ROLE = 'replica';
最后用psql执行这个脚本:
psql -d your_database -f restore_script.sql
额外的优化建议
- 重新恢复所有节点:用上述方法重新生成并恢复备份,确保所有节点的
last_modified字段保留原始数据的时间戳,这样Bucardo启动同步时就不会误判伪变更。 - 确认Bucardo表配置:检查你添加表到Bucardo集群的命令,确保指定了使用自定义的
last_modified字段,比如:
这样Bucardo会直接用业务层面的时间戳来判断冲突,比依赖内部的bucardo add table your_table --db=your_db --last-modified-col=last_modifiedchange_time更准确。 - 验证触发器状态:恢复完成后,可以手动查询表中的
last_modified字段,确认没有被修改为恢复时间,确保触发器在恢复过程中确实被禁用了。
内容的提问来源于stack exchange,提问作者Jürgen Zornig
相关产品推荐
相关产品推荐

