PostgreSQL作为功能丰富的开源关系型数据库,其流复制(Streaming Replication)机制是实现数据库高可用架构的核心能力。数据库运维中,主从复制配合自动故障切换工具构建高可用集群,保障数据冗余与服务连续性。本文从流复制原理到Patroni自动切换,完整演示PostgreSQL高可用架构的搭建过程。
PostgreSQL流复制架构原理
PostgreSQL流复制基于WAL(Write-Ahead Log)机制实现。主节点(Primary)将事务日志以WAL记录形式写入,备节点(Standby)通过网络实时接收WAL流并回放,保持与主节点数据一致。流复制的关键进程:
# 流复制核心进程
# Primary端:
# walsender - 发送WAL日志给备节点,每个备节点一个
#
# Standby端:
# walreceiver - 接收主节点WAL日志
# startup - 回放WAL日志恢复数据
#
# 复制模式对比:
# 异步复制 - 主节点提交不等备节点确认,备节点可能有延迟
# 同步复制 - 主节点等待至少一个备节点确认WAL已写入才提交
#
# 备节点类型:
# Hot Standby - 接收WAL的同时可提供只读查询
# Warm Standby - 只接收WAL,不接受查询连接
同步复制虽然保障数据零丢失,但会牺牲主节点写入性能(需等待备节点确认)。生产环境通常采用同步+异步混合模式:一个同步备节点保障数据安全,一个异步备节点提供读取扩展。
主节点WAL日志配置
PostgreSQL主节点需要配置WAL相关参数以支持流复制连接:
# postgresql.conf (主节点配置)
# WAL级别: replica支持物理复制,logical支持逻辑复制
wal_level = replica
# WAL发送进程数(等于备节点数量+1)
max_wal_senders = 10
# WAL保留段数,防止备节点断连后需要的WAL被覆盖
wal_keep_size = 1024MB
# WAL写入方式: on(本地fsync), remote_write(备节点写入)
synchronous_commit = on
# 同步复制: 等待备节点确认
synchronous_standby_names = 'FIRST 1 (standby1)'
# 监听所有网卡
listen_addresses = '*'
port = 5432
# 连接数与内存
max_connections = 200
shared_buffers = 4GB
work_mem = 64MB
wal_buffers = 64MB
# 归档配置(用于PITR时间点恢复)
archive_mode = on
archive_command = 'test ! -f /data/pg_archive/%f && cp %p /data/pg_archive/%f'
# pg_hba.conf (允许备节点连接)
# TYPE DATABASE USER ADDRESS METHOD
host replication replica 192.168.10.0/24 md5
配置完成后需要创建专用复制用户并重启服务:
-- 创建复制用户
CREATE ROLE replica WITH REPLICATION LOGIN PASSWORD 'Replica@2026';
-- 查看复制状态
SELECT application_name, client_addr, state, sync_state,
sent_lsn, write_lsn, flush_lsn, replay_lsn
FROM pg_stat_replication;
-- 查看WAL发送统计
SELECT * FROM pg_stat_wal_receiver;
备节点流复制搭建步骤
使用pg_basebackup工具从主节点克隆基础备份,然后配置为流复制备节点:
# 停止备节点上的PostgreSQL服务
systemctl stop postgresql
# 清空备节点数据目录
rm -rf /var/lib/postgresql/16/main/*
# 从主节点克隆基础备份
pg_basebackup \
-h 192.168.10.21 \
-U replica \
-D /var/lib/postgresql/16/main \
-Fp -Xs -P -R
# -R 参数自动创建standby.signal文件和primary_conninfo配置
# 生成的postgresql.auto.conf内容:
# primary_conninfo = 'user=replica password=xxx host=192.168.10.21 port=5432'
# primary_slot_name = 'standby1'
# 在主节点创建复制槽(防止WAL被过早回收)
SELECT pg_create_physical_replication_slot('standby1');
# 备节点postgresql.conf额外配置
hot_standby = on
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 1s
hot_standby_feedback = on
# 启动备节点
systemctl start postgresql
# 验证备节点状态
psql -c "SELECT pg_is_in_recovery();" -- 返回true表示备节点
psql -c "SELECT * FROM pg_stat_wal_receiver();" -- 查看接收状态
复制槽(Replication Slot)的作用是确保主节点不会在备节点断连期间回收所需的WAL段文件。不使用复制槽时,如果备节点长时间断连,主节点可能回收WAL导致备节点无法继续复制。启用hot_standby_feedback参数可防止主节点执行VACUUM时清理备节点正在使用的行,避免备节点查询冲突。
Patroni自动故障切换部署
Patroni是PostgreSQL高可用管理工具,自动监控主节点状态并在故障时触发切换。配合etcd作为配置存储中心实现集群协调:
# 安装etcd集群(3节点)
apt install etcd -y
# etcd配置 /etc/etcd/etcd.conf (node1)
ETCD_NAME=node1
ETCD_DATA_DIR=/var/lib/etcd
ETCD_LISTEN_PEER_URLS=http://192.168.10.21:2380
ETCD_LISTEN_CLIENT_URLS=http://192.168.10.21:2379
ETCD_INITIAL_CLUSTER=node1=http://192.168.10.21:2380,node2=http://192.168.10.22:2380,node3=http://192.168.10.23:2380
ETCD_INITIAL_CLUSTER_TOKEN=pg-cluster
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://192.168.10.21:2380
# 安装Patroni
pip3 install patroni[etcd]
# Patroni配置 /etc/patroni/patroni.yml (node1)
scope: pg-cluster
name: node1
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.10.21:8008
etcd:
hosts: 192.168.10.21:2379,192.168.10.22:2379,192.168.10.23:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
synchronous_mode: true
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
max_wal_senders: 10
wal_keep_size: 1024MB
initdb:
- encoding: UTF8
- data-checksums
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.10.21:5432
data_dir: /var/lib/postgresql/16/main
bin_dir: /usr/lib/postgresql/16/bin
authentication:
replication:
username: replica
password: Replica@2026
superuser:
username: postgres
password: PgAdmin@2026
parameters:
hot_standby: on
max_connections: 200
tags:
nofailover: false
noloadbalance: false
clonefrom: false
# 启动Patroni服务
systemctl start patroni
# 查看集群状态
patronictl -c /etc/patroni/patroni.yml list
# + Cluster: pg-cluster --+---------+----+-----------+
# | Member | Host | Role | State | Lag in MB |
# +--------+-------------+---------+----------+----------+
# | node1 | 192.168.10.21| Leader | running | |
# | node2 | 192.168.10.22| Replica | streaming| 0 |
# | node3 | 192.168.10.23| Replica | streaming| 0 |
# +--------+-------------+---------+----------+----------+
当主节点故障时,Patroni在10秒(loop_wait)内检测到,通过etcd进行Leader选举,将延迟最小的备节点提升为新的主节点。切换过程中synchronous_mode参数保证新主节点的数据与原主节点一致,避免数据丢失。故障节点恢复后,Patroni自动通过pg_rewind同步增量日志重新加入集群。
PgBouncer连接池配置与读写分离
高可用集群需要配合连接池实现读写分离,PgBouncer是PostgreSQL最常用的连接池中间件:
# 安装PgBouncer
apt install pgbouncer -y
# PgBouncer配置 /etc/pgbouncer/pgbouncer.ini
[databases]
; 写请求路由到主节点
primary = host=192.168.10.21 port=5432 dbname=appdb
; 读请求路由到备节点
replica = host=192.168.10.22 port=5432 dbname=appdb
; 通过Patroni REST API自动路由到当前主节点
; 需配合pgbouncer的USE_PATRONI功能
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 500
default_pool_size = 20
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 60
query_timeout = 30
query_wait_timeout = 30
# 应用层读写分离配置(Java示例)
# 写操作: jdbc:postgresql://pgbouncer:6432/primary
# 读操作: jdbc:postgresql://pgbouncer:6432/replica
pool_mode设置为transaction级别时,PgBouncer在事务级别复用后端连接,平衡了连接利用率和事务隔离性。配合Patroni的REST API(/read-write端点),PgBouncer可以动态感知主节点切换并自动重连新主节点,实现故障切换对应用透明。数据库高可用架构的搭建需要综合考虑数据复制延迟、故障检测灵敏度与切换后的数据一致性,Patroni+etcd+PgBouncer组合是目前PostgreSQL生产环境的主流高可用方案。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-liu-fu-zhi-gao-ke-yong-jia-gou-da-jian-pei-zhi/