PostgreSQL流复制(Streaming Replication)是构建数据库高可用架构的核心机制。主节点(Primary)通过WAL日志流实时同步到备节点(Standby),备节点持续接收并回放WAL日志保持数据一致。配合Patroni或repmgr等集群管理工具,可以实现自动故障切换,满足生产环境对数据库RPO=0和RTO在秒级的要求。本文覆盖流复制配置、故障切换和读写分离实战。
PostgreSQL流复制架构与WAL日志机制
PostgreSQL通过预写式日志(WAL)记录所有数据变更。流复制模式下,Primary持续发送WAL日志给Standby,Standby接收后写入WAL文件并回放。同步级别通过synchronous_commit参数控制:local(仅本地确认)、on(等备节点接收确认)、remote_write(等备节点写入确认)、remote_apply(等备节点回放完成)。
主节点Primary配置
# postgresql.conf(主节点)
listen_addresses = '*'
port = 5432
wal_level = replica # 流复制需要replica级别
max_wal_senders = 10 # 最大WAL发送进程数
wal_keep_size = 1024 # 保留WAL大小(MB),防止备节点断连后追赶不上
hot_standby = on
synchronous_standby_names = '*' # 同步复制,所有备节点参与确认
# 归档配置
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
# 连接配置
max_connections = 200
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 64MB
# pg_hba.conf(主节点)- 允许备节点复制连接
# TYPE DATABASE USER ADDRESS METHOD
host replication repl 192.168.1.0/24 md5
host all all 192.168.1.0/24 md5
# 创建复制专用用户
psql -U postgres -c "CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'repl_password';"
备节点Standby配置与基础备份
使用pg_basebackup创建基础备份
# 在备节点上执行,从主节点拉取基础备份
pg_basebackup \
-h 192.168.1.10 \
-U repl \
-D /var/lib/postgresql/data \
-Fp \
-Xs \
-P \
-R \
-S standby_slot
# -Fp: plain格式,直接拷贝文件
# -Xs: 使用stream方式同步WAL
# -P: 显示进度
# -R: 自动创建standby.signal和primary_conninfo配置
# -S: 使用复制槽(推荐,防止主节点过早回收WAL)
# postgresql.conf(备节点)- 在基础备份上追加配置
hot_standby = on
hot_standby_feedback = on # 向主节点发送反馈,防止查询冲突
max_wal_senders = 10
# postgresql.auto.conf(pg_basebackup -R自动生成)
primary_conninfo = 'host=192.168.1.10 port=5432 user=repl password=repl_password'
primary_slot_name = 'standby_slot'
使用复制槽防止WAL过早回收
# 在主节点创建物理复制槽
psql -U postgres -c "SELECT pg_create_physical_replication_slot('standby_slot');"
# 查看复制槽状态
psql -U postgres -c "SELECT slot_name, active, restart_lsn FROM pg_replication_slots;"
# 查看复制状态
psql -U postgres -c "SELECT application_name, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;"
同步级别选择与性能权衡
# 异步复制(最高性能,可能丢失少量数据)
synchronous_commit = local
synchronous_standby_names = ''
# 同步复制(数据零丢失,写入延迟增加)
synchronous_commit = on
synchronous_standby_names = 'standby1'
# remote_write(平衡方案,备节点写入WAL即确认)
synchronous_commit = remote_write
synchronous_standby_names = 'standby1'
# remote_apply(备节点回放完成才确认,读一致性最好但延迟最大)
synchronous_commit = remote_apply
synchronous_standby_names = 'standby1'
Patroni自动故障切换集群部署
Patroni是PostgreSQL高可用集群管理工具,基于分布式一致性(etcd/ZooKeeper/Consul)实现Leader选举和自动切换。
# patroni.yml(每个节点一份)
scope: pg-cluster
name: node1
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.1.10:8008
etcd:
hosts: 192.168.1.20:2379,192.168.1.21:2379,192.168.1.22:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 20
maximum_lag_on_failover: 1048576 # 1MB,超过此延迟不切换
synchronous: true
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
max_wal_senders: 10
wal_keep_size: 1024
initdb:
- encoding: UTF8
- locale: en_US.UTF-8
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.10:5432
data_dir: /var/lib/postgresql/data
bin_dir: /usr/lib/postgresql/16/bin
authentication:
replication:
username: repl
password: repl_password
superuser:
username: postgres
password: pg_password
parameters:
hot_standby: on
hot_standby_feedback: on
create_replica_methods:
- basebackup
basebackup:
checkpoint: fast
tags:
nofailover: false
noloadbalance: false
clonefrom: false
replicatefrom: false
# 启动Patroni(三个节点分别启动)
patroni /etc/patroni/patroni.yml
# 查看集群状态
patronictl -c /etc/patroni/patroni.yml list
# 输出示例:
# + Cluster: pg-cluster (70000000) -+---------+----+-----------+
# | Member | Host | Role | State | TL | Lag in MB |
# +-------+---------------+---------+---------+----+-----------+
# | node1 | 192.168.1.10 | Leader | running | 16 | |
# | node2 | 192.168.1.11 | Replica | streaming | 16 | 0 |
# | node3 | 192.168.1.12 | Replica | streaming | 16 | 0 |
# +-------+---------------+---------+---------+----+-----------+
读写分离配置与连接池方案
Pgpool-II或HAProxy配合应用层路由实现读写分离,写请求到Primary,读请求到Standby:
# Pgpool-II配置 - pgpool.conf
listen_addresses = '*'
port = 9999
# 后端节点配置
backend_hostname0 = '192.168.1.10'
backend_port0 = 5432
backend_weight0 = 0 # 读不路由到主节点
backend_data_directory0 = '/var/lib/postgresql/data'
backend_hostname1 = '192.168.1.11'
backend_port1 = 5432
backend_weight1 = 1 # 读路由到备节点
backend_data_directory1 = '/var/lib/postgresql/data'
backend_hostname2 = '192.168.1.12'
backend_port2 = 5432
backend_weight2 = 1
# 读写分离模式
load_balance_mode = on
master_slave_mode = on
master_slave_sub_mode = 'stream'
# 故障检测
health_check_period = 10
health_check_timeout = 5
health_check_user = 'postgres'
故障切换测试与验证
# 手动切换(维护场景)
patronictl -c /etc/patroni/patroni.yml switchover
# 模拟主节点故障
docker stop patroni-node1
# Patroni自动选举新Leader,观察状态变化
patronictl -c /etc/patroni/patroni.yml list
# 验证复制状态
psql -h 192.168.1.11 -U postgres -c "SELECT pg_is_in_recovery();"
# 返回f表示该节点已是Primary
流复制延迟监控通过pg_stat_replication视图查看sent_lsn与replay_lsn的差距。配置告警规则:当lag超过maximum_lag_on_failover阈值时触发告警,运维人员介入排查网络或备节点性能问题。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-gao-ke-yong-jia-gou-yu-liu-fu-zhi/