PostgreSQL 流复制实战:主从搭建与高可用切换

PostgreSQL 流复制(Streaming Replication)是构建读写分离、异地容灾和高可用架构的基石。本文从零演示一主一从的搭建、同步/异步差异、延迟监控与故障切换,所有命令均可直接复制。

一、什么是流复制(为什么需要它)

流复制的原理是:主库把 WAL(Write-Ahead Log,预写日志) 通过 TCP 实时推送到从库,从库持续重放这些日志,从而保持与主库几乎一致的数据状态。它的典型用途有三类:一是 读写分离,把大量只读查询(报表、搜索)分流到从库;二是 容灾,异地从库在主库机房故障时顶上;三是 高可用切换,从库 promoted 成新主库,业务无感知。

关于 PostgreSQL 的体系与日常运维,可参考 PostgreSQL 实战 一文打底。

二、异步 vs 同步:先定 RPO/RTO

搭建前先回答一个问题:能接受丢多少数据?这决定了用异步还是同步复制。

维度异步复制同步复制
提交确认主库提交即返回,不等从库至少一个从库确认落盘才返回
数据安全性可能丢失最后几秒(RPO>0)零丢失(RPO=0)
写性能几乎无影响写延迟增加,从库宕机主库被阻塞
适用场景读多写少、可容忍极小丢失金融交易、订单等强一致需求

绝大多数业务先用异步,等对一致性要求极高时再针对性开启同步。

三、环境准备

准备两台机器(或单机用 Docker 跑两个容器演示):主库 192.168.1.10,从库 192.168.1.11,PostgreSQL 15+(大版本必须一致,否则 WAL 不兼容)。

3.1 主库 postgresql.conf

listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 1GB        # PG13+ 取代旧的 wal_keep_segments

3.2 pg_hba.conf 放行复制连接

# 仅允许从库 IP 用复制专用账号连接
host    replication     repl_user      192.168.1.11/32    scram-sha-256

3.3 创建复制用户

CREATE ROLE repl_user WITH REPLICATION PASSWORD 'strong_pwd' LOGIN;

修改配置后重载:SELECT pg_reload_conf(); 或 pg_ctl reload。

四、从库基础备份与拉起

用 pg_basebackup 从主库拉一份一致性备份,并顺便生成复制配置:

pg_basebackup -h 192.168.1.10 -U repl_user -D /var/lib/pgsql/15/data \
  -Fp -Xs -P -R -C --slot=replica1

其中 -R 会自动生成 standby.signal 与 primary_conninfo,省去手工配置;--slot=replica1 创建复制槽,防止主库过早清理从库还没接收的 WAL。

4.1 关键配置(postgresql.auto.conf)

primary_conninfo = 'host=192.168.1.10 port=5432 user=repl_user password=strong_pwd'
primary_slot_name = 'replica1'
restore_command = 'cp /archive/%f %p'   # 若开启归档用于 PITR

五、做成只读从库并验证

启动从库后,先确认它确实在”恢复模式”(即从库),再在主库查 walsender 状态:

-- 在从库执行,应返回 t
SELECT pg_is_in_recovery();

-- 在主库执行,应能看到从库的连接
SELECT pid, usename, application_name, state, sync_state
FROM pg_stat_replication;

在从库建表会被拒绝(默认只读)。读写分离可在应用层用连接池(如 PgBouncer)把读请求路由到从库;慢查询定位可配合 PostgreSQL 慢查询优化。

六、同步复制:把 RPO 压到 0

在主库的 postgresql.conf 指定同步从库:

synchronous_standby_names = 'replica1'

从库通过 application_name 与这个名字匹配。注意:同步从库一旦宕机,主库写操作会被阻塞。生产建议用 quorum 写多个:synchronous_standby_names = 'ANY 1 (replica1, replica2)',任一存活即可,兼顾安全与可用。

七、延迟监控与告警

从库延迟是核心指标。一条 SQL 即可看出复制滞后多少:

SELECT now() - pg_last_xact_replay_timestamp() AS replication_lag;
监控字段(pg_stat_replication)含义告警建议
write_lag / flush_lag / replay_lag从库写/落盘/重放落后主库的时长replay_lag > 30s 告警
sent_lsn / replay_lsn已发送 / 已重放的日志位置两者差值持续增大需排查
state复制流状态(streaming/catchup)非 streaming 立即排查

八、故障切换:手动与自动

主库宕机时,把从库提升为新主库。手动方式(PG12+ 推荐 SQL):

-- 在从库执行,把它提升为主库
SELECT pg_promote();

手动切换慢且易出错,生产常用自动方案:

方案特点适用
Patroni依赖 etcd/Consul,强一致、自动选主、防脑裂中大型、多节点
repmgr轻量、自带 witness 节点、运维简单中小型集群
Keepalived + VIP最简单,靠 VIP 漂移单从库、容忍脑裂风险

九、常见坑与排障清单

  • 大版本不一致:主从 PG 大版本必须相同,否则 WAL 格式不兼容,复制直接失败。
  • 复制槽堆积撑爆磁盘:wal_keep_size 配合复制槽会保留 WAL,从库长期离线会导致主库磁盘被占满,需监控 pg_replication_slots。
  • 从库停太久重建:若 WAL 已被清理,需重新 pg_basebackup 全量重建。
  • 同步复制脑裂:务必配置多个 synchronous_standby_names 或用 quorum,避免单点阻塞。

十、与备份、慢查询协同

流复制是”近实时副本”,不是备份——主库误删一张表,删除操作会立刻同步到从库。因此它必须配合 数据库 PITR 时间点恢复 与定期物理备份,才能在误操作时回滚。容器化部署可参考 Docker 实战 把 PG 跑在编排里,便于一键拉起从库。

十一、复制槽(Replication Slot)深入

复制槽是主库上记录”从库还需要哪些 WAL”的对象。有了它,即使 wal_keep_size 设得很小,主库也不会清理从库尚未接收的日志,从而避免从库因 WAL 缺失而中断复制。查看槽状态:

SELECT slot_name, active, restart_lsn, wal_status
FROM pg_replication_slots;

需要警惕的是:物理槽(physical)一旦对应从库离线且不清理,WAL 会无限堆积、最终撑爆主库磁盘,因此必须配合监控告警。临时槽(temporary)在连接断开时自动删除,适合一次性迁移与升级场景。

十二、级联复制与延迟从库

从库还可以再挂载从库,形成 级联复制,把主库的 WAL 发送压力分摊出去。更实用的技巧是 延迟从库:故意让某个从库落后主库几小时重放,一旦主库发生误删数据,能在延迟窗口内从它抢救回来:

# 在从库 postgresql.conf 中设置,落后主库 4 小时再重放
recovery_min_apply_delay = '4h'

延迟从库配合 数据库 PITR 时间点恢复,构成”副本 + 时间点备份”的双保险,是生产环境误操作的最后一道防线。

十三、上线前检查清单

检查项命令 / 配置通过标准
大版本一致SELECT version();主从完全相同
复制在流pg_stat_replication.state值为 streaming
延迟达标replay_lag< 30s
槽不堆积pg_replication_slots.wal_status非 ‘lost’
切换演练SELECT pg_promote();从库升主成功且原主不再写入

掌握流复制后,你就拥有了读写分离、容灾与高可用的底座。下一步可以叠加连接池、负载均衡与自动选主,把单点 PostgreSQL 升级为真正的高可用数据库服务。

上一篇 前端埋点实战:手动打点、可视化与无埋点方案
下一篇 一致哈希实战:从原理到分布式缓存与分片落地
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]