基于 pg_auto_failover
参考:
- GitHub - hapostgres/pg_auto_fa...
- Site Unreachable
- PostgreSQL高可用-pg_auto_failover的简单使用介绍
pg_auto_failover 的需求和能力列表
1. 需求(安装和运行所需条件)
基础要求
条件 | 详细信息 |
---|---|
PostgreSQL 版本 | 支持 PostgreSQL 13-17 |
操作系统 | Linux(推荐)或 macOS(可测试) |
依赖软件 | pg_autoctl (pg_auto_failover CLI 工具),PostgreSQL 服务器 |
存储和网络 | 主库与备库网络稳定,支持同步或异步复制 |
监控节点 | 至少 3 台服务器 才能完全避免脑裂 |
架构要求
条件 | 详细信息 |
---|---|
最少服务器数量 | 2 台(但可能会有脑裂风险) |
推荐服务器数量 | 3 台(主库、备库、监控) |
数据复制方式 | 默认异步(提高性能),支持同步(提高一致性) |
PostgreSQL 流复制 | 由 pg_auto_failover 自动管理 |
2. 能力(提供的功能)
高可用性(HA)
功能 | 详细信息 |
---|---|
自动主备切换 | 主节点故障时,自动提升备节点 |
自动重新加入集群 | 原主节点恢复后自动降级为备节点 |
数据复制 | 默认异步(高性能),支持同步复制(一致性更高) |
防止脑裂 | 需要监控节点(2 台服务器时可能有脑裂风险) |
集群管理
功能 | 详细信息 |
---|---|
自动 PostgreSQL 配置 | 无需手动配置流复制 |
集群状态管理 | 监控节点会管理 主/备/备用节点 |
拓扑结构 | 仅支持 主 - 备架构(1 主 1 备) |
自动故障检测 | 检测主库状态,自动触发故障转移 |
管理与监控
功能 | 详细信息 |
---|---|
管理工具 | pg_autoctl CLI 提供简单的命令行管理 |
集群健康检查 | 定期检查节点状态 |
支持日志与指标监控 | 可与 Prometheus/Grafana 结合 |
额外特性
功能 | 详细信息 |
---|---|
支持 Load Balancer | 允许配置读流量均衡 |
多数据中心部署 | 支持跨数据中心 HA(需要额外配置) |
3. 适用场景
适用 | 详细信息 |
---|---|
✅ 适用于 | 高可用 PostgreSQL、自动主备切换、低运维成本 |
❌ 不适用于 | 仅 2 台服务器(可能有脑裂风险),多主架构 |
4. 典型架构
组件 | 作用 |
---|---|
主库(Primary) | 处理所有写请求,并同步数据到备库 |
备库(Secondary) | 复制主库数据,在主库故障时提升为新主库 |
监控节点(Monitor) | 负责监控集群状态,决定故障转移 |
5. 结论
- 如果有 3 台服务器(主、备、监控)→ pg_auto_failover 是合适的,自动化程度高,管理简单
- 如果只有 2 台服务器 → 可能会有脑裂风险,建议改用 Patroni + watchdog
安装部署
定义基本信息
本次安装的环境:
环境 | 值 |
---|---|
操作系统 | Ubuntu 22.04.5 LTS |
数据库 | PostgreSQL 14.15 (Ubuntu 14.15-0ubuntu0.22.04.1) |
pg-auto-failover-cli | 1.6.3-1 |
仲裁机 | 192.192.192.9 |
主机 | 192.192.192.204 |
备机 | 192.192.192.205 |
VIP | 192.192.192.260 |
在每个主机执行:
# 可能需要修改的
monitor_ip="192.192.192.9" # 仲裁
primary_ip="192.192.192.204" # 主
secondary_ip="192.192.192.205" # 备# 几个路径,可以在后边安装好数据库后再确认
pgdata="/var/lib/postgresql/14/main/"
pgbin="/usr/lib/postgresql/14/bin"
pgconfig="/etc/postgresql/14/main/"# 密码含有@则考虑后续命令中手动填充
autoctl_node_pwd="autoctl_ceni_2025"
replication_pwd="replication_ceni_2025"
export autoctl_node_pwd=$autoctl_node_pwd
export replication_pwd=$replication_pwd# 无需修改
cat >> /etc/profile << EOF
export monitor_ip=$monitor_ip
export primary_ip=$primary_ip
export secondary_ip=$secondary_ip
export pgdata=$pgdata
export pgbin=$pgbin
export pgconfig=$pgconfig
export PGDATA=$pgdata
export PGHOME=$pgdata
export PATH=\$PATH:$pgbin
EOFsource /etc/profileecho "$monitor_ip monitor" >> /etc/hosts
echo "$primary_ip primary" >> /etc/hosts
echo "$secondary_ip secondary" >> /etc/hosts
![[Pasted image 20250207132357.png]]
安装数据库
分别在主备和仲裁机上安装:
apt update
apt install -y postgresql-common
# 调整配置文件以阻止初始化cluster
echo 'create_main_cluster = false' | sudo tee -a /etc/postgresql-common/createcluster.confapt install -y --no-install-recommends postgresql-14
apt install -y pg-auto-failover-cli
执行 pg_autoctl
测试:
![[Pasted image 20250206150642.png]]
仲裁节点 执行
创建监控节点:
hostnamectl set-hostname monitorsu - postgres -c "pg_autoctl create monitor --auth scram-sha-256 \--pgdata $pgdata \--pgport 5432 \--hostname monitor \--ssl-self-signed"
创建服务启动服务 (root 用户):
pg_autoctl -q show systemd --pgdata $pgdata > /usr/lib/systemd/system/pgautofailover.servicesystemctl daemon-reload
systemctl enable pgautofailover.service
systemctl start pgautofailover.service
systemctl status pgautofailover.service
创建密码:
su - postgres -c "psql -d pg_auto_failover -c \"alter user autoctl_node password '$autoctl_node_pwd';\""
主节点 执行
hostnamectl set-hostname primarysu - postgres -c "pg_autoctl create postgres --auth scram-sha-256 \--hostname primary \--ssl-self-signed \--monitor 'postgres://autoctl_node:$autoctl_node_pwd@monitor:5432/pg_auto_failover?sslmode=require'"su - postgres -c "pg_autoctl config set replication.password $replication_pwd"
创建服务 (root 用户):
pg_autoctl -q show systemd --pgdata $pgdata > /usr/lib/systemd/system/pgautofailover.servicesystemctl daemon-reload
systemctl enable pgautofailover.service
systemctl start pgautofailover.service
systemctl status pgautofailover.service
创建流复制用户:
su - postgres -c "psql -d postgres -c \"ALTER USER pgautofailover_replicator PASSWORD '$replication_pwd';\""
备节点 执行
# 备节点要执行
hostnamectl set-hostname secondarysu - postgres -c "export PGPASSWORD=$replication_pwd; export PGSSLMODE=require; pg_autoctl create postgres --auth scram-sha-256 \--hostname secondary \--ssl-self-signed \--monitor 'postgres://autoctl_node:$autoctl_node_pwd@monitor:5432/pg_auto_failover?sslmode=require'"su - postgres -c "pg_autoctl config set replication.password $replication_pwd"
创建服务启动服务 (root 用户):
pg_autoctl -q show systemd --pgdata $pgdata > /usr/lib/systemd/system/pgautofailover.servicesystemctl daemon-reload
systemctl enable pgautofailover.service
systemctl start pgautofailover.service
systemctl status pgautofailover.service
查看状态
su - postgres -c "pg_autoctl show state"
![[Pasted image 20250206180129.png]]
在一主多从情况下手动提升某个从节点为主库(在要提升的从节点 node_2 上执行):
适用场景:
- 你需要强制进行主从切换,比如主节点已经失效,但故障转移没有自动发生。
- 你希望人为干预集群的主从角色变化。
su - postgres -c "pg_autoctl perform promotion -name node_2"
如果需要手动触发主备切换:
- 该命令用于 手动触发主备切换(switchover)。
- 作用是 让当前 primary(主节点)降级为 secondary,同时 让当前最合适的 secondary(备节点)提升为 primary。
su - postgres -c "pg_autoctl perform switchover"
![[Pasted image 20250207161040.png]]
如果有异常需要关闭 pg_autoctl :
# 1. 首先停止节点服务
su - postgres -c "pg_autoctl stop"# 2. 删除节点
su - postgres -c "pg_autoctl drop node --pgdata $PGDATA"# 3. 清理数据目录和配置文件
su - postgres -c "rm -rf $PGDATA/* && rm -rf /var/lib/postgresql/.local/pg_autoctl/*"
测试
当前状态 node1 为主,node2 为备
当主机关机,会检测到 timeout:
![[Pasted image 20250207155841.png]]
然后备机会变为 read-write 模式
![[Pasted image 20250207155914.png]]
主机重启后,备机 node2 自动升级为 primary,原主机 node1 降级为 secondary.
![[Pasted image 20250207160051.png]]
在当前的主服务器 node2 上创建表:
su - postgres -c "psql -c \"CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT);INSERT INTO test_table (name) VALUES ('test');\""
在备服务器 node1 查看:
su - postgres -c "psql -c \"SELECT * FROM test_table;\""
![[Pasted image 20250207160446.png]]
如果需要在仲裁机上删除某节点:
su - postgres -c "pg_autoctl drop node --pgdata $pgdata --name node_2 --force"
创建用户
su - postgres -c "psql -c \"CREATE USER dbuser WITH PASSWORD 'gg@Ceni@2025#gg';\""# 允许用户远程连接
echo "host all dbuser 192.192.192.0/24 md5" >> $pgconfig/pg_hba.conf
查看用户,应该能够在主备机上同步:
su - postgres -c "psql -c '\du'"
删除用户:
su - postgres -c "psql -c 'DROP USER dbuser;'"
注意
状态机 Monitor 挂了对集群使用完全没有影响。但是此时如果集群里面的机器在挂一台,是没有办法自动进行故障转移的,因为我们失去了状态机。
配置 Keepalived
在主机和备机安装 Keepalived
apt install keepalived
主节点配置文件:
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {router_id LVS_DEVEL
}vrrp_script chk_pgdb {script "/etc/keepalived/check.sh"interval 5weight 2
}vrrp_instance VI_1 {state MASTERinterface ens192 # 网卡编号virtual_router_id 99 # 同一集群内keepalived id 应该相同priority 100 # 优先级advert_int 1authentication {auth_type PASSauth_pass ceni@pg@2025}virtual_ipaddress {192.192.192.240}
}
EOF
备节点配置文件:
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {router_id LVS_DEVEL
}vrrp_script chk_pgdb {script "/etc/keepalived/check.sh"interval 5weight 2
}vrrp_instance VI_1 {state BACKUPinterface ens192 # 网卡编号virtual_router_id 99 # 同一集群内keepalived id 应该相同priority 99 # 优先级advert_int 1nopreemtauthentication {auth_type PASSauth_pass ceni@pg@2025}virtual_ipaddress {192.192.192.240}
}
EOF
创建存活检查脚本和通知脚本
cat > /etc/keepalived/check.sh << EOF
#!/bin/sh
# 本脚本用于 Keepalived 检查 PostgreSQL 状态,通过 su - postgres -c "psql -qtAX -c \"select pg_is_in_recovery();\""
# 执行查找 pg_is_in_recovery() 的结果。如果结果为 "f",表示当前节点为主节点;否则为备节点。
#
# 请确保:
# 1. psql 已安装,且当前系统中 postgres 用户正常配置了访问 PostgreSQL 的权限。
# 2. 日志输出使用 logger (可选) 以便调试。# 执行 SQL 查询,获取 pg_is_in_recovery() 返回值
ROLE=$(su - postgres -c "psql -qtAX -c \"select pg_is_in_recovery();\"" 2>/dev/null)# 记录日志
logger "Keepalived check: pg_is_in_recovery() returned '${ROLE}'"# 判断结果,如果返回 f 则为主节点
if [ "$ROLE" = "f" ]; thenexit 0
elseexit 1
fi
EOF
cat > /etc/keepalived/notify.sh << EOF
#!/bin/bash
# notify.shecho $1 $2 is in $3 state > /etc/keepalived/keepalive.$1.$2.state
EOF
cat > /etc/keepalived/getstate.sh << EOF
#!/bin/bash
# getstate.shcat /etc/keepalived/keepalive.*.*.state
EOF
启动服务
systemctl enable --now keepalived
systemctl status keepalived.service