1. PostgreSQL高可用方案选型与Patroni核心价值
在企业级数据库应用中,高可用性(High Availability)是核心需求之一。PostgreSQL作为功能强大的开源关系型数据库,提供了多种高可用解决方案。在众多方案中,Patroni凭借其设计理念和功能特性脱颖而出,成为当前最受欢迎的PostgreSQL高可用管理工具。
PostgreSQL原生支持流复制(Streaming Replication),这为构建高可用集群奠定了基础。但原生的流复制缺乏自动故障转移(failover)机制,需要依赖外部工具来实现完整的高可用方案。常见的PostgreSQL高可用工具包括:
- PAF(PostgreSQL Automatic Failover)
- repmgr
- Patroni
与其他方案相比,Patroni具有以下显著优势:
-
全面的复制支持:不仅支持基本的异步复制,还支持同步复制及智能降级机制。当同步备库出现故障时,能自动降级为异步复制,确保主库写入不阻塞,类似于MySQL的半同步复制但更加智能。
-
灵活的节点控制:可以精细控制每个节点的行为,包括是否参与选主、是否参与负载均衡、是否可以成为同步备机等。
-
自动修复能力:支持通过pg_rewind自动修复旧主库,避免重建整个实例的开销。
-
多种初始化方式:不仅支持传统的pg_basebackup,还支持与wal-e、pgBackRest、barman等备份工具集成。
-
完善的API支持:提供REST API接口,便于与其他系统集成。
-
脑裂防护机制:通过watchdog和同步复制等多种机制防止脑裂(split-brain)情况发生。
-
多后端支持:可与etcd、ZooKeeper、Consul、Kubernetes等多种分布式配置存储(DCS)集成。
2. Patroni架构与核心组件
2.1 Patroni系统架构
Patroni采用分布式架构设计,主要包含以下组件:
-
Patroni守护进程:运行在每个PostgreSQL节点上的主进程,负责节点状态管理、故障检测和恢复。
-
分布式配置存储(DCS):通常使用etcd、ZooKeeper或Consul等,用于存储集群状态和元数据,实现节点间的协调。
-
PostgreSQL实例:Patroni管理的数据库实例,可以是主库或备库。
-
Watchdog(可选):硬件或软件watchdog,用于在极端情况下防止脑裂。
2.2 关键配置文件解析
Patroni的核心配置文件通常为YAML格式,以下是一个典型配置的关键部分解析:
yaml复制scope: pgsql # 集群名称
namespace: /service/ # DCS中的命名空间路径
name: pg1 # 当前节点名称
restapi:
listen: 0.0.0.0:8008 # REST API监听地址
connect_address: 192.168.1.101:8008 # 其他节点访问本节点的地址
etcd:
host: 192.168.1.100:2379 # etcd服务地址
bootstrap:
dcs:
ttl: 30 # Leader锁的TTL(秒)
loop_wait: 10 # 状态检查间隔(秒)
retry_timeout: 10 # 操作重试超时(秒)
maximum_lag_on_failover: 1048576 # 允许备库落后的最大字节数
master_start_timeout: 300 # 主库启动超时(秒)
synchronous_mode: false # 是否启用同步模式
postgresql:
listen: 0.0.0.0:5432 # PostgreSQL监听地址
connect_address: 192.168.1.101:5432 # 其他节点访问本节点PG的地址
data_dir: /var/lib/postgresql/12/main # 数据目录
bin_dir: /usr/lib/postgresql/12/bin # PostgreSQL二进制文件目录
3. Patroni集群部署实战
3.1 环境准备
部署一个三节点的Patroni集群,建议配置如下:
- 操作系统:CentOS 7/8或Ubuntu 18.04/20.04
- PostgreSQL版本:12或更高
- Patroni版本:2.0+
- etcd版本:3.4+
节点规划:
- 节点1:192.168.1.101 (初始主库)
- 节点2:192.168.1.102 (备库)
- 节点3:192.168.1.103 (备库)
- etcd集群:192.168.1.100:2379 (可单独部署或与数据库节点共用)
3.2 基础环境配置
在所有节点上执行以下准备工作:
- 时钟同步:确保所有节点时间一致
bash复制yum install -y ntpdate
ntpdate pool.ntp.org && hwclock -w
- 关闭防火墙和SELinux(生产环境应根据需要调整):
bash复制setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config
systemctl disable --now firewalld
- 安装必要依赖:
bash复制yum install -y epel-release
yum install -y python3 python3-pip python3-devel gcc
3.3 etcd集群部署
etcd作为Patroni的分布式配置存储,需要先部署。在生产环境中建议部署3个或5个节点组成集群。以下是单节点etcd的安装配置:
- 安装etcd:
bash复制yum install -y etcd
- 配置etcd(/etc/etcd/etcd.conf):
ini复制ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.1.100:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_NAME="etcd0"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.100:2379"
- 启动etcd服务:
bash复制systemctl enable --now etcd
3.4 PostgreSQL与Patroni安装
在所有数据库节点上执行:
- 安装PostgreSQL 12:
bash复制yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install -y postgresql12-server postgresql12-contrib
- 安装Patroni:
bash复制pip3 install patroni[etcd]
- 创建数据目录并设置权限:
bash复制mkdir -p /var/lib/postgresql/12/main
chown postgres:postgres -R /var/lib/postgresql
chmod 700 /var/lib/postgresql/12/main
3.5 Patroni服务配置
- 创建systemd服务文件(/etc/systemd/system/patroni.service):
ini复制[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target
[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no
[Install]
WantedBy=multi-user.target
- 创建Patroni配置文件(/etc/patroni.yml),以节点1为例:
yaml复制scope: pgsql
namespace: /service/
name: pg1
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.1.101:8008
etcd:
hosts: 192.168.1.100:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
master_start_timeout: 300
synchronous_mode: false
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 100
shared_buffers: 1GB
wal_level: replica
wal_log_hints: 'on'
initdb:
- encoding: UTF8
- locale: C
- data-checksums
pg_hba:
- host replication repl 192.168.1.0/24 md5
- host all all 192.168.1.0/24 md5
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.101:5432
data_dir: /var/lib/postgresql/12/main
bin_dir: /usr/pgsql-12/bin
authentication:
replication:
username: repl
password: "repl123"
superuser:
username: postgres
password: "postgres123"
其他节点的配置类似,主要修改name、restapi.connect_address和postgresql.connect_address为各自的IP地址。
3.6 启动Patroni集群
- 在第一个节点上启动Patroni:
bash复制systemctl enable --now patroni
-
在其他节点上依次启动Patroni,它们会自动加入集群并作为备库运行。
-
检查集群状态:
bash复制patronictl -c /etc/patroni.yml list
输出示例:
code复制+ Cluster: pgsql (6868912301204081018) ----+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+--------+-------------+--------+---------+----+-----------+
| pg1 | 192.168.1.101 | Leader | running | 1 | |
| pg2 | 192.168.1.102 | | running | 1 | 0.0 |
| pg3 | 192.168.1.103 | | running | 1 | 0.0 |
+--------+-------------+--------+---------+----+-----------+
4. 高可用保障与脑裂防护
4.1 故障转移机制
Patroni通过定期更新DCS中的Leader key来维持主库身份。如果主库故障,Leader key会因TTL过期而释放,触发备库选举新主库。关键参数包括:
ttl: Leader key的存活时间(秒)loop_wait: 主库更新Leader key的间隔(秒)retry_timeout: 操作重试超时(秒)
4.2 脑裂防护策略
脑裂(split-brain)指集群中同时出现多个主库的情况,会导致数据不一致。Patroni提供多层防护:
-
Watchdog机制:
- 配置软件或硬件watchdog
- 当Patroni进程异常终止时,watchdog会触发系统重启
- 配置示例:
yaml复制watchdog: mode: automatic device: /dev/watchdog safety_margin: 5
-
同步复制模式:
- 启用后,主库必须有至少一个同步备库确认才能提交事务
- 配置示例:
yaml复制synchronous_mode: true synchronous_mode_strict: true # 禁止自动降级为异步
-
etcd不可用时的防护:
- 当Patroni无法连接etcd时,主库会自动降级为备库
- 可通过设置超大
retry_timeout减少etcd临时故障的影响
4.3 故障场景处理
不同故障场景下Patroni的行为:
| 故障位置 | 故障类型 | Patroni动作 |
|---|---|---|
| 备库 | PostgreSQL停止 | 尝试重启PostgreSQL |
| 备库 | Patroni停止 | 停止PostgreSQL |
| 主库 | PostgreSQL停止 | 尝试重启,超时后触发failover |
| 主库 | Patroni停止 | 停止PostgreSQL并触发failover |
| 主库 | 网络分区(无法连接etcd) | 将主库降级为备库 |
| 整个etcd集群 | etcd故障 | 所有节点变为备库,集群只读 |
5. 客户端访问方案
5.1 多主机URL连接
PostgreSQL驱动支持在连接字符串中指定多个主机:
JDBC示例:
java复制// 连接主库
jdbc:postgresql://192.168.1.101:5432,192.168.1.102:5432,192.168.1.103:5432/dbname?targetServerType=primary
// 连接备库(负载均衡)
jdbc:postgresql://192.168.1.101:5432,192.168.1.102:5432,192.168.1.103:5432/dbname?targetServerType=preferSecondary&loadBalanceHosts=true
libpq示例(psql):
bash复制psql "host=192.168.1.101,192.168.1.102,192.168.1.103 port=5432 dbname=dbname user=user password=pass target_session_attrs=read-write"
5.2 VIP漂移方案
通过Patroni回调脚本实现VIP自动漂移:
- 创建VIP管理脚本
/usr/local/bin/vip-manager:
bash复制#!/bin/bash
VIP=192.168.1.200
DEV=eth0
case $1 in
on_start|on_role_change)
if [ "$2" = "master" ]; then
ip addr add $VIP/24 dev $DEV
arping -c 3 -U -I $DEV $VIP
else
ip addr del $VIP/24 dev $DEV
fi
;;
esac
- 在Patroni配置中添加回调:
yaml复制postgresql:
callbacks:
on_start: /usr/local/bin/vip-manager
on_role_change: /usr/local/bin/vip-manager
5.3 HAProxy负载均衡
HAProxy可实现读写分离和负载均衡:
- 安装HAProxy:
bash复制yum install -y haproxy
- 配置示例(/etc/haproxy/haproxy.cfg):
ini复制frontend pg_write
bind *:5000
option httpchk GET /primary
default_backend pg_primary
backend pg_primary
option httpchk GET /primary
server pg1 192.168.1.101:5432 check port 8008
server pg2 192.168.1.102:5432 check port 8008
server pg3 192.168.1.103:5432 check port 8008
frontend pg_read
bind *:5001
option httpchk GET /replica
default_backend pg_replica
backend pg_replica
option httpchk GET /replica
server pg1 192.168.1.101:5432 check port 8008
server pg2 192.168.1.102:5432 check port 8008
server pg3 192.168.1.103:5432 check port 8008
6. 日常运维与管理
6.1 常用patronictl命令
-
查看集群状态:
bash复制
patronictl -c /etc/patroni.yml list -
手动切换主库:
bash复制
patronictl -c /etc/patroni.yml switchover -
修改集群配置:
bash复制
patronictl -c /etc/patroni.yml edit-config -
重启集群节点:
bash复制
patronictl -c /etc/patroni.yml restart pgsql
6.2 配置动态调整
-
启用同步复制:
bash复制patronictl -c /etc/patroni.yml edit-config -s 'synchronous_mode=true' -
修改PostgreSQL参数:
bash复制patronictl -c /etc/patroni.yml edit-config -p 'max_connections=200'
6.3 监控与日志
-
Patroni日志:默认输出到syslog,可通过journalctl查看:
bash复制
journalctl -u patroni -f -
通过REST API获取节点状态:
bash复制
curl http://192.168.1.101:8008 | jq -
Prometheus监控指标:
Patroni的/metrics端点提供Prometheus格式的监控数据。
7. 高级特性与最佳实践
7.1 级联复制配置
-
集群内级联复制:
yaml复制tags: replicatefrom: pg2 -
跨集群级联复制:
yaml复制bootstrap: dcs: standby_cluster: host: 192.168.1.200 # 上游集群VIP port: 5432 primary_slot_name: standby_slot
7.2 备份集成
Patroni可与多种备份工具集成:
-
配置pgBackRest备份:
yaml复制postgresql: create_replica_methods: - pgbackrest pgbackrest: command: /usr/bin/pgbackrest --stanza=main restore keep_data: true no_params: true -
定期备份脚本可通过Patroni回调实现。
7.3 版本升级策略
-
小版本升级:
- 逐个节点停机升级PostgreSQL包
- Patroni会自动处理恢复流程
-
大版本升级:
- 使用逻辑复制或工具如pg_dump/pg_restore
- 或搭建新集群后通过Patroni的standby_cluster配置从旧集群同步
8. 常见问题排查
8.1 节点无法加入集群
- 症状:节点启动后状态一直为"starting"或"failed"
- 排查步骤:
- 检查etcd连接是否正常
- 检查PostgreSQL日志是否有错误
- 验证复制用户权限
- 检查网络连通性
8.2 故障转移失败
- 症状:主库故障后没有自动切换
- 排查步骤:
- 检查etcd集群健康状态
- 验证备库与etcd的连接
- 检查
maximum_lag_on_failover设置是否过小 - 查看Patroni日志了解选举过程
8.3 同步复制降级问题
- 症状:同步复制模式下频繁降级为异步
- 解决方案:
- 检查网络稳定性
- 增加
synchronous_node_count配置 - 调整
wal_sender_timeout等PostgreSQL参数
9. 性能调优建议
-
复制相关参数:
yaml复制postgresql: parameters: wal_level: logical max_wal_senders: 10 max_replication_slots: 10 wal_keep_segments: 100 hot_standby: "on" -
监控与告警:
- 监控复制延迟(
patronictl list中的Lag) - 设置Prometheus告警规则
- 监控复制延迟(
-
资源分配:
- 为etcd分配专用资源,避免与数据库竞争
- 调整Patroni的
loop_wait和ttl平衡响应速度与负载
10. 生产环境注意事项
-
etcd集群部署:
- 生产环境至少部署3个etcd节点
- 考虑与数据库节点分离部署
- 定期备份etcd数据
-
网络配置:
- 确保节点间网络低延迟
- 考虑冗余网络链路
-
安全加固:
- 启用etcd TLS加密
- 限制Patroni API访问
- 使用强密码和适当权限
-
灾难恢复计划:
- 定期测试故障转移流程
- 准备手动恢复方案
- 维护详细的文档和操作手册
在实际生产部署中,Patroni已经证明能够提供可靠的PostgreSQL高可用解决方案。某金融系统采用Patroni+etcd方案后,将数据库可用性从99.9%提升到了99.99%,年故障时间从8小时降低到不足1小时。关键是要根据具体业务需求调整配置参数,并定期进行故障演练。
