PostgreSQL逻辑复制配置与Patroni高可用集群搭建实战

PostgreSQL的逻辑复制(Logical Replication)基于WAL日志的解码层实现,只复制数据变更而非整个数据块,支持跨版本复制、选择性表复制和双向复制。Patroni在物理复制基础上提供自动故障检测和主从切换,是PostgreSQL高可用方案的事实标准。本文完整演示逻辑复制配置流程和Patroni高可用集群搭建,覆盖从单机到三节点高可用的完整路径。

逻辑复制与物理复制的区别

物理复制在数据块级别同步主库WAL日志到备库,备库与主库完全一致,是字节级复制。优势是延迟低、配置简单,劣势是备库必须与主库版本和架构一致,不能跨大版本,不能选择性复制表。

逻辑复制通过WAL解码插件(如pgoutput)将WAL日志解析为逻辑变更事件(INSERT/UPDATE/DELETE),再应用到目标库。优势是支持跨版本复制、选择性表复制、发布-订阅模型灵活。劣势是配置较复杂,不支持DDL复制(表结构变更需手动同步),大事务的复制延迟高于物理复制。

逻辑复制发布-订阅配置实战

以下在源库(publisher,192.168.1.10)和目标库(subscriber,192.168.1.20)之间配置逻辑复制,同步orders和customers两张表。

源库配置postgresql.conf:

# 必须设为logical才能支持逻辑复制
wal_level = logical
# 保留足够WAL日志,防止复制延迟时WAL被回收
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 1024MB

源库创建复制用户并授权:

CREATE ROLE replication_user WITH LOGIN REPLICATION PASSWORD 'StrongPass123!';

-- 授予待复制表的读权限
GRANT SELECT ON orders, customers TO replication_user;

源库创建发布(Publication):

-- 发布指定表
CREATE PUBLICATION pub_orders FOR TABLE orders, customers;

-- 发布所有表(谨慎使用)
-- CREATE PUBLICATION pub_all FOR ALL TABLES;

目标库pg_hba.conf允许源库连接:

# 允许源库IP通过复制用户连接
host    all    replication_user    192.168.1.10/32    md5

目标库创建订阅(Subscription):

CREATE SUBSCRIPTION sub_orders
  CONNECTION 'host=192.168.1.10 port=5432 dbname=prod user=replication_user password=StrongPass123!'
  PUBLICATION pub_orders
  WITH (
    copy_data = true,        -- 初始数据同步
    create_slot = true,      -- 自动创建复制槽
    enabled = true,
    slot_name = 'sub_orders_slot'
  );

copy_data设为true时,订阅创建后自动执行一次全表COPY将源库现有数据同步到目标库,之后持续通过WAL流复制增量变更。

验证复制状态:

-- 源库查看发布状态
SELECT * FROM pg_publication;

-- 目标库查看订阅状态
SELECT * FROM pg_subscription;

-- 查看复制进度
SELECT * FROM pg_stat_subscription;

逻辑复制冲突处理与跳过事务

逻辑复制常见的冲突场景:目标库存在主键冲突(INSERT重复)、外键约束冲突、CHECK约束冲突。冲突发生时复制会暂停,直到手动解决。

-- 查看订阅worker日志中的冲突信息
SELECT * FROM pg_stat_subscription

-- 跳过冲突事务(PostgreSQL 16+)
ALTER SUBSCRIPTION sub_orders SKIP (lsn = '0/1631748');

-- 重启订阅
ALTER SUBSCRIPTION sub_orders DISABLE;
ALTER SUBSCRIPTION sub_orders ENABLE;

生产环境建议在目标库表上设置主键,这是逻辑复制的最佳实践。无主键表的UPDATE和DELETE操作无法精确识别行,会导致复制异常。

Patroni高可用集群搭建

Patroni基于etcd实现分布式一致性,管理PostgreSQL主从切换。以下搭建3节点Patroni集群(1主2从)。

安装etcd集群(3节点):

# /etc/etcd/etcd.conf (节点1)
name: etcd1
data-dir: /var/lib/etcd
listen-peer-urls: http://0.0.0.0:2380
listen-client-urls: http://0.0.0.0:2379
initial-advertise-peer-urls: http://192.168.1.10:2380
advertise-client-urls: http://192.168.1.10:2379
initial-cluster: etcd1=http://192.168.1.10:2380,etcd2=http://192.168.1.20:2380,etcd3=http://192.168.1.30:2380
initial-cluster-token: etcd-cluster
initial-cluster-state: new

Patroni配置文件patroni.yml:

scope: pg-cluster
name: node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 192.168.1.10:8008

etcd:
  hosts: 192.168.1.10:2379,192.168.1.20:2379,192.168.1.30:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 20
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        max_wal_senders: 10
        max_connections: 200

  initdb:
    - encoding: UTF8
    - data-checksums

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 192.168.1.10:5432
  data_dir: /var/lib/postgresql/data
  bin_dir: /usr/pgsql-16/bin
  authentication:
    replication:
      username: replicator
      password: ReplPass456!
    superuser:
      username: postgres
      password: AdminPass789!
  parameters:
    archive_mode: "on"
    archive_command: "cp %p /backup/archive/%f"

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false

启动Patroni服务(3节点依次启动):

systemctl start patroni
systemctl enable patroni

# 查看集群状态
patronictl -c /etc/patroni/patroni.yml list

输出示例:

+ Cluster: pg-cluster (7017606987496831835) --+---------+----+-----------+
| Member | Host           | Role    | State   | TL | Lag in MB |
+--------+----------------+---------+---------+----+-----------+
| node1  | 192.168.1.10   | Leader  | running |  1 |           |
| node2  | 192.168.1.20   | Replica | running |  1 |         0 |
| node3  | 192.168.1.30   | Replica | running |  1 |         0 |
+--------+----------------+---------+---------+----+-----------+

自动故障切换与脑裂防护

当主库故障时,Patroni通过etcd的分布式锁机制选举新主库。选举条件:候选节点必须是同步备库(synchronous standby),且复制延迟小于maximum_lag_on_failover配置值。

手动执行switchover(计划内切换):

patronictl switchover -c /etc/patroni/patroni.yml

脑裂防护机制:Patroni Leader节点每ttl秒向etcd续约租约。如果Leader与etcd失联超过ttl秒,租约过期,其他节点发起新选举。旧Leader感知到失去Leader身份后,立即将自己降级为备库并停止接受写入,防止脑裂。

使用pg_rewind修复分裂脑后的数据不一致。当旧主库在脑裂期间接收了写入,重新加入集群时需要pg_rewind回退差异:

# 旧主库上执行
pg_rewind --target-data=/var/lib/postgresql/data   --source-server="host=192.168.1.20 user=postgres password=AdminPass789!"

# 然后重新启动Patroni
systemctl restart patroni

use_pg_rewind设为true时,Patroni在节点重新加入集群前自动执行pg_rewind,无需人工介入。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-luo-ji-fu-zhi-pei-zhi-yu-patroni-gao-ke-yong-ji/

(0)
小编小编
上一篇 11小时前
下一篇 11小时前

相关推荐