本文主要记录 PostgreSQL 流复制(Streaming Replication)主从热备的配置步骤:主库参数与复制用户/复制槽、备库 pg_basebackup 与 standby.signal、复制状态验证,以及手动 promote。文末补充 sslmode、WAL 保留参数与常见报错处理。
本方案不包含自动故障切换。主库故障时需人工 pg_ctl promote / pg_promote(),并改应用连接。若需要自动切换,应另外部署 Patroni、repmgr 等方案。大版本以 16 为例,路径与 unit 名按发行版调整;密码与 IP 使用占位符。
背景说明
| 角色 | 职责 |
|---|---|
| Primary(主库) | 读写;产生 WAL 并发送给备库 |
| Standby(备库) | 接收并应用 WAL;hot_standby=on 时可只读查询 |
| 复制槽 | 主库保留备库尚未消费的 WAL,比单纯 wal_keep_size 更可靠 |
| 手动切换 | 确认旧主不可用后提升备库,避免脑裂 |
环境信息
| 项目 | 取值(示例 / 占位) |
|---|---|
| PostgreSQL | 16.x(主备主版本一致) |
| 主库 | <primary-host>,端口 5432 |
| 备库 | <standby-host> |
| 数据目录 | <pgdata>(如 /var/lib/postgresql/16/main) |
| 复制用户 | replication_user |
| 复制槽 | <slot_name>(如 standby1_slot) |
| 服务名 | postgresql-16 或发行版等价 unit |
前置:主备网络互通;防火墙放行 5432;备库数据目录可被 pg_basebackup 写入(空目录或不存在)。
配置主库
postgresql.conf
wal_level = replica
max_wal_senders = 5
# 使用复制槽时可不依赖 wal_keep_size;见下文 WAL 参数说明
# wal_keep_size = 512MB
hot_standby_feedback = on
wal_level 等参数通常需重启生效。
pg_hba.conf
允许备库以 replication 身份连接(地址与认证方式按现场收紧):
# TYPE DATABASE USER ADDRESS METHOD
host replication replication_user <standby-ip>/32 scram-sha-256
创建复制用户与复制槽
CREATE USER replication_user WITH REPLICATION PASSWORD '<password>';
SELECT pg_create_physical_replication_slot('<slot_name>');
使配置生效
# systemd 示例
systemctl restart postgresql-16
# 或
pg_ctl restart -D <pgdata>
仅改 pg_hba 时有时可 reload;涉及 wal_level 仍应重启。
准备与配置备库
停止服务并清空数据目录
备库不得带着另一套 initdb 出来的集群去“接”主库。数据目录须为空或不存在,再由 pg_basebackup 填充。
systemctl stop postgresql-16
# 确认后清理目标目录内容(破坏性,先备份自有配置)
# rm -rf <pgdata>/*
pg_basebackup
在备库上执行(版本与主库主版本一致):
pg_basebackup \
-h <primary-host> -p 5432 \
-U replication_user \
-D <pgdata> \
-Fp -Xs -P \
-S <slot_name> \
--wal-method=stream
按提示输入复制用户密码。PG12+ 不再依赖 recovery.conf;-R 行为因版本而异,本文采用手动写 standby.signal + primary_conninfo。
standby.signal 与 postgresql.conf
touch <pgdata>/standby.signal
在备库 postgresql.conf(或 conf.d 覆盖)中:
primary_conninfo = 'host=<primary-host> port=5432 user=replication_user password=<password> sslmode=prefer application_name=standby1'
primary_slot_name = '<slot_name>'
hot_standby = on
主库未开 SSL 时,sslmode=prefer 会回退明文;也可显式 disable。生产建议规划证书后使用 require / verify-full。
只读访问还需配置备库 pg_hba.conf。
启动备库
systemctl start postgresql-16
# 查看日志,期望进入 standby 并开始 streaming
日志中常见关键字示意(非固定原文):
entering standby mode
started streaming WAL from primary
验证复制状态
主库
SELECT * FROM pg_stat_replication;
关注:state 是否为 streaming;sent_lsn / write_lsn / flush_lsn / replay_lsn 是否接近;application_name 是否与 primary_conninfo 一致;异步复制时 sync_state 多为 async。
备库
SELECT pg_is_in_recovery(); -- 期望 t
SELECT * FROM pg_stat_wal_receiver; -- status 期望 streaming
数据抽检
在主库写入测试表/行,稍后在备库只读查询是否可见。备库禁止写操作。
手动故障切换
- 确认旧主库已故障且不会双写(必要时隔离网络)。
- 在备库提升:
pg_ctl promote -D <pgdata>
# 或 SQL:SELECT pg_promote();
- 修改应用连接指向新主库。
- 旧主恢复后一般需清空数据,按上文重新
pg_basebackup做成新备库,或废弃。
无自动切换:不会自动改写 VIP/DNS,应用层与运维流程需提前演练。
sslmode 说明
primary_conninfo 中 sslmode 控制备库连主库时的 TLS 行为(主库未开 SSL 时):
| 值 | 主库无 SSL 时 |
|---|---|
disable | 明文,成功 |
allow / prefer(默认倾向) | 尝试后回退明文,通常成功 |
require / verify-ca / verify-full | 失败(无法建立 SSL) |
主库开启 SSL 且证书配齐后,生产更推荐 verify-full。
WAL 保留:wal_keep_size 与 max_slot_wal_keep_size
示例:
wal_keep_size = 0
max_slot_wal_keep_size = -1
含义概括:
wal_keep_size = 0:不按固定尺寸额外囤积 WAL,主要交给复制槽等机制。max_slot_wal_keep_size = -1:不限制单槽可滞留的 WAL 体积上限。
结果是:强依赖复制槽保证备库可追;若槽对应备库长期离线且未删槽,pg_wal 可能撑满磁盘。必须监控磁盘与 pg_replication_slots(active、滞后 LSN)。更稳妥时可给 max_slot_wal_keep_size 设合理上限并配合告警。
常见问题
database system identifier differs between the primary and standby
备库数据目录不是当前主库的 pg_basebackup 产物(本地 initdb、旧集群、指错主库等)。处理:停备库 → 清空 <pgdata> → 重新 basebackup → 写 standby.signal 与 primary_conninfo → 启动。
pg_basebackup: incompatible server version
备库上的 pg_basebackup 与主库主版本不一致。检查:
pg_basebackup --version
psql --version
安装与主库同主版本的 server/client,或用完整路径调用(如 /usr/lib/postgresql/16/bin/pg_basebackup),并调整 PATH。报错后工具可能清理未完成目录,属保护性行为。
备库宕机、主库仍正常
- 主库读写一般不受影响。
- 使用复制槽时主库会为离线备库保留 WAL,磁盘有涨满风险。
- 备库只读流量中断。
- 备库恢复后:槽与 WAL 仍在则可继续追;若未用槽且 WAL 已丢,需重新 basebackup。
注意事项
- 复制密码写在
primary_conninfo时注意文件权限;可用.pgpass等减少明文落盘(按环境选择)。 - 有备库不等于免备份;仍需定期物理/逻辑备份。
- 切换前必须防止旧主复活双写。
- 本文不替代官方发行说明;参数名以当前大版本文档为准。