PostgreSQL 17 高可用集群:从流复制到自动故障转移的完整部署实践
数据库宕机一分钟,损失可能是几十万。高可用不是可选项,而是生产环境的基本门槛。本文手把手带你搭建一套基于 PostgreSQL 17 流复制 + pg_auto_failover 的高可用集群,实现 RPO < 1 秒、RTO < 30 秒的自动故障切换能力。
一、流复制原理:为什么它是高可用的基石
1.1 传统备份 vs 流复制
很多团队早期使用 pg_dump 做定时备份,看起来"有备份",但一旦真的出故障,往往会发现:
- 上一次备份是昨晚 2 点,故障发生在今天下午 —— 数据丢了半天
- 从备份恢复要解压、导入、验证 —— 恢复耗时数小时
- 备份文件本身损坏 —— 恢复彻底失败
流复制(Streaming Replication)从根本上解决了这些问题:
| 指标 | 传统备份 | 流复制 |
|---|---|---|
| RPO(最大数据丢失量) | 小时级 | < 1 秒 |
| RTO(故障恢复时间) | 小时级 | 30 秒内 |
| 备库可用性 | 不可用 | 可读(热备) |
| 故障切换方式 | 人工操作 | 自动切换 |
1.2 流复制的工作原理
Primary 节点
↓ 写入数据,生成 WAL(Write-Ahead Log)日志
↓ WAL Sender 进程将 WAL 实时推送给备库
Standby 节点
↓ WAL Receiver 进程接收 WAL
↓ Recovery 进程持续回放 WAL,保持与主库同步
↓ 可提供只读查询服务(hot_standby = on)
WAL 是 PostgreSQL 的事务日志,先写日志,再写数据。流复制的本质是把这份日志实时传送给备库并回放,让备库的数据状态与主库保持高度一致。
二、架构设计:两节点 + pg_auto_failover
2.1 整体架构
┌─────────────────────────────────────────────┐
│ pg_auto_failover Monitor │
│ 192.168.1.102:5000 │
└──────────────┬──────────────────────────────┘
│ 心跳检测 / 故障判定
┌────────────────────┼────────────────────────┐
│ │ │
┌─────────▼──────────┐ │ ┌──────────▼─────────┐
│ Primary 节点 │◄────────┴────────────►│ Standby 节点 │
│ 192.168.1.100:5432 │ WAL 流复制(实时) │ 192.168.1.101:5432│
│ 读写服务 │ │ 只读查询 │
└────────────────────┘ └────────────────────┘
↑ 故障时自动切换
应用层连接串(始终指向当前 Primary)
角色说明:
- Primary:主库,处理所有读写请求,持续向备库推送 WAL
- Standby:备库,实时同步主库数据,可承接只读查询,Primary 故障时自动晋升
- Monitor:pg_auto_failover 监控节点,负责健康检测、故障判定和切换协调
2.2 硬件与网络要求
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 服务器数量 | 2 台 | 3 台(含 Monitor,跨可用区) |
| CPU | 2 核 | 4 核+ |
| 内存 | 4 GB | 8 GB+ |
| 磁盘 | SSD | NVMe SSD |
| 主备网络延迟 | < 10 ms | < 1 ms(同机房) |
| 操作系统 | Ubuntu 20.04+ | Ubuntu 22.04 LTS |
网络延迟是关键:同步复制模式下,主库每次提交都需要等待备库确认,网络延迟直接影响写入性能。推荐主备节点部署在同一机房/同一可用区。
三、详细部署步骤
3.1 环境准备(所有节点)
配置各节点 /etc/hosts(或 DNS),确保节点间通过主机名可互访:
# 在所有节点追加
echo "192.168.1.100 pg-primary" | sudo tee -a /etc/hosts
echo "192.168.1.101 pg-standby" | sudo tee -a /etc/hosts
echo "192.168.1.102 pg-monitor" | sudo tee -a /etc/hosts
3.2 配置主库(Primary)
第一步:创建复制专用用户
sudo -u postgres psql
-- 创建复制用户,权限最小化
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'Repl@Strong2026';
-- 验证用户创建
\du replicator
第二步:修改 postgresql.conf
sudo -u postgres vi /etc/postgresql/17/main/postgresql.conf
关键参数:
# ==================== 复制相关 ====================
wal_level = replica # 开启复制所需的 WAL 级别
max_wal_senders = 5 # 允许的最大 WAL 发送进程数(备库数 + 2)
hot_standby = on # 允许备库提供只读服务
# ==================== WAL 归档 ====================
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/17/archive/%f'
# ==================== 超时设置 ====================
wal_sender_timeout = 60s # WAL 发送超时
wal_receiver_timeout = 60s # WAL 接收超时
# ==================== 监听地址 ====================
listen_addresses = '*' # 监听所有网卡(生产环境建议指定 IP)
port = 5432
第三步:修改 pg_hba.conf(访问控制)
sudo -u postgres vi /etc/postgresql/17/main/pg_hba.conf
追加以下内容:
# 允许备库连接复制
host replication replicator 192.168.1.101/32 scram-sha-256
# 允许 pg_auto_failover Monitor 连接
host all postgres 192.168.1.102/32 scram-sha-256
# 允许应用服务器连接(按实际 IP 修改)
host all all 192.168.1.0/24 scram-sha-256
第四步:创建归档目录并重启
# 创建 WAL 归档目录
sudo -u postgres mkdir -p /var/lib/postgresql/17/archive
sudo -u postgres chmod 700 /var/lib/postgresql/17/archive
# 重启主库使配置生效
sudo systemctl restart postgresql
# 验证主库正常运行
sudo -u postgres psql -c "SELECT version();"
sudo -u postgres psql -c "SHOW wal_level;"
3.3 配置备库(Standby)
第一步:停止备库的 PostgreSQL 并清空数据目录
sudo systemctl stop postgresql
# 备份原有配置文件
sudo cp /etc/postgresql/17/main/postgresql.conf /tmp/postgresql.conf.bak
sudo cp /etc/postgresql/17/main/pg_hba.conf /tmp/pg_hba.conf.bak
# 清空数据目录(重要!pg_basebackup 需要目标目录为空)
sudo -u postgres rm -rf /var/lib/postgresql/17/main/*
第二步:从主库拉取基础备份
sudo -u postgres pg_basebackup \
-h 192.168.1.100 \
-D /var/lib/postgresql/17/main \
-U replicator \
-P -W -R \
--wal-method=stream \
--checkpoint=fast
# 参数说明:
# -h 主库 IP
# -D 目标数据目录
# -U 复制用户
# -P 显示进度
# -W 提示输入密码
# -R 自动生成 standby.signal 和 postgresql.auto.conf(复制连接信息)
# --wal-method=stream 同时流式传输 WAL,确保备份一致性
第三步:配置备库 postgresql.conf
sudo -u postgres vi /etc/postgresql/17/main/postgresql.conf
listen_addresses = '*'
port = 5432
hot_standby = on # 允许备库提供只读查询
hot_standby_feedback = on # 向主库反馈备库查询状态,防止主库清理备库还在读的数据行
wal_receiver_timeout = 60s
第四步:验证 standby.signal 文件存在
# pg_basebackup -R 会自动创建此文件,表明这是一个备库
ls -la /var/lib/postgresql/17/main/standby.signal
# 查看自动生成的连接配置
cat /var/lib/postgresql/17/main/postgresql.auto.conf
# 应包含:primary_conninfo = 'host=192.168.1.100 user=replicator ...'
第五步:启动备库
sudo systemctl start postgresql
# 查看启动日志
sudo journalctl -u postgresql -n 50 --no-pager
# 正常应包含:
# LOG: entering standby mode
# LOG: started streaming WAL from primary
3.4 验证流复制状态
在主库执行:
-- 查看复制连接状态
SELECT
client_addr,
usename,
application_name,
state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
write_lag,
flush_lag,
replay_lag,
sync_state
FROM pg_stat_replication;
期望输出示例:
client_addr | usename | state | sync_state | replay_lag
----------------+------------+-----------+------------+------------
192.168.1.101 | replicator | streaming | async | 00:00:00
测试数据同步:
-- 在主库创建测试表并插入数据
CREATE TABLE replication_test (id SERIAL PRIMARY KEY, ts TIMESTAMPTZ DEFAULT NOW());
INSERT INTO replication_test DEFAULT VALUES;
-- 在备库验证(需先执行 SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY; 或在只读模式下连接)
-- 连接到备库
sudo -u postgres psql -h 192.168.1.101 -c "SELECT * FROM replication_test;"
-- 应立即看到主库刚插入的数据
3.5 配置 pg_auto_failover(自动故障转移)
pg_auto_failover 引入了一个独立的 Monitor 节点,负责:
- 持续对主备库进行心跳检测
- 在检测到主库不可达时,协调备库执行 Failover
- 防止脑裂(Split-Brain):只有 Monitor 认可的节点才能成为 Primary
Step 1:在 Monitor 节点初始化监控服务
# 在 192.168.1.102 上执行
sudo -u postgres pg_autoctl create monitor \
--pgdata /var/lib/postgresql/17/monitor \
--pgport 5000 \
--hostname 192.168.1.102
# 启动 Monitor
sudo -u postgres pg_autoctl run --pgdata /var/lib/postgresql/17/monitor &
# 查看监控节点状态
sudo -u postgres pg_autoctl show state --pgdata /var/lib/postgresql/17/monitor
Step 2:将主库注册到 Monitor
# 在 192.168.1.100(Primary)上执行
sudo -u postgres pg_autoctl create postgres \
--pgdata /var/lib/postgresql/17/main \
--pgport 5432 \
--hostname 192.168.1.100 \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover \
--name pg-primary
# 启动 pg_autoctl 代理
sudo -u postgres pg_autoctl run --pgdata /var/lib/postgresql/17/main &
Step 3:将备库注册到 Monitor
# 在 192.168.1.101(Standby)上执行
sudo -u postgres pg_autoctl create postgres \
--pgdata /var/lib/postgresql/17/main \
--pgport 5432 \
--hostname 192.168.1.101 \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover \
--name pg-standby
# 启动 pg_autoctl 代理
sudo -u postgres pg_autoctl run --pgdata /var/lib/postgresql/17/main &
Step 4:验证集群状态
# 在任意节点执行
sudo -u postgres pg_autoctl show state \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover
期望输出:
Name | Node | Host:Port | LSN | Reachable | Health | Current State | Assigned State
--------------+-------+------------------------+------------------+-----------+--------+---------------+----------------
pg-primary | 1 | 192.168.1.100:5432 | 0/5000000 | yes | OK | primary | primary
pg-standby | 2 | 192.168.1.101:5432 | 0/5000000 | yes | OK | secondary | secondary
两个节点均为 OK 状态,集群配置完成。
四、自动故障转移测试
重要:故障转移测试建议在非生产时间窗口进行,并提前通知相关团队。
4.1 计划内切换(手动 Switchover)
计划内维护时(如主库升级、硬件维护),使用手动切换:
# 在任意节点执行手动切换(原备库晋升为 Primary)
sudo -u postgres pg_autoctl perform switchover \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover
# 查看切换后的状态
sudo -u postgres pg_autoctl show state \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover
手动切换整个过程通常在 10 秒以内完成,业务中断时间极短。
4.2 模拟主库故障(自动 Failover 测试)
# 在 Primary 节点(192.168.1.100)上强制停止数据库
sudo systemctl stop postgresql
# 在 Monitor 节点或 Standby 节点上持续观察状态变化
watch -n 2 "sudo -u postgres pg_autoctl show state \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover"
观察到的状态变化过程:
时间 +0s : pg-primary → primary (正常)
时间 +5s : pg-primary → unhealthy (Monitor 检测到不可达)
时间 +15s : pg-primary → demoted (降级确认)
时间 +20s : pg-standby → wait_primary (等待晋升)
时间 +25s : pg-standby → primary (晋升完成 ✅)
整个自动切换过程约 20-30 秒,期间应用层若使用了连接池(如 PgBouncer)或连接重试机制,可以无感知地完成切换。
4.3 恢复原主库,重新加入集群
# 修复原主库后,重新启动 PostgreSQL
sudo systemctl start postgresql
# 重新注册到集群(原主库会自动变为 Secondary)
sudo -u postgres pg_autoctl run --pgdata /var/lib/postgresql/17/main &
# 验证原主库已以 Secondary 身份加入集群
sudo -u postgres pg_autoctl show state \
--monitor postgresql://autoctl_node@192.168.1.102:5000/pg_auto_failover
五、监控与告警:生产环境的必要保障
5.1 关键监控指标
| 指标 | 查询方法 | 告警阈值 | 说明 |
|---|---|---|---|
| 复制延迟(字节差) | pg_stat_replication.write_lag |
> 100 MB | 网络或备库性能问题 |
| 复制延迟(时间差) | pg_last_xact_replay_timestamp() |
> 5 秒 | 备库回放异常 |
| WAL 发送状态 | pg_stat_replication.state |
非 streaming | 复制中断 |
| 连接数 | pg_stat_activity |
> max_connections × 80% | 连接池告警 |
| 磁盘使用率 | df -h |
> 80% | WAL 积压风险 |
| pg_autoctl 进程 | pgrep pg_autoctl |
进程不存在 | 自动切换能力失效 |
5.2 复制延迟监控脚本
将以下脚本保存为 /usr/local/bin/check_pg_replication.sh:
chmod +x /usr/local/bin/check_pg_replication.sh
# 测试运行
/usr/local/bin/check_pg_replication.sh 192.168.1.101 5 30
5.3 集成 Prometheus + Grafana
# 安装 postgres_exporter
wget https://github.com/prometheus-community/postgres_exporter/releases/latest/download/postgres_exporter_linux_amd64.tar.gz
tar -xzf postgres_exporter_linux_amd64.tar.gz
sudo mv postgres_exporter /usr/local/bin/
# 配置连接信息
export DATA_SOURCE_NAME="postgresql://monitor_user:password@localhost:5432/postgres?sslmode=disable"
# 启动 exporter(默认端口 9187)
postgres_exporter &
Prometheus 配置追加:
scrape_configs:
- job_name: 'postgresql'
static_configs:
- targets: ['192.168.1.100:9187', '192.168.1.101:9187']
labels:
cluster: 'pg-ha'
推荐 Grafana Dashboard ID:9628(PostgreSQL Database)和 12485(pg_auto_failover)。
六、性能优化与最佳实践
6.1 内核参数调优
cat >> /etc/sysctl.conf << 'EOF'
# 共享内存(设置为物理内存的 50%)
kernel.shmmax = 274877906944
kernel.shmall = 67108864
# 网络优化
net.core.somaxconn = 1024
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6
# 减少 swap 使用
vm.swappiness = 10
vm.overcommit_memory = 2
vm.overcommit_ratio = 90
EOF
sysctl -p
6.2 PostgreSQL 参数调优
6.3 安全加固
启用 SSL 复制:
# 生成自签名证书(生产环境建议使用 CA 签发)
sudo -u postgres openssl req -new -x509 -days 3650 -nodes \
-out /etc/postgresql/17/main/server.crt \
-keyout /etc/postgresql/17/main/server.key \
-subj "/CN=pg-primary"
sudo chmod 600 /etc/postgresql/17/main/server.key
sudo chown postgres:postgres /etc/postgresql/17/main/server.{crt,key}
# postgresql.conf
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
强制使用 SCRAM-SHA-256 认证(PG 17 默认值):
# postgresql.conf
password_encryption = scram-sha-256
# pg_hba.conf 中将 md5 全部替换为 scram-sha-256
host replication replicator 192.168.1.101/32 scram-sha-256
host all all 192.168.1.0/24 scram-sha-256
最小化复制用户权限:
-- 复制用户只需 REPLICATION 权限,不需要数据库访问权限
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'xxx';
-- 不要给 replicator 用户 superuser 或 login 数据库的权限
七、常见问题排查
Q1:复制延迟持续增高
现象: pg_stat_replication.replay_lag 不断增大,备库追不上主库
排查步骤:
# 1. 检查网络带宽
iperf3 -c 192.168.1.101 -t 30
# 2. 检查备库磁盘 I/O
iostat -x 1 10
# 3. 查看 WAL 产生速率(主库)
sudo -u postgres psql -c "SELECT pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) as lag FROM pg_stat_replication;"
# 4. 检查备库 recovery 进程 CPU 使用率
top -u postgres
解决方案:
- 升级主备间网络带宽
- 开启
wal_compression = on减少传输量 - 检查备库是否有大量只读查询拖慢 WAL 回放,考虑配置只读副本分流
Q2:故障转移未自动触发
现象: 主库宕机后,备库未自动晋升
排查步骤:
# 1. 检查 Monitor 节点状态
sudo -u postgres pg_autoctl show state --pgdata /var/lib/postgresql/17/monitor
# 2. 查看 Monitor 日志
sudo journalctl -u pg_autoctl -n 100 --no-pager | grep -E "ERROR|WARN|failover"
# 3. 检查 Monitor 与各节点的网络连通性
nc -zv 192.168.1.100 5432
nc -zv 192.168.1.101 5432
# 4. 验证 pg_autoctl 进程是否在所有节点上运行
ps aux | grep pg_autoctl
常见原因及解决:
- Monitor 节点本身宕机 → Monitor 是单点,生产环境建议使用高可用监控部署
- pg_autoctl 进程未运行 → 检查 systemd 配置,设置
Restart=always - 节点间网络分区 → 检查防火墙规则,确保 Monitor 可达所有节点
Q3:备库无法启动 / 复制连接被拒绝
现象: 备库日志报 FATAL: could not connect to the primary server
排查步骤:
# 1. 确认 pg_hba.conf 中允许了备库 IP
sudo -u postgres psql -c "SHOW hba_file;"
grep replication /etc/postgresql/17/main/pg_hba.conf
# 2. 在备库上手动测试连接
sudo -u postgres psql "host=192.168.1.100 user=replicator dbname=replication sslmode=require"
# 3. 检查 postgresql.auto.conf 中的连接信息
cat /var/lib/postgresql/17/main/postgresql.auto.conf
# 4. 检查 standby.signal 文件是否存在
ls /var/lib/postgresql/17/main/standby.signal
如果以上排查无果,重新拉取基础备份:
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/17/main/*
sudo -u postgres pg_basebackup \
-h 192.168.1.100 -D /var/lib/postgresql/17/main \
-U replicator -P -W -R --wal-method=stream
sudo systemctl start postgresql
八、定期演练清单
高可用方案的价值,在于真正故障时能发挥作用。建议每季度执行以下演练:
✅ 手动 Switchover 测试(验证计划内切换正常)
✅ 模拟主库故障(验证自动 Failover 触发时间 ≤ 30 秒)
✅ 恢复原主库并重新加入集群(验证集群恢复能力)
✅ 从备份恢复测试(验证备份有效性和 RTO)
✅ 检查监控告警是否正常触发(避免告警静默失效)
✅ 确认应用层连接重试机制有效(模拟切换后应用自动重连)
总结
本文完整介绍了 PostgreSQL 17 流复制 + pg_auto_failover 高可用集群的部署实践:
| 能力 | 实现方式 | 效果 |
|---|---|---|
| 数据保护 | 流复制(WAL 实时同步) | RPO < 1 秒 |
| 自动切换 | pg_auto_failover Monitor | RTO < 30 秒 |
| 只读扩展 | hot_standby 备库承接读请求 | 读写分离 |
| 监控告警 | Prometheus + Grafana + 自定义脚本 | 问题提前预警 |
| 安全加固 | SSL + SCRAM-SHA-256 + 最小权限 | 符合生产规范 |
这套架构可以满足 99.9% 的可用性要求(每年宕机 < 8.7 小时)。如需进一步提升,可以扩展为 3 节点跨可用区 部署,将可用性提升至 99.99%。
高可用不是一次性的配置工作,而是持续的运维能力——正确的配置 + 完善的监控 + 定期的演练,才能在真正的故障面前,让系统的自愈能力如预期发挥作用。
参考资料
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)