PostgreSQL高可用架构搭建:Patroni+etcd自动故障转移配置

PostgreSQL在生产环境中部署高可用架构是数据库运维的基础工作。Patroni配合etcd实现自动故障转移,在主库故障时自动选举新主库并将读副本提升为主库,恢复时间控制在30秒以内。本文给出完整的搭建步骤和故障转移测试方法。

高可用架构设计与组件说明

架构由三个节点组成,每个节点运行PostgreSQL和Patroni实例。etcd集群(3节点)作为分布式配置存储,负责Leader选举和集群状态协调。HAProxy作为读写分离代理,应用通过HAProxy连接数据库。

架构拓扑:

                   HAProxy
            (write:5432 read:5433)
                 |
    +------------+------------+
    |            |            |
  PG-1        PG-2        PG-3
  Leader      Replica      Replica
    |            |            |
    +------------+------------+
                 |
           etcd集群
          (3 nodes)

Patroni管理PostgreSQL生命周期,包括启动、停止、角色切换、复制配置。etcd存储集群拓扑信息(当前Leader、连接字符串、复制状态)。HAProxy通过Patroni REST API(端口8008)健康检查确定主库位置。

etcd集群搭建

三个节点分别安装etcd,配置集群发现。以三节点为例,IP为10.0.0.11、10.0.0.12、10.0.0.13。

# /etc/etcd/etcd.conf (节点1 - 10.0.0.11)
ETCD_NAME=node1
ETCD_DATA_DIR=/var/lib/etcd
ETCD_LISTEN_PEER_URLS=http://10.0.0.11:2380
ETCD_LISTEN_CLIENT_URLS=http://10.0.0.11:2379,http://127.0.0.1:2379
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://10.0.0.11:2380
ETCD_ADVERTISE_CLIENT_URLS=http://10.0.0.11:2379
ETCD_INITIAL_CLUSTER=node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380
ETCD_INITIAL_CLUSTER_TOKEN=pg-cluster
ETCD_INITIAL_CLUSTER_STATE=new

# 启动etcd
systemctl enable etcd
systemctl start etcd

# 验证集群状态
etcdctl --endpoints=http://10.0.0.11:2379 member list
etcdctl --endpoints=http://10.0.0.11:2379 endpoint health --cluster

Patroni配置与PostgreSQL初始化

每个节点安装Patroni并配置YAML文件。关键配置项包括etcd连接、PostgreSQL参数、复制槽、自动故障转移策略。

# /etc/patroni/patroni.yml (节点1)
scope: pg-cluster
name: node1

restapi:
  listen: 10.0.0.11:8008
  connect_address: 10.0.0.11:8008

etcd:
  hosts: 10.0.0.11:2379,10.0.0.12:2379,10.0.0.13:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 20
    maximum_lag_on_failover: 1048576  # 1MB
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 1024
        archive_mode: "on"
        archive_command: "cp %p /data/pg_archive/%f"

  initdb:
    - encoding: UTF8
    - data-checksums
    - locale: C

  pg_hba:
    - local all all trust
    - host all all 10.0.0.0/24 md5
    - host replication replicator 10.0.0.0/24 md5

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.0.11:5432
  data_dir: /data/pgdata
  bin_dir: /usr/pgsql-16/bin
  config_dir: /data/pgdata
  pgpass: /tmp/pgpass
  authentication:
    replication:
      username: replicator
      password: RepPass2026
    superuser:
      username: postgres
      password: PgSuper2026
  create_replica_methods:
    - basebackup

tags:
    nofailover: false
    noloadbalance: false
    clonefrom: false
# 创建复制用户(在Leader节点执行)
psql -U postgres -c "CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'RepPass2026';"

# 启动Patroni(三个节点依次启动)
patroni /etc/patroni/patroni.yml &

# 查看集群状态
patronictl -c /etc/patroni/patroni.yml list
# 输出示例:
# + Cluster: pg-cluster ----+---------+----+-----------+
# | Member  | Host         | Role    | State    | TL  |
# +---------+--------------+---------+----------+-----+
# | node1   | 10.0.0.11    | Leader  | running  |  1  |
# | node2   | 10.0.0.12    | Replica | streaming|  1  |
# | node3   | 10.0.0.13    | Replica | streaming|  1  |
# +---------+--------------+---------+----------+-----+

HAProxy读写分离配置

HAProxy通过Patroni REST API区分主库和副本。写请求路由到Leader,读请求分发到所有副本。

# /etc/haproxy/haproxy.cfg
frontend pg_write
    bind *:5432
    default_backend pg_primary

frontend pg_read
    bind *:5433
    default_backend pg_replicas

backend pg_primary
    option httpchk
    httpchk GET /primary
    server node1 10.0.0.11:5432 check port 8008
    server node2 10.0.0.12:5432 check port 8008
    server node3 10.0.0.13:5432 check port 8008

backend pg_replicas
    option httpchk
    httpchk GET /replica
    balance roundrobin
    server node1 10.0.0.11:5432 check port 8008
    server node2 10.0.0.12:5432 check port 8008
    server node3 10.0.0.13:5432 check port 8008

Patroni REST API的/primary端点只在Leader节点返回200,/replica只在Replica节点返回200。HAProxy根据健康检查结果动态路由请求,故障转移后自动将写请求路由到新Leader。

故障转移测试与数据备份恢复

模拟主库故障,验证自动切换:

# 1. 停止Leader节点的PostgreSQL
ssh 10.0.0.11
systemctl stop patroni

# 2. 观察集群状态变化(10-30秒内完成切换)
patronictl -c /etc/patroni/patroni.yml list
# node1变为unreachable,node2或node3提升为Leader

# 3. 验证写入能力
psql -h 10.0.0.10 -p 5432 -U postgres -c "CREATE TABLE failover_test(id int);"
# 写入成功,证明新Leader已接管

# 4. 恢复原Leader
systemctl start patroni
# node1自动以Replica角色重新加入集群

# 5. 手动switchover(计划内维护)
patronictl switchover --candidate node2 --force

数据备份恢复配合pgBackRest实现增量备份和时间点恢复(PITR):

# pgBackRest配置
[db]
cmd=/usr/pgsql-16/bin/pgbackrest
stanza=pg-cluster
pg1-host=10.0.0.11
pg1-path=/data/pgdata
repo1-type=s3
repo1-s3-endpoint=s3.yunthe.com
repo1-s3-bucket=pg-backup

# 全量备份
pgbackrest --stanza=pg-cluster backup --type=full

# 增量备份
pgbackrest --stanza=pg-cluster backup --type=incr

# 时间点恢复示例(恢复到指定时间)
pgbackrest --stanza=pg-cluster restore \
    --type=time --target="2026-07-24 14:30:00"

备份策略:每周日全量备份,每天增量备份,WAL日志持续归档。RPO(恢复点目标)控制在5分钟以内,RTO(恢复时间目标)在30分钟以内。

Patroni加etcd方案在三节点部署下能承受单节点故障而不中断服务。故障转移时间取决于ttl和loop_wait配置,默认配置下切换在20-30秒内完成。SQL查询优化方面,副本节点可承担只读查询压力,配合连接池(PgBouncer)进一步提升并发处理能力。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-gao-ke-yong-jia-gou-da-jian-patronietcd-zi-dong/

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

相关推荐