上一篇【第46篇】Slony-I逻辑复制——传统的主从复制方案下一篇【第48篇】PL/Proxy数据分片——PostgreSQL的水平扩展利器在前面的文章中无论是物理复制、逻辑复制还是 Slony-I都只支持单向主从复制——备库不能写入。但有些场景确实需要双主甚至多主写入比如多个数据中心同时服务本地用户、或者需要零停机迁移时两边同时写入。Bucardo就是 PostgreSQL 生态中最成熟的多主复制方案。一、Bucardo 概述1.1 核心特点Bucardo 的核心特点 ┌──────────────────────────────────────────────────────────┐ │ ✅ 多主复制Multi-Master—— 多个节点都能写入 │ │ ✅ 源-目的复制Source-Target—— 单向也可以 │ │ ✅ 多种冲突解决策略 │ │ ✅ 支持行级和列级别的选择性同步 │ │ ✅ 支持自定义冲突处理逻辑 │ │ ✅ 基于触发器捕获变更 │ │ ⚠️ 依赖 Perl需要较完整的 Perl 环境 │ │ ⚠️ 配置较复杂维护成本高 │ └──────────────────────────────────────────────────────────┘1.2 两种复制模式多主复制Multi-Master / m/m ┌──────────┐ 双向同步 ┌──────────┐ │ Node A │ ←────────→ │ Node B │ │ (可读写) │ │ (可读写) │ └──────────┘ └──────────┘ 两个节点都接受写入Bucardo 负责合并变更 源-目的复制Source-Target / push/pull ┌──────────┐ 单向推送 ┌──────────┐ │ Source │ ────────→ │ Target │ │ (可读写) │ │ (可读) │ └──────────┘ └──────────┘ 类似普通主从但可以按表/列选择同步内容二、安装与配置2.1 依赖安装# Bucardo 依赖 Perl 和多个 CPAN 模块# CentOS/RHELsudoyuminstallperl perl-DBI perl-DBD-Pg postgresql-devel# 安装 Perl 模块sudocpan DBD::Pgsudocpan DBIx::Safesudocpan Encode::Localesudocpan boolean# 或使用 cpanm更方便sudocpanm--notestDBD::Pg DBIx::Safe Encode::Locale boolean# 安装 Bucardo# 从源码安装wgethttps://bucardo.org/Bucardo.tar.gztarxzf Bucardo.tar.gzcdBucardo perl Makefile.PLmakesudomakeinstall# 验证安装bucardo--version2.2 数据库准备-- 在每个节点上执行-- 确保 PostgreSQL 配置-- postgresql.confwal_levellogical max_replication_slots10listen_addresses*-- pg_hba.conf 添加 Bucardo 的访问权限# host all bucardo 0.0.0.0/0 md5三、核心概念3.1 关键术语Bucardo 的核心概念 ┌──────────────────────────────────────────────────────────────┐ │ │ │ Barn仓库包含所有 Bucardo 元数据的数据库 │ │ └── 默认名为 bucardo独立于业务数据库 │ │ │ │ Herd牛群一组需要同步的表 │ │ └── 例如sales_herd {orders, order_items, customers} │ │ │ │ Sync同步定义复制规则 │ │ ├── 源端 herd → 目标端 herd │ │ ├── 复制模式m/m 或 push/pull │ │ └── 冲突解决策略 │ │ │ │ Relay中继可选的中继数据库减少直接连接 │ │ │ │ Goat山羊表中被排除同步的列 │ │ │ └──────────────────────────────────────────────────────────────┘3.2 初始化 Bucardo# 初始化 Bucardo创建 bucardo 管理库bucardoinstall# 交互式设置# 提示输入 PostgreSQL 连接信息# 默认连接本地的 PostgreSQL# 指定连接信息bucardoinstall\--dbhost127.0.0.1\--dbport5432\--dbuserpostgres\--dbnamebucardo\--dbpasspostgres# 安装完成后会创建# - bucardo 数据库# - bucardo 数据库用户# - 各种元数据表和函数四、搭建多主复制4.1 添加数据库节点# 添加要同步的数据库# bucardo add database 名称 连接信息bucardoadddatabase db_a\dbhostnode_adbnamemydbdbuserbucardodbpassxxx bucardoadddatabase db_b\dbhostnode_bdbnamemydbdbuserbucardodbpassxxx# 验证bucardo list databases4.2 添加同步的表组Herd# 创建 herd 并添加表bucardoaddherd sales_herd# 添加表到 herd需要在 db_a 上存在bucardoaddtable ordersdbdb_aherdsales_herd bucardoaddtable order_itemsdbdb_aherdsales_herd bucardoaddtable customersdbdb_aherdsales_herd# 添加所有 public schema 下的表# bucardo add all tables --dbdb_a --herdsales_herd# 验证bucardo list tables4.3 创建同步Sync# 创建多主同步# bucardo add sync 名称 herdherd dbs节点列表 relgroup分组bucardoaddsyncsales_sync\herdsales_herd\dbsdb_a,db_b\relgroupsales_rg\conflict_strategybucardo_latest# 查看同步状态bucardo list syncs4.4 启动 Bucardo# 启动 Bucardo 守护进程bucardo start# 查看运行状态bucardo status# 查看详细信息bucardo list syncs--show# 停止bucardo stop# 重启bucardo restart4.5 添加新的同步表# 运行时动态添加表bucardoaddtable productsdbdb_aherdsales_herd bucardoaddtable productsdbdb_bherdsales_herd# 重新激活同步bucardo activatesyncsales_sync# 如果需要完全重建同步bucardo removesyncsales_sync# 重新 add sync ...五、冲突处理策略5.1 冲突产生的原因多主复制的冲突场景 时间线T1 → T2 → T3 Node A: UPDATE id1 (nameAlice) → 同步到 B → B 上的旧版本被覆盖 Node B: UPDATE id1 (nameBob) → 同步到 A → A 上的新版本被覆盖 结果取决于同步顺序可能丢失其中一方的修改5.2 Bucardo 的冲突解决策略# 创建同步时指定冲突策略# --conflict_strategy 或 -c 参数# 1. bucardo_latest —— 最后更新的获胜默认# 使用事务时间戳比较bucardoaddsync...--conflict_strategybucardo_latest# 2. latest —— 数据库本地时间最新的获胜# 使用 xact_stamp 字段如果表有的话bucardoaddsync...--conflict_strategylatest# 3. abort —— 遇到冲突时中止同步等待人工处理bucardoaddsync...--conflict_strategyabort# 4. random —— 随机选一个bucardoaddsync...--conflict_strategyrandom# 5. custom —— 使用自定义的冲突处理函数# 需要在数据库中创建自定义函数bucardoaddsync...--conflict_strategymy_custom_func5.3 自定义冲突处理-- 创建自定义冲突处理函数-- 函数签名必须符合 Bucardo 的规范CREATEORREPLACEFUNCTIONbucardo_custom_conflict()RETURNStextAS$$DECLAREv_new_idint;BEGIN-- 记录冲突日志INSERTINTOconflict_log(table_name,conflict_time)VALUES(orders,now());-- 选择保留哪个版本的逻辑RETURNnew;-- new 表示用新版本覆盖旧版本END;$$LANGUAGEplpgsql;六、常用管理命令# 数据库管理 bucardo list databases# 列出所有数据库bucardo remove database db_name# 移除数据库# 表管理 bucardo list tables# 列出所有被追踪的表bucardo kick sales_sync0# 立即触发一次同步# 同步管理 bucardo list syncs# 列出所有同步bucardo activatesyncxxx# 激活同步bucardo deactivatesyncxxx# 暂停同步bucardo removesyncxxx# 删除同步# 监控 bucardo status# 运行状态概览bucardo list horses# 运行中的工作进程bucardo list deltas# 等待同步的变更# 日志查看 # Bucardo 日志通常在tail-f/var/log/bucardo/bucardo.log七、Bucardo 的适用场景与限制7.1 适用场景Bucardo 最适合的场景 1. 双活数据中心 两个 IDC 同时服务本地用户数据双向同步 2. 零停机数据库迁移 新旧库同时写入逐步切换流量最后停止旧库 3. 数据聚合 多个远程节点的数据汇总到中心节点 4. 特殊的单向同步需求 需要按列过滤、冲突策略等高级功能7.2 主要限制Bucardo 的限制 ┌──────────────────────────────────────────────────────────┐ │ 1. 依赖 Perl 环境部署门槛较高 │ │ 2. 基于触发器性能开销与 Slony-I 类似 │ │ 3. 大事务延迟较大 │ │ 4. 不自动同步 DDL │ │ 5. 冲突处理在多主场景下仍然复杂 │ │ 6. 社区活跃度不如内置逻辑复制 │ │ 7. 文档较少排错困难 │ └──────────────────────────────────────────────────────────┘八、总结Bucardo是 PostgreSQL 生态中最成熟的多主复制方案两种模式多主m/m和源-目的push/pull核心概念Barn管理库→ Herd表组→ Sync同步规则冲突处理提供多种策略也支持自定义函数部署门槛依赖 Perl配置复杂新项目建议优先评估 PG 内置方案下一篇我们学习PL/Proxy数据分片——PostgreSQL的水平扩展利器。标签PostgreSQL、Bucardo、多主复制、双向同步、冲突处理、数据分片上一篇【第46篇】Slony-I逻辑复制——传统的主从复制方案下一篇【第48篇】PL/Proxy数据分片——PostgreSQL的水平扩展利器