PostgreSQL:Patroni 高可用架构,基于etcd的自动故障转移集群
2026/4/19 1:05:44 网站建设 项目流程

文章目录

    • 一、核心概念与架构
      • 1.1 Patroni 是什么?
      • 1.2 架构组成
    • 二、环境规划
      • 2.1 节点角色与 IP
    • 三、部署 etcd 集群
      • 3.1 安装 etcd(以 CentOS 为例)
      • 3.2 创建配置文件
      • 3.3 启动 etcd
      • 3.4 验证 etcd 集群
    • 四、部署 PostgreSQL 与 Patroni
      • 4.1 安装 PostgreSQL(所有 PG 节点)
      • 4.2 安装 Patroni
      • 4.3 配置 Patroni(以 pg1 为例)
      • 4.4 创建数据目录并授权
      • 4.5 启动 Patroni
    • 五、集群状态验证
      • 5.1 使用 patronictl 查看集群
      • 5.2 访问 REST API
      • 5.3 验证流复制
    • 六、自动故障转移演练
      • 6.1 模拟主库宕机
      • 6.2 观察自动切换
      • 6.3 验证新主库
      • 6.4 恢复原主库
    • 七、应用连接与负载均衡(HAProxy)
      • 7.1 安装 HAProxy
      • 7.2 配置 HAProxy(/etc/haproxy/haproxy.cfg)
      • 7.3 启动 HAProxy
    • 八、高级特性与运维
      • 8.1 手动切换(Switchover)
      • 8.2 配置动态重载
      • 8.3 备份集成
      • 8.4 监控与告警
    • 九、常见问题与实践建议
      • 9.1 脑裂防护
      • 9.2 网络分区(Split-Brain)
      • 9.3 性能建议
      • 9.4 安全加固

PostgreSQL 本身具备强大的流复制能力,但缺乏内置的自动故障转移(Automatic Failover)机制。为实现生产级高可用(High Availability, HA),社区广泛采用Patroni配合分布式协调服务(如 etcd、Consul、ZooKeeper)构建自动主备切换集群。本文将从原理、架构、部署、配置、演练到运维,详解基于 etcd 的 Patroni 高可用集群。


一、核心概念与架构

1.1 Patroni 是什么?

Patroni 是一个用 Python 编写的 PostgreSQL 高可用模板(Template),由 Zalando 开发并开源。它不修改 PostgreSQL 源码,而是通过外部守护进程(Daemon)管理 PostgreSQL 实例的生命周期,结合分布式协调器(DCS)实现:

  • 自动主节点选举(Leader Election)
  • 故障检测与自动 Failover
  • 在线配置重载
  • RESTful API 管理接口
  • 支持多副本、同步/异步复制、级联复制等

1.2 架构组成

一个典型的 Patroni + etcd 高可用集群包含以下组件:

组件作用
PostgreSQL 实例数据库服务,运行在每个节点
Patroni 进程每个节点运行一个,监控本地 PG 状态,与 DCS 通信
etcd 集群分布式键值存储,用于存储集群元数据、锁、Leader 信息(至少 3 节点以容忍 1 节点故障)
HAProxy / PgBouncer(可选)应用连接代理,自动路由读写请求
VIP / DNS / Service Discovery(可选)提供统一访问入口

典型拓扑(3 节点 PG + 3 节点 etcd):

+----------------+ +----------------+ +----------------+ | PG Node 1 | | PG Node 2 | | PG Node 3 | | - PostgreSQL | | - PostgreSQL | | - PostgreSQL | | - Patroni |<--->| - Patroni |<--->| - Patroni | +----------------+ +----------------+ +----------------+ ^ ^ ^ | | | +----------------------+----------------------+ | +-------------+ | etcd Cluster (3 nodes) | +-------------+

注意:etcd 可独立部署,也可与 PG 节点共存(不推荐生产环境混部)。


二、环境规划

2.1 节点角色与 IP

主机名IP 地址角色说明
etcd1192.168.10.10etcdetcd 集群成员
etcd2192.168.10.11etcdetcd 集群成员
etcd3192.168.10.12etcdetcd 集群成员
pg1192.168.10.20PostgreSQL + Patroni数据库节点
pg2192.168.10.21PostgreSQL + Patroni数据库节点
pg3192.168.10.22PostgreSQL + Patroni数据库节点
haproxy192.168.10.30HAProxy应用连接代理(可选)

操作系统:CentOS 7 或 Ubuntu 20.04+
PostgreSQL 版本:14(所有 PG 节点版本必须一致)
Python 版本:3.6+


三、部署 etcd 集群

etcd 是 Patroni 的“大脑”,用于存储集群状态。需部署奇数节点(3、5…)以支持容错。

3.1 安装 etcd(以 CentOS 为例)

在 etcd1、etcd2、etcd3 上执行:

# 下载 etcdETCD_VER=v3.5.10wgethttps://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gztarxzvf etcd-${ETCD_VER}-linux-amd64.tar.gzsudocpetcd-${ETCD_VER}-linux-amd64/etcd* /usr/local/bin/

3.2 创建配置文件

以 etcd1 为例(/etc/etcd/etcd.conf.yml):

name:etcd1data-dir:/var/lib/etcdlisten-peer-urls:http://192.168.10.10:2380listen-client-urls:http://192.168.10.10:2379,http://127.0.0.1:2379initial-advertise-peer-urls:http://192.168.10.10:2380advertise-client-urls:http://192.168.10.10:2379initial-cluster:etcd1=http://192.168.10.10:2380,etcd2=http://192.168.10.11:2380,etcd3=http://192.168.10.12:2380initial-cluster-token:pg-etcd-tokeninitial-cluster-state:new

etcd2 和 etcd3 修改name、IP 即可。

3.3 启动 etcd

创建 systemd 服务(/etc/systemd/system/etcd.service):

[Unit] Description=etcd After=network.target [Service] Type=exec ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.conf.yml Restart=always User=root [Install] WantedBy=multi-user.target

启动:

sudosystemctl daemon-reloadsudosystemctlenable--now etcd

3.4 验证 etcd 集群

在任意 etcd 节点执行:

etcdctl --endpoints=http://192.168.10.10:2379,http://192.168.10.11:2379,http://192.168.10.12:2379 endpoint health

应全部返回healthy


四、部署 PostgreSQL 与 Patroni

4.1 安装 PostgreSQL(所有 PG 节点)

# CentOSsudoyuminstall-y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpmsudoyuminstall-y postgresql14-server postgresql14-contrib# 不要初始化!Patroni 会自动初始化

4.2 安装 Patroni

sudoyuminstall-y python3-pip pip3installpatroni[etcd]psycopg2-binary

验证安装:

patroni --version

4.3 配置 Patroni(以 pg1 为例)

创建/etc/patroni/patroni.yml

scope:pg-ha-cluster# 集群名称,所有节点必须一致namespace:/service/# etcd 中的命名空间name:pg1# 本节点名称,必须唯一restapi:listen:192.168.10.20:8008# Patroni API 监听地址connect_address:192.168.10.20:8008etcd:hosts:# etcd 集群地址-192.168.10.10:2379-192.168.10.11:2379-192.168.10.12:2379bootstrap:dcs:ttl:30# Leader 锁 TTL(秒)loop_wait:10# 主循环间隔retry_timeout:10# 操作超时maximum_lag_on_failover:1048576# 最大允许延迟(字节),约 1MBsynchronous_mode:false# 是否启用同步复制postgresql:use_pg_rewind:true# 故障恢复时使用 pg_rewinduse_slots:true# 使用复制槽防止 WAL 过早清理parameters:wal_level:replicahot_standby:"on"max_connections:200max_wal_senders:10wal_keep_size:1GBmax_replication_slots:10checkpoint_completion_target:0.9archive_mode:"off"initdb:-encoding:UTF8-data-checksums# 启用数据页校验,pg_rewind 必需users:admin:# 初始化超级用户password:admin123options:-createrole-createdbpostgresql:listen:192.168.10.20:5432# PostgreSQL 监听地址connect_address:192.168.10.20:5432data_dir:/var/lib/pgsql/14/databin_dir:/usr/pgsql-14/binauthentication:replication:username:replicatorpassword:replpass123superuser:username:postgrespassword:postgres123parameters:unix_socket_directories:'/tmp'tags:nofailover:false# 允许参与 Failovernoloadbalance:false# 允许负载均衡(读)clonefrom:true# 允许其他节点从此节点克隆

关键说明

  • scope必须全局唯一,用于隔离多个 Patroni 集群;
  • use_pg_rewind: true要求data-checksumswal_log_hints = on
  • 所有 PG 节点的patroni.yml仅需修改namelistenconnect_address

4.4 创建数据目录并授权

sudomkdir-p /var/lib/pgsql/14/datasudochownpostgres:postgres /var/lib/pgsql/14/data

4.5 启动 Patroni

切换到 postgres 用户启动(避免权限问题):

sudo-u postgres patroni /etc/patroni/patroni.yml

首次启动时,Patroni 会:

  1. 在 etcd 中注册集群;
  2. 执行initdb初始化数据库;
  3. 设置复制用户和参数;
  4. 自动选举第一个启动的节点为主库(Leader)。

建议使用 systemd 管理 Patroni 进程(见附录)。


五、集群状态验证

5.1 使用 patronictl 查看集群

在任意 PG 节点执行:

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

输出示例:

+ Cluster: pg-ha-cluster (7073733813877921290) -------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+----------------+---------+---------+----+-----------+ | pg1 | 192.168.10.20 | Leader | running | 1 | 0 | | pg2 | 192.168.10.21 | Replica | running | 1 | 0 | | pg3 | 192.168.10.22 | Replica | running | 1 | 0 | +--------+----------------+---------+---------+----+-----------+

5.2 访问 REST API

curlhttp://192.168.10.20:8008/clustercurlhttp://192.168.10.20:8008/primary# 返回 200 表示是主库

5.3 验证流复制

在主库执行:

SELECT*FROMpg_stat_replication;

应看到两个备库连接。


六、自动故障转移演练

6.1 模拟主库宕机

在 pg1 上 kill Patroni 进程:

sudopkill-f"patroni /etc/patroni/patroni.yml"

6.2 观察自动切换

  • etcd 在 30 秒(ttl)内未收到 pg1 的心跳;
  • Patroni 在 pg2/pg3 上检测到 Leader 失联;
  • 触发选举,其中一个备库(如 pg2)自动 promote 为主库;
  • 原主库(pg1)重启后自动 rejoin 为备库。

查看日志(/var/log/patroni.log或终端输出)可看到:

2026-02-10 19:30:00,000 INFO: Lock owner: pg1; I am pg2 2026-02-10 19:30:05,000 INFO: does not have lock 2026-02-10 19:30:10,000 INFO: demoting self because leader is not available 2026-02-10 19:30:15,000 INFO: promoting to leader

6.3 验证新主库

patronictl -c /etc/patroni/patroni.yml list# pg2 应变为 Leader# 在 pg2 上写入数据psql -h192.168.10.21 -U admin -d postgres -c"CREATE TABLE test(id int);"

6.4 恢复原主库

重启 pg1 上的 Patroni:

sudo-u postgres patroni /etc/patroni/patroni.yml

Patroni 会自动:

  1. 检测到自己不是 Leader;
  2. 使用pg_rewind同步差异(因use_pg_rewind: true);
  3. 启动为备库。

若未启用 checksums,Patroni 会使用pg_basebackup重建,耗时较长。


七、应用连接与负载均衡(HAProxy)

为避免应用硬编码主库 IP,使用 HAProxy 提供统一入口。

7.1 安装 HAProxy

在 haproxy 节点:

sudoyuminstall-y haproxy

7.2 配置 HAProxy(/etc/haproxy/haproxy.cfg)

global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemon defaults mode tcp log global option tcplog timeout connect 10s timeout client 1h timeout server 1h # 写请求:只路由到主库 frontend pg_write bind *:5000 default_backend pg_primary # 读请求:可路由到主库或备库 frontend pg_read bind *:5001 default_backend pg_replicas backend pg_primary option httpchk GET /primary http-check expect status 200 server pg1 192.168.10.20:5432 maxconn 100 check port 8008 server pg2 192.168.10.21:5432 maxconn 100 check port 8008 server pg3 192.168.10.22:5432 maxconn 100 check port 8008 backend pg_replicas option httpchk GET /replica http-check expect status 200 server pg1 192.168.10.20:5432 maxconn 100 check port 8008 server pg2 192.168.10.21:5432 maxconn 100 check port 8008 server pg3 192.168.10.22:5432 maxconn 100 check port 8008

7.3 启动 HAProxy

sudosystemctlenable--now haproxy

应用连接:

  • 写:host=192.168.10.30 port=5000
  • 读:host=192.168.10.30 port=5001

八、高级特性与运维

8.1 手动切换(Switchover)

计划内维护时,安全切换主库:

patronictl -c /etc/patroni/patroni.yml switchover# 交互式选择新主库

或指定目标:

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

8.2 配置动态重载

修改patroni.yml后无需重启:

patronictl -c /etc/patroni/patroni.yml reload pg1

8.3 备份集成

Patroni 支持与 WAL-G、pgBackRest 集成,实现 PITR。

8.4 监控与告警

  • 使用patronictl list或 API 获取状态;
  • Prometheus exporter:patroni --config-file ... --prometheus-port 9369
  • 告警指标:复制延迟、主库宕机、etcd 不可用。

九、常见问题与实践建议

9.1 脑裂防护

  • etcd 的 TTL 机制确保同一时间只有一个 Leader;
  • 不要手动干预 PostgreSQL 角色(如直接执行pg_ctl promote)。

9.2 网络分区(Split-Brain)

  • etcd 需多数派存活(3 节点最多容忍 1 节点故障);
  • 避免将 etcd 与 PG 混部在同一物理机。

9.3 性能建议

  • etcd 使用 SSD 存储;
  • Patroni 节点时间同步(NTP);
  • 合理设置ttlloop_wait(通常 ttl > 2 * loop_wait)。

9.4 安全加固

  • etcd 启用 TLS;
  • Patroni API 启用认证;
  • PostgreSQL 使用 scram-sha-256 密码加密。

总结:基于 Patroni + etcd 的 PostgreSQL 高可用架构具备以下优势:

  • 自动化:故障检测、Failover、Rejoin 全自动;
  • 安全:通过 DCS 避免脑裂;
  • 灵活:支持同步/异步、多副本、级联;
  • 可观测:提供 REST API 和 CLI 工具;
  • 生态友好:与 Kubernetes(Spilo)、Prometheus、HAProxy 无缝集成。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询