Skip to content

PostgreSQL Patroni自动故障转移

核心概念

Patroni是一个用于PostgreSQL集群管理的开源工具,提供自动故障转移、配置管理和高可用性保障。它通过分布式一致性存储(DCS)来协调多个PostgreSQL节点,实现自动选主和故障转移。

1. 核心组件

组件描述
Patroni主进程,负责监控PostgreSQL节点状态,协调故障转移
DCS分布式一致性存储(如etcd、Consul、ZooKeeper),存储集群状态和配置
PostgreSQL数据库实例,分为主节点和备节点
Watchdog硬件或软件看门狗,用于在极端情况下强制重启节点

2. 关键概念

  • Leader Election:当主节点故障时,Patroni通过DCS进行领导者选举,选择新的主节点
  • 故障检测:Patroni定期检查主节点状态,通过心跳机制检测故障
  • 自动故障转移:当检测到主节点故障时,自动将备节点提升为主节点
  • 配置管理:通过DCS集中管理PostgreSQL配置,确保所有节点配置一致
  • 切换协调:确保在故障转移过程中只有一个主节点,避免脑裂

3. 工作原理

  1. 所有Patroni节点定期向DCS发送心跳
  2. 主节点持有DCS中的锁,表明其领导者身份
  3. 当主节点故障,心跳停止,DCS中的锁释放
  4. 备节点竞争DCS中的锁,获得锁的节点成为新主节点
  5. 新主节点执行pg_ctl promote提升为可用状态
  6. 其他备节点重新配置,连接到新主节点进行流复制

环境准备

1. 系统要求

组件版本要求
PostgreSQL9.3+
Python3.6+
DCSetcd 3.2+, Consul 0.7+, ZooKeeper 3.4.5+
操作系统Linux (推荐CentOS 7+, Ubuntu 16.04+)

2. 网络要求

  • 所有节点之间网络互通
  • DCS节点与所有Patroni节点网络互通
  • 建议使用1Gbps以上网络带宽

3. 节点规划

节点角色IP地址主机名职责
DCS1192.168.1.101dcs1etcd节点1
DCS2192.168.1.102dcs2etcd节点2
DCS3192.168.1.103dcs3etcd节点3
Postgres1192.168.1.201pg1PostgreSQL主节点/Patroni节点1
Postgres2192.168.1.202pg2PostgreSQL备节点/Patroni节点2
Postgres3192.168.1.203pg3PostgreSQL备节点/Patroni节点3

安装与配置

1. 安装DCS(etcd示例)

1.1 安装etcd

bash
# 在所有DCS节点上安装etcd
sudo yum install -y etcd

1.2 配置etcd

bash
# 编辑etcd配置文件 /etc/etcd/etcd.conf
ETCD_NAME="etcd1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.1.101:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.101:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.101:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.101:2379"
ETCD_INITIAL_CLUSTER="etcd1=http://192.168.1.101:2380,etcd2=http://192.168.1.102:2380,etcd3=http://192.168.1.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-1"
ETCD_INITIAL_CLUSTER_STATE="new"

1.3 启动etcd

bash
# 启动并启用etcd服务
sudo systemctl start etcd
sudo systemctl enable etcd

# 验证etcd集群状态
etcdctl --endpoints=http://192.168.1.101:2379,http://192.168.1.102:2379,http://192.168.1.103:2379 cluster-health

2. 安装Patroni

bash
# 在所有PostgreSQL节点上安装Patroni
pip3 install patroni[etcd]
pip3 install python-etcd

# 安装PostgreSQL(如果尚未安装)
sudo yum install -y postgresql15 postgresql15-server

3. 配置Patroni

3.1 创建Patroni配置文件

bash
# 在所有PostgreSQL节点上创建配置文件 /etc/patroni.yml
scope: pg_cluster
namespace: /postgresql/
name: pg1

restapi:
  listen: 192.168.1.201:8008
  connect_address: 192.168.1.201:8008

etcd:
  hosts: 192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        max_connections: 100
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: "512MB"
        wal_log_hints: "on"

  initdb:
  - encoding: UTF8
  - data-checksums

  pg_hba:
  - host replication replicator 127.0.0.1/32 md5
  - host replication replicator 192.168.1.0/24 md5
  - host all all 0.0.0.0/0 md5

postgresql:
  listen: 192.168.1.201:5432
  connect_address: 192.168.1.201:5432
  data_dir: /var/lib/pgsql/15/data
  bin_dir: /usr/pgsql-15/bin
  pgpass: /tmp/pgpass0
  authentication:
    replication:
      username: replicator
      password: replicapass
    superuser:
      username: postgres
      password: postgrespass
  parameters:
    unix_socket_directories: /var/run/postgresql

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

3.2 配置差异

  • 在pg2节点上,将name改为pg2listenconnect_address改为pg2的IP
  • 在pg3节点上,将name改为pg3listenconnect_address改为pg3的IP

集群部署

1. 启动第一个Patroni节点

bash
# 在pg1节点上启动Patroni
patroni /etc/patroni.yml

# 或使用systemd服务
cat > /etc/systemd/system/patroni.service << EOF
[Unit]
Description=Patroni PostgreSQL Cluster Manager
After=syslog.target network.target

[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl start patroni
systemctl enable patroni

2. 验证第一个节点状态

bash
# 查看Patroni API状态
curl http://192.168.1.201:8008/patroni

# 查看集群状态
curl http://192.168.1.201:8008/cluster

3. 启动其他Patroni节点

bash
# 在pg2和pg3节点上启动Patroni
systemctl start patroni
systemctl enable patroni

# 验证集群状态
curl http://192.168.1.201:8008/cluster

自动故障转移配置

1. 故障转移参数

在Patroni配置文件的bootstrap.dcs部分,以下参数控制故障转移行为:

参数描述默认值
ttlDCS中领导者锁的生存时间30秒
loop_wait心跳发送间隔10秒
retry_timeout重试操作的超时时间10秒
maximum_lag_on_failover故障转移时允许的最大WAL延迟1MB
failover_check_timeout故障检查超时时间30秒
synchronous_mode是否启用同步模式false

2. 自定义故障转移配置

yaml
# 在bootstrap.dcs中添加或修改以下参数
bootstrap:
  dcs:
    ttl: 60
    loop_wait: 20
    retry_timeout: 20
    maximum_lag_on_failover: 10485760  # 10MB
    synchronous_mode: true
    synchronous_mode_strict: false
    failover_check_timeout: 60

3. 手动触发故障转移

bash
# 使用Patroni API手动触发故障转移
curl -X POST http://192.168.1.201:8008/failover -d "{\"leader\": \"pg1\", \"candidate\": \"pg2\"}"

# 或使用patronictl命令
patronictl -c /etc/patroni.yml failover

监控与管理

1. 使用patronictl管理工具

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

# 查看节点详细信息
patronictl -c /etc/patroni.yml show pg1

# 重新初始化节点
patronictl -c /etc/patroni.yml reinit pg_cluster pg3

# 暂停/恢复节点
patronictl -c /etc/patroni.yml pause pg_cluster pg2
patronictl -c /etc/patroni.yml resume pg_cluster pg2

2. Patroni API

API端点方法描述
/patroniGET获取节点状态
/clusterGET获取集群状态
/failoverPOST触发故障转移
/switchoverPOST触发手动切换
/restartPOST重启节点
/reloadPOST重载配置

3. 监控指标

Patroni暴露Prometheus格式的监控指标,可通过/metrics端点访问:

bash
# 查看监控指标
curl http://192.168.1.201:8008/metrics

4. 日志监控

bash
# 查看Patroni日志
journalctl -u patroni -f

# 配置日志级别(在patroni.yml中)
log:
  level: INFO
  dir: /var/log/patroni
  file_num: 10
  file_size: 10485760  # 10MB

最佳实践

1. 生产环境配置建议

  • DCS部署:至少部署3个DCS节点,确保高可用性
  • 网络配置:使用专用网络连接DCS和Patroni节点
  • 硬件配置:所有PostgreSQL节点使用相同或相似的硬件配置
  • 存储配置:使用SSD存储提高IO性能
  • 监控配置:配置全面的监控和告警,包括:
    • Patroni API状态
    • PostgreSQL复制延迟
    • DCS集群健康状态
    • 节点资源使用率

2. 安全配置

  • 使用SSL加密:为Patroni API和DCS连接启用SSL
  • 限制网络访问:通过防火墙限制只有必要的IP可以访问Patroni和PostgreSQL端口
  • 使用强密码:为PostgreSQL和DCS设置强密码
  • 定期备份:即使有高可用集群,也要定期进行数据库备份

3. 性能优化

  • 调整PostgreSQL参数:根据实际负载调整PostgreSQL配置
  • 合理设置故障转移参数:根据网络延迟和负载调整ttl、loop_wait等参数
  • 使用pg_rewind:启用use_pg_rewind减少故障恢复时间
  • 启用复制槽:使用use_slots确保WAL日志不丢失

4. 灾难恢复

  • 定期测试故障转移:模拟主节点故障,测试自动故障转移功能
  • 文档化故障处理流程:编写详细的故障处理文档
  • 准备回滚计划:在进行重大变更前,准备回滚计划

常见问题(FAQ)

Q1:如何检查Patroni集群状态?

A1:可以通过以下方法检查:

bash
# 使用patronictl命令
patronictl -c /etc/patroni.yml list

# 使用API
curl http://192.168.1.201:8008/cluster

Q2:如何手动触发故障转移?

A2:可以使用以下方法:

bash
# 使用API
curl -X POST http://192.168.1.201:8008/failover -d "{}"

# 使用patronictl命令
patronictl -c /etc/patroni.yml failover

Q3:如何添加新节点到现有集群?

A3:添加新节点的步骤:

  1. 安装PostgreSQL和Patroni
  2. 创建与现有节点相同的patroni.yml配置文件,修改节点名称和IP
  3. 启动Patroni服务
  4. 验证新节点是否加入集群

Q4:如何从Patroni集群中移除节点?

A4:移除节点的步骤:

  1. 停止该节点的Patroni服务
  2. 使用patronictl命令移除节点:
    bash
    patronictl -c /etc/patroni.yml remove pg_cluster pg3

Q5:Patroni集群出现脑裂怎么办?

A5:处理脑裂的步骤:

  1. 立即停止所有PostgreSQL节点
  2. 检查DCS状态,确保只有一个领导者
  3. 手动选择一个正确的主节点
  4. 使用pg_rewind同步其他节点
  5. 重新启动Patroni服务

Q6:如何升级Patroni集群?

A6:升级步骤:

  1. 升级DCS集群(如果需要)
  2. 逐个升级Patroni节点:
    bash
    patronictl -c /etc/patroni.yml pause pg_cluster pg1
    pip3 install --upgrade patroni[etcd]
    patronictl -c /etc/patroni.yml resume pg_cluster pg1
  3. 升级PostgreSQL版本(如果需要)

Q7:如何配置Patroni使用Consul?

A7:修改patroni.yml配置文件:

yaml
# 将etcd配置替换为consul配置
consul:
  host: 192.168.1.101:8500
  scheme: http
  verify: true
  token: "your-consul-token"

Q8:如何监控Patroni集群?

A8:监控方案:

  1. 使用Prometheus + Grafana监控Patroni指标
  2. 配置日志收集(如ELK Stack)
  3. 使用Nagios/Zabbix监控服务状态
  4. 监控PostgreSQL复制延迟

Q9:Patroni故障转移失败怎么办?

A9:故障转移失败的处理:

  1. 查看Patroni日志,分析失败原因
  2. 检查DCS状态,确保DCS集群正常
  3. 检查PostgreSQL节点状态
  4. 手动干预,使用pg_rewind同步节点
  5. 重新启动故障转移

Q10:如何调整Patroni日志级别?

A10:在patroni.yml中修改log.level参数:

yaml
log:
  level: DEBUG  # 或INFO, WARNING, ERROR
  dir: /var/log/patroni

故障排除

1. 节点无法加入集群

症状:新节点启动后无法加入集群

解决方法

  • 检查网络连接,确保节点间网络互通
  • 检查DCS连接配置,确保etcd/consul地址正确
  • 检查节点名称是否唯一
  • 查看Patroni日志,分析错误原因

2. 故障转移不触发

症状:主节点故障后,没有自动触发故障转移

解决方法

  • 检查DCS状态,确保DCS集群正常
  • 调整ttl和loop_wait参数,减小故障检测延迟
  • 检查maximum_lag_on_failover参数,确保没有设置过大
  • 查看Patroni日志,分析故障原因

3. PostgreSQL无法启动

症状:Patroni无法启动PostgreSQL

解决方法

  • 检查PostgreSQL数据目录权限
  • 查看PostgreSQL日志,分析启动失败原因
  • 检查Patroni配置中的PostgreSQL参数是否正确
  • 尝试手动启动PostgreSQL,验证是否可以正常启动

4. 复制延迟过高

症状:备节点复制延迟过高

解决方法

  • 检查网络带宽,确保网络连接稳定
  • 调整PostgreSQL的wal_sender_timeout等参数
  • 检查备节点负载,确保备节点资源充足
  • 启用pg_stat_statements,分析慢查询

5. DCS连接失败

症状:Patroni无法连接到DCS

解决方法

  • 检查DCS节点状态,确保DCS集群正常
  • 检查DCS连接配置,确保地址和端口正确
  • 检查防火墙设置,确保DCS端口开放
  • 查看DCS日志,分析连接失败原因