Skip to content

PostgreSQL 双向复制与多主架构

双向复制架构概述

双向复制(Bidirectional Replication)是指两个或多个PostgreSQL实例之间相互复制数据的架构,每个实例既可以作为主库接收写入,也可以作为从库复制其他实例的数据。

适用场景

  • 地理分布式部署,需要在多个数据中心同时处理写入
  • 需要提高写入可用性,避免单一主库瓶颈
  • 应用层需要就近写入,减少网络延迟

架构类型

  1. 基于流复制的双向复制

    • 利用PostgreSQL原生流复制机制
    • 需要额外工具处理冲突
    • 适合PostgreSQL 9.0及以上版本
  2. 基于逻辑复制的多主架构

    • 利用PostgreSQL 10+的逻辑复制功能
    • 支持表级复制,灵活性更高
    • 冲突处理相对简单
  3. 第三方解决方案

    • Bucardo:成熟的PostgreSQL多主复制解决方案
    • Slony-I:基于触发器的复制系统
    • pglogical:高级逻辑复制扩展

基于流复制的双向复制配置

前提条件

  • PostgreSQL 9.0+版本
  • 两个实例具有相同的PostgreSQL版本
  • 实例间网络互通,防火墙已开放端口
  • 已配置SSH免密登录(用于基础备份)

配置步骤

1. 初始化两个PostgreSQL实例

在两台服务器上分别安装并初始化PostgreSQL:

bash
# 服务器A(192.168.1.10)
pgsql -c "CREATE USER replication REPLICATION LOGIN CONNECTION LIMIT 10 ENCRYPTED PASSWORD 'replication_pass';"

# 服务器B(192.168.1.20)
pgsql -c "CREATE USER replication REPLICATION LOGIN CONNECTION LIMIT 10 ENCRYPTED PASSWORD 'replication_pass';"

2. 配置pg_hba.conf

在两台服务器的pg_hba.conf中添加复制权限:

# 服务器A
host    replication     replication     192.168.1.20/32        scram-sha-256

# 服务器B
host    replication     replication     192.168.1.10/32        scram-sha-256

3. 配置postgresql.conf

在两台服务器上启用流复制相关参数:

# 服务器A与B共享配置
wal_level = replica          # PostgreSQL 10+使用replica,9.x使用hot_standby
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
log_replication_commands = on

4. 配置双向复制

  • 从服务器A到服务器B的复制

    bash
    # 在服务器B上执行
    pg_basebackup -h 192.168.1.10 -U replication -D $PGDATA -Fp -Xs -P -R
  • 从服务器B到服务器A的复制

    bash
    # 在服务器A上执行
    pg_basebackup -h 192.168.1.20 -U replication -D $PGDATA -Fp -Xs -P -R

5. 修改recovery.conf/recovery.signal

PostgreSQL 12+使用recovery.signal,之前版本使用recovery.conf:

bash
# 服务器A的recovery.signal
touch $PGDATA/recovery.signal
echo "primary_conninfo = 'host=192.168.1.20 port=5432 user=replication password=replication_pass application_name=server_a'" >> $PGDATA/postgresql.auto.conf
echo "standby_mode = 'on'" >> $PGDATA/postgresql.auto.conf

# 服务器B的recovery.signal
touch $PGDATA/recovery.signal
echo "primary_conninfo = 'host=192.168.1.10 port=5432 user=replication password=replication_pass application_name=server_b'" >> $PGDATA/postgresql.auto.conf
echo "standby_mode = 'on'" >> $PGDATA/postgresql.auto.conf

6. 启动服务并验证

bash
# 启动两台服务器的PostgreSQL服务
systemctl start postgresql-14

# 验证复制状态
# 在服务器A上
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

# 在服务器B上
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

基于逻辑复制的多主架构

前提条件

  • PostgreSQL 10+版本
  • 所有实例具有相同的PostgreSQL版本
  • 已安装pgoutput插件(默认包含)

配置步骤

1. 配置postgresql.conf

wal_level = logical          # 必须设置为logical
max_replication_slots = 10
max_wal_senders = 10
max_logical_replication_workers = 4
max_worker_processes = 16

2. 创建复制用户

sql
CREATE USER logical_repl WITH REPLICATION LOGIN PASSWORD 'logical_repl_pass';

3. 配置pg_hba.conf

host    replication     logical_repl    0.0.0.0/0            scram-sha-256
host    all             logical_repl    0.0.0.0/0            scram-sha-256

4. 创建发布者

在每个节点上创建发布,指定需要复制的表:

sql
-- 在节点1上
CREATE PUBLICATION pub_node1 FOR ALL TABLES;

-- 在节点2上
CREATE PUBLICATION pub_node2 FOR ALL TABLES;

5. 创建订阅者

在每个节点上创建订阅,订阅其他节点的发布:

sql
-- 在节点1上订阅节点2
CREATE SUBSCRIPTION sub_node2
  CONNECTION 'host=node2 port=5432 dbname=mydb user=logical_repl password=logical_repl_pass'
  PUBLICATION pub_node2
  WITH (copy_data=true, create_slot=true);

-- 在节点2上订阅节点1
CREATE SUBSCRIPTION sub_node1
  CONNECTION 'host=node1 port=5432 dbname=mydb user=logical_repl password=logical_repl_pass'
  PUBLICATION pub_node1
  WITH (copy_data=true, create_slot=true);

6. 验证复制状态

sql
-- 查看发布状态
SELECT * FROM pg_publication;
SELECT * FROM pg_publication_tables;

-- 查看订阅状态
SELECT * FROM pg_subscription;
SELECT * FROM pg_stat_subscription;

冲突处理策略

多主架构中最核心的挑战是处理数据冲突,当两个节点同时修改同一行数据时会产生冲突。

冲突类型

  1. 主键冲突:两个节点同时插入具有相同主键的记录
  2. 唯一约束冲突:违反唯一约束
  3. 更新冲突:同一行数据在不同节点被修改
  4. 删除冲突:一个节点删除记录,另一个节点修改同一记录

冲突解决方法

1. 应用层冲突避免

  • 分片策略:根据业务逻辑将数据分片,每个分片只在一个节点上写入
  • 时间戳冲突检测:使用全局唯一时间戳标记数据版本
  • 乐观锁:使用版本号或时间戳进行冲突检测

2. 数据库层冲突处理

  • 冲突检测与记录:使用PostgreSQL的冲突检测机制记录冲突
  • 冲突自动解决策略
    • 最后更新获胜(Last Update Wins)
    • 节点优先级策略(Primary Node Wins)
    • 自定义冲突解决函数

3. 第三方工具冲突处理

  • Bucardo:提供多种冲突解决策略,包括自定义Python脚本
  • pglogical:支持冲突检测和自定义解决方法

基于Bucardo的多主复制

Bucardo概述

Bucardo是一个成熟的PostgreSQL多主复制解决方案,基于触发器实现,支持复杂的复制拓扑。

安装与配置

1. 安装依赖

bash
# CentOS/RHEL
yum install -y perl-DBI perl-DBD-Pg perl-ExtUtils-MakeMaker

# Ubuntu/Debian
apt-get install -y libdbi-perl libdbd-pg-perl libextutils-makemaker-perl

2. 安装Bucardo

bash
wget https://bucardo.org/downloads/Bucardo-5.6.0.tar.gz
tar xzf Bucardo-5.6.0.tar.gz
cd Bucardo-5.6.0
perl Makefile.PL
sudo make install

3. 初始化Bucardo

bash
sudo -u postgres bucardo_ctl install

4. 配置Bucardo

bash
# 启动Bucardo守护进程
sudo -u postgres bucardo_ctl start

# 添加数据库连接
bucardo_ctl add db db1 dbname=mydb host=node1 user=bucardo password=bucardo_pass
bucardo_ctl add db db2 dbname=mydb host=node2 user=bucardo password=bucardo_pass

# 创建表组
bucardo_ctl add tables all --db=db1 --group=my_tables

# 创建复制集
bucardo_ctl add sync my_sync type=twoway dbs=db1:source,db2:source tables=my_tables conflict_strategy=latest

# 启动复制
bucardo_ctl start sync my_sync

监控与管理

bash
# 查看Bucardo状态
bucardo_ctl status

# 查看复制状态
bucardo_ctl list syncs

# 查看冲突
bucardo_ctl list conflicts

# 重启Bucardo
bucardo_ctl restart

多主架构最佳实践

架构设计

  1. 限制节点数量:建议不超过4个节点,节点越多冲突概率越高
  2. 合理规划网络:确保节点间网络延迟低且稳定
  3. 统一时钟:所有节点使用NTP服务同步时钟

性能优化

  1. 调整WAL参数

    wal_compression = on
    wal_buffers = 16MB
    checkpoint_completion_target = 0.9
  2. 优化逻辑复制

    max_logical_replication_workers = 8
    max_parallel_workers = 16
  3. 合理设置复制槽:定期清理不再使用的复制槽

冲突管理

  1. 选择合适的冲突解决策略:根据业务需求选择
  2. 监控冲突:设置告警机制,及时发现并处理冲突
  3. 定期分析冲突:优化应用设计,减少冲突发生

高可用性

  1. 结合HA工具:多主架构可与Patroni、repmgr等HA工具结合使用
  2. 设置故障自动隔离:当节点出现问题时自动隔离,避免数据不一致
  3. 定期备份:即使有复制,也要定期进行全量备份

常见问题与解决方案

1. 复制延迟过高

原因

  • 网络带宽不足
  • 写入量过大
  • 冲突处理消耗资源

解决方案

  • 优化网络配置,增加带宽
  • 调整WAL参数,提高WAL生成效率
  • 优化应用设计,减少跨节点写入冲突

2. 冲突频繁发生

原因

  • 应用层设计不合理
  • 数据分片策略不当
  • 时钟不同步

解决方案

  • 重新设计应用,避免跨节点同时写入同一数据
  • 调整数据分片策略,确保数据只在一个节点写入
  • 配置NTP服务,确保所有节点时钟同步

3. 复制中断

原因

  • 网络中断
  • 节点崩溃
  • 复制槽故障

解决方案

  • 检查网络连接,修复网络问题
  • 重启故障节点,重新建立复制
  • 重新创建复制槽,恢复复制

版本差异注意事项

PostgreSQL 9.x

  • 仅支持基于流复制的双向复制
  • 需要使用recovery.conf配置文件
  • 不支持逻辑复制

PostgreSQL 10-11

  • 支持基础逻辑复制功能
  • 逻辑复制不支持DDL复制
  • 冲突处理需要手动干预

PostgreSQL 12+

  • 支持recovery.signal替代recovery.conf
  • 逻辑复制性能提升
  • 支持更多的冲突检测机制

PostgreSQL 14+

  • 逻辑复制支持并行应用
  • 新增冲突处理相关视图
  • 复制槽管理功能增强