【PostgreSQL从零到精通】第47篇:Bucardo多主复制——实现真正的双向数据同步
上一篇【第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_level=logical max_replication_slots=10listen_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\--dbhost=127.0.0.1\--dbport=5432\--dbuser=postgres\--dbname=bucardo\--dbpass=postgres# 安装完成后会创建:# - bucardo 数据库# - bucardo 数据库用户# - 各种元数据表和函数四、搭建多主复制
4.1 添加数据库节点
# 添加要同步的数据库# bucardo add database <名称> <连接信息>bucardoadddatabase db_a\dbhost=node_adbname=mydbdbuser=bucardodbpass=xxx bucardoadddatabase db_b\dbhost=node_bdbname=mydbdbuser=bucardodbpass=xxx# 验证bucardo list databases4.2 添加同步的表组(Herd)
# 创建 herd 并添加表bucardoaddherd sales_herd# 添加表到 herd(需要在 db_a 上存在)bucardoaddtable ordersdb=db_aherd=sales_herd bucardoaddtable order_itemsdb=db_aherd=sales_herd bucardoaddtable customersdb=db_aherd=sales_herd# 添加所有 public schema 下的表# bucardo add all tables --db=db_a --herd=sales_herd# 验证bucardo list tables4.3 创建同步(Sync)
# 创建多主同步# bucardo add sync <名称> herd=<herd> dbs=<节点列表> relgroup=<分组>bucardoaddsyncsales_sync\herd=sales_herd\dbs=db_a,db_b\relgroup=sales_rg\conflict_strategy=bucardo_latest# 查看同步状态bucardo list syncs4.4 启动 Bucardo
# 启动 Bucardo 守护进程bucardo start# 查看运行状态bucardo status# 查看详细信息bucardo list syncs--show# 停止bucardo stop# 重启bucardo restart4.5 添加新的同步表
# 运行时动态添加表bucardoaddtable productsdb=db_aherd=sales_herd bucardoaddtable productsdb=db_bherd=sales_herd# 重新激活同步bucardo activatesyncsales_sync# 如果需要完全重建同步bucardo removesyncsales_sync# 重新 add sync ...五、冲突处理策略
5.1 冲突产生的原因
多主复制的冲突场景: 时间线:T1 → T2 → T3 Node A: UPDATE id=1 (name='Alice') → 同步到 B → B 上的旧版本被覆盖 Node B: UPDATE id=1 (name='Bob') → 同步到 A → A 上的新版本被覆盖 结果:取决于同步顺序,可能丢失其中一方的修改5.2 Bucardo 的冲突解决策略
# 创建同步时指定冲突策略# --conflict_strategy 或 -c 参数# 1. bucardo_latest —— 最后更新的获胜(默认)# 使用事务时间戳比较bucardoaddsync...--conflict_strategy=bucardo_latest# 2. latest —— 数据库本地时间最新的获胜# 使用 xact_stamp 字段(如果表有的话)bucardoaddsync...--conflict_strategy=latest# 3. abort —— 遇到冲突时中止同步,等待人工处理bucardoaddsync...--conflict_strategy=abort# 4. random —— 随机选一个bucardoaddsync...--conflict_strategy=random# 5. custom —— 使用自定义的冲突处理函数# 需要在数据库中创建自定义函数bucardoaddsync...--conflict_strategy=my_custom_func5.3 自定义冲突处理
-- 创建自定义冲突处理函数-- 函数签名必须符合 Bucardo 的规范CREATEORREPLACEFUNCTIONbucardo_custom_conflict()RETURNStextAS$$DECLAREv_new_idint;BEGIN-- 记录冲突日志INSERTINTOconflict_log(table_name,conflict_time)VALUES('orders',now());-- 选择保留哪个版本的逻辑RETURN'new';-- '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的水平扩展利器
