外观
PostgreSQL Patroni自动故障转移
核心概念
Patroni是一个用于PostgreSQL集群管理的开源工具,提供自动故障转移、配置管理和高可用性保障。它通过分布式一致性存储(DCS)来协调多个PostgreSQL节点,实现自动选主和故障转移。
1. 核心组件
| 组件 | 描述 |
|---|---|
| Patroni | 主进程,负责监控PostgreSQL节点状态,协调故障转移 |
| DCS | 分布式一致性存储(如etcd、Consul、ZooKeeper),存储集群状态和配置 |
| PostgreSQL | 数据库实例,分为主节点和备节点 |
| Watchdog | 硬件或软件看门狗,用于在极端情况下强制重启节点 |
2. 关键概念
- Leader Election:当主节点故障时,Patroni通过DCS进行领导者选举,选择新的主节点
- 故障检测:Patroni定期检查主节点状态,通过心跳机制检测故障
- 自动故障转移:当检测到主节点故障时,自动将备节点提升为主节点
- 配置管理:通过DCS集中管理PostgreSQL配置,确保所有节点配置一致
- 切换协调:确保在故障转移过程中只有一个主节点,避免脑裂
3. 工作原理
- 所有Patroni节点定期向DCS发送心跳
- 主节点持有DCS中的锁,表明其领导者身份
- 当主节点故障,心跳停止,DCS中的锁释放
- 备节点竞争DCS中的锁,获得锁的节点成为新主节点
- 新主节点执行
pg_ctl promote提升为可用状态 - 其他备节点重新配置,连接到新主节点进行流复制
环境准备
1. 系统要求
| 组件 | 版本要求 |
|---|---|
| PostgreSQL | 9.3+ |
| Python | 3.6+ |
| DCS | etcd 3.2+, Consul 0.7+, ZooKeeper 3.4.5+ |
| 操作系统 | Linux (推荐CentOS 7+, Ubuntu 16.04+) |
2. 网络要求
- 所有节点之间网络互通
- DCS节点与所有Patroni节点网络互通
- 建议使用1Gbps以上网络带宽
3. 节点规划
| 节点角色 | IP地址 | 主机名 | 职责 |
|---|---|---|---|
| DCS1 | 192.168.1.101 | dcs1 | etcd节点1 |
| DCS2 | 192.168.1.102 | dcs2 | etcd节点2 |
| DCS3 | 192.168.1.103 | dcs3 | etcd节点3 |
| Postgres1 | 192.168.1.201 | pg1 | PostgreSQL主节点/Patroni节点1 |
| Postgres2 | 192.168.1.202 | pg2 | PostgreSQL备节点/Patroni节点2 |
| Postgres3 | 192.168.1.203 | pg3 | PostgreSQL备节点/Patroni节点3 |
安装与配置
1. 安装DCS(etcd示例)
1.1 安装etcd
bash
# 在所有DCS节点上安装etcd
sudo yum install -y etcd1.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-health2. 安装Patroni
bash
# 在所有PostgreSQL节点上安装Patroni
pip3 install patroni[etcd]
pip3 install python-etcd
# 安装PostgreSQL(如果尚未安装)
sudo yum install -y postgresql15 postgresql15-server3. 配置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: false3.2 配置差异
- 在pg2节点上,将
name改为pg2,listen和connect_address改为pg2的IP - 在pg3节点上,将
name改为pg3,listen和connect_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 patroni2. 验证第一个节点状态
bash
# 查看Patroni API状态
curl http://192.168.1.201:8008/patroni
# 查看集群状态
curl http://192.168.1.201:8008/cluster3. 启动其他Patroni节点
bash
# 在pg2和pg3节点上启动Patroni
systemctl start patroni
systemctl enable patroni
# 验证集群状态
curl http://192.168.1.201:8008/cluster自动故障转移配置
1. 故障转移参数
在Patroni配置文件的bootstrap.dcs部分,以下参数控制故障转移行为:
| 参数 | 描述 | 默认值 |
|---|---|---|
| ttl | DCS中领导者锁的生存时间 | 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: 603. 手动触发故障转移
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 pg22. Patroni API
| API端点 | 方法 | 描述 |
|---|---|---|
| /patroni | GET | 获取节点状态 |
| /cluster | GET | 获取集群状态 |
| /failover | POST | 触发故障转移 |
| /switchover | POST | 触发手动切换 |
| /restart | POST | 重启节点 |
| /reload | POST | 重载配置 |
3. 监控指标
Patroni暴露Prometheus格式的监控指标,可通过/metrics端点访问:
bash
# 查看监控指标
curl http://192.168.1.201:8008/metrics4. 日志监控
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/clusterQ2:如何手动触发故障转移?
A2:可以使用以下方法:
bash
# 使用API
curl -X POST http://192.168.1.201:8008/failover -d "{}"
# 使用patronictl命令
patronictl -c /etc/patroni.yml failoverQ3:如何添加新节点到现有集群?
A3:添加新节点的步骤:
- 安装PostgreSQL和Patroni
- 创建与现有节点相同的patroni.yml配置文件,修改节点名称和IP
- 启动Patroni服务
- 验证新节点是否加入集群
Q4:如何从Patroni集群中移除节点?
A4:移除节点的步骤:
- 停止该节点的Patroni服务
- 使用patronictl命令移除节点:bash
patronictl -c /etc/patroni.yml remove pg_cluster pg3
Q5:Patroni集群出现脑裂怎么办?
A5:处理脑裂的步骤:
- 立即停止所有PostgreSQL节点
- 检查DCS状态,确保只有一个领导者
- 手动选择一个正确的主节点
- 使用pg_rewind同步其他节点
- 重新启动Patroni服务
Q6:如何升级Patroni集群?
A6:升级步骤:
- 升级DCS集群(如果需要)
- 逐个升级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 - 升级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:监控方案:
- 使用Prometheus + Grafana监控Patroni指标
- 配置日志收集(如ELK Stack)
- 使用Nagios/Zabbix监控服务状态
- 监控PostgreSQL复制延迟
Q9:Patroni故障转移失败怎么办?
A9:故障转移失败的处理:
- 查看Patroni日志,分析失败原因
- 检查DCS状态,确保DCS集群正常
- 检查PostgreSQL节点状态
- 手动干预,使用pg_rewind同步节点
- 重新启动故障转移
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日志,分析连接失败原因
