一、为什么 PostgreSQL 需要主从复制
先从业务价值说起。主从复制至少能解决以下几个问题:
1. 避免单点故障
如果只有一个主库,那么数据库就是全系统的核心单点。一旦这台机器宕机,整个应用基本瘫痪。部署从库后,主库出问题时可以把从库提升为新主库,从而恢复服务。
2. 提高恢复能力
主从复制意味着数据会持续同步到另一台机器。相比只有逻辑备份,复制能提供更快的恢复路径,尤其适合对 RTO(恢复时间目标)有要求的系统。
3. 支持读写分离
虽然本文重点是高可用,但从库还可以承担读请求,例如报表查询、统计分析、后台管理等,从而减轻主库压力。
4. 支持备份与运维操作卸载
很多备份、校验、只读分析任务都可以放在从库执行,减少对主库的干扰。
二、PostgreSQL 主从复制的基本原理
理解原理后,配置过程会清晰很多。
PostgreSQL 的主从复制主要依赖 WAL(Write-Ahead Log,预写式日志)。主库在处理事务时,会先把数据变更写入 WAL;从库则通过流复制(Streaming Replication)接收这些 WAL 记录,并在本地回放,从而让数据保持一致。
整体过程可以概括为:
- 主库产生 WAL
- WAL Sender 进程把日志流发送给从库
- 从库 WAL Receiver 接收日志
- 从库回放 WAL,更新数据文件
- 从库持续追赶主库,保持同步或准同步状态
异步复制与同步复制
- 异步复制:主库提交事务时不等待从库确认,性能更高,但主库突然故障时可能丢少量尚未同步的数据。
- 同步复制:主库提交事务时要等待从库确认,数据安全性更高,但写性能会下降。
生产中很多团队先用异步复制,在更高安全要求场景再评估同步复制。
三、实验环境规划
为了便于说明,假设我们使用两台 Linux 服务器:
- 主库:192.168.1.10
- 从库:192.168.1.11
- PostgreSQL 版本:PostgreSQL 14/15/16 均可,本文命令尽量采用通用写法
- 操作系统:CentOS / Rocky / Ubuntu 思路一致
数据目录假设为:
- /var/lib/pgsql/16/data
复制用户设为:
- 用户名:replicator
- 密码:replica123
请注意,实际生产中密码要更复杂,网络策略也应限制来源 IP。
四、主库配置步骤
第一步:安装 PostgreSQL
不同发行版安装略有差异,这里不展开软件源细节。安装完成后,确认服务已启动:
bash
systemctl status postgresql
或版本化服务名:
bash
systemctl status postgresql-16
第二步:修改 postgresql.conf
找到主库配置文件,通常在数据目录中:
bash
vi /var/lib/pgsql/16/data/postgresql.conf
重点修改以下参数:
listen_addresses = '*' wal_level = replica max_wal_senders = 10 max_replication_slots = 10 wal_keep_size = 1024MB hot_standby = on
参数解释
- listen_addresses='*':允许远程连接
- wal_level=replica:开启复制所需的 WAL 级别
- max_wal_senders=10:允许多少个 WAL 发送进程
- max_replication_slots=10:复制槽数量上限
- wal_keep_size=1024MB:保留一定 WAL,避免从库短暂中断后缺日志
- hot_standby=on:允许从库以只读方式提供查询(主要从库生效)
第三步:配置 pg_hba.conf
编辑主库访问控制文件:
bash
vi /var/lib/pgsql/16/data/pg_hba.conf
增加如下内容:
host replication replicator 192.168.1.11/32 md5 host all all 192.168.1.0/24 md5
第一行允许从库使用 replicator 用户进行复制连接。
第二行是普通客户端访问规则,可按需调整。
第四步:创建复制用户
登录 PostgreSQL:
bash
psql -U postgres
执行:
sql
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'replica123';
第五步:重启主库
bash
systemctl restart postgresql-16
然后检查是否生效:
bash
psql -U postgres -c "SHOW wal_level;" psql -U postgres -c "SHOW max_wal_senders;"
五、从库配置步骤
从库的核心思路是:先通过主库做一次基准备份,然后让从库持续追主。
第一步:停止从库 PostgreSQL 服务
bash
systemctl stop postgresql-16
第二步:清空旧数据目录
如果从库已经初始化过,需要先清理旧数据:
bash
rm -rf /var/lib/pgsql/16/data/*
请务必确认当前机器是从库,避免误删主库数据。
第三步:使用 pg_basebackup 拉取主库基准备份
bash
pg_basebackup -h 192.168.1.10 -p 5432 -U replicator \ -D /var/lib/pgsql/16/data -Fp -Xs -P -R
输入密码后开始备份。
参数说明
- -h:主库地址
- -U replicator:复制用户
- -D:从库数据目录
- -Fp:plain 格式
- -Xs:同时拉取 WAL
- -P:显��进度
- -R:自动写入复制配置(非常重要)
执行完成后,从库数据目录里会生成必要文件。
在较新版本 PostgreSQL 中,-R 会生成 standby.signal 并写入 postgresql.auto.conf 中的主库连接信息。
第四步:检查从库自动生成的连接参数
可查看:
bash
cat /var/lib/pgsql/16/data/postgresql.auto.conf
通常会看到类似内容:
primary_conninfo = 'user=replicator password=replica123 host=192.168.1.10 port=5432 sslmode=prefer sslcompression=0'
同时还会有:
bash
ls /var/lib/pgsql/16/data/standby.signal
只要 standby.signal 存在,实例启动后就会以从库身份运行。
第五步:启动从库
bash
systemctl start postgresql-16
六、验证主从复制是否成功
1. 在主库查看复制连接状态
执行:
bash
psql -U postgres -c "SELECT pid, usename, application_name, client_addr, state, sync_state, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;"
如果能看到从库连接信息,说明主库已经在向从库发送 WAL。
常见字段说明:
- state:通常为 streaming
- sync_state:async 表示异步复制,sync 表示同步复制
- client_addr:从库 IP
2. 在从库判断自己是否为恢复模式
执行:
bash
psql -U postgres -c "SELECT pg_is_in_recovery();"
返回 t 说明当前是从库;返回 f 说明当前是主库。
3. 在主库建表验证同步
主库执行:
sql
CREATE TABLE repl_test ( id serial primary key, name text, created_at timestamp default now() ); INSERT INTO repl_test(name) VALUES ('hello replication');
然后在从库查询:
sql
SELECT * FROM repl_test;
若能查到数据,说明复制工作正常。
七、主从切换实战:主库故障后如何提升从库
主从复制真正的价值,在于故障时能切换。这里先讲最基本的手工切换,这是理解高可用的基础。
场景:主库已经不可用,从库需要提升为新主库
在从库执行:
bash
pg_ctl promote -D /var/lib/pgsql/16/data
如果环境中 pg_ctl 不在 PATH,可使用完整路径。
也可以在 SQL 中确认状态变化:
bash
psql -U postgres -c "SELECT pg_is_in_recovery();"
如果返回 f,说明从库已经提升为主库。
提升后需要做什么
- 应用连接地址切到新主库
- 原主库修复后,不能直接重新加入,必须重新初始化为从库
- 检查业务写入是否恢复正常
八、原主恢复后如何重新加入集群
假设原主库修好后,要变成新主库的从库,通常做法是重新基准备份:
- 停止原主库服务
- 清空原主库旧数据目录
- 从当前新主库执行 pg_basebackup 拉取数据
- 以从库身份启动
命令思路与前面的从库初始化完全类似,只是主从角色已经变化。
如果你追求更高级的"时间线追赶"和最小化重建,可以进一步研究 pg_rewind,但对初学者来说,先掌握"重建从库"是最稳妥的实践路径。
九、延迟监控命令:判断从库是否追上主库
主从复制不是"连上就万事大吉",还必须监控延迟。延迟大了会影响读一致性和故障恢复能力。
1. 主库查看复制发送状态
bash
psql -U postgres -c "SELECT application_name, client_addr, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn, pg_size_pretty(pg_wal_lsn_diff(sent_lsn, replay_lsn)) AS replay_delay_bytes FROM pg_stat_replication;"
这个命令可以看到主库发送位置与从库回放位置之间的字节差异。
2. 从库查看 WAL 接收与回放情况
bash
psql -U postgres -c "SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_size_pretty(pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn())) AS replay_gap;"
如果 replay_gap 很大,说明从库接收了 WAL,但回放速度跟不上。
3. 从库查看回放时间延迟
bash
psql -U postgres -c "SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;"
这个命令非常常用。
如果返回几毫秒、几秒,通常可接受;如果达到几十秒甚至几分钟,就要排查了。
注意:如果从库暂时没有新事务回放,结果可能为 NULL,这是正常现象。
4. 查看从库接收进程状态
bash
psql -U postgres -c "SELECT status, receive_start_lsn, receive_start_tli, written_lsn, flushed_lsn, latest_end_lsn, latest_end_time, slot_name, conninfo FROM pg_stat_wal_receiver;"
这个视图可以帮助你判断从库是否还在正常接收主库 WAL。
十、常用主从切换与排障命令汇总
为了方便实战,这里整理一组高频命令。
主库查看复制状态
bash
psql -U postgres -c "SELECT * FROM pg_stat_replication;"
从库判断角色
bash
psql -U postgres -c "SELECT pg_is_in_recovery();"
从库查看回放延迟
bash
psql -U postgres -c "SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;"
从库查看 WAL 接收器状态
bash
psql -U postgres -c "SELECT * FROM pg_stat_wal_receiver;"
提升从库为主库
bash
pg_ctl promote -D /var/lib/pgsql/16/data
重新基准备份构建从库
bash
pg_basebackup -h 192.168.1.10 -p 5432 -U replicator -D /var/lib/pgsql/16/data -Fp -Xs -P -R
查看当前 WAL 位置
主库:
bash
psql -U postgres -c "SELECT pg_current_wal_lsn();"
从库:
bash
psql -U postgres -c "SELECT pg_last_wal_replay_lsn();"
十一、生产环境中的几个关键建议
1. 复制槽建议合理使用
可通过物理复制槽避免从库断开期间主库过早删除 WAL:
主库创建复制槽:
sql
SELECT * FROM pg_create_physical_replication_slot('standby1_slot');
然后在从库 primary_conninfo 配套使用 primary_slot_name。
但要注意:如果从库长期离线,复制槽会导致主库 WAL 积压,占满磁盘,所以监控必须跟上。
2. WAL 保留与磁盘监控必不可少
主从复制最怕的不是一时延迟,而是从库追不上,主库又把旧 WAL 删掉,导致必须全量重建。因此:
- 监控 WAL 目录增长
- 监控复制延迟
- 合理配置 wal_keep_size
- 对复制槽积压设置告警
3. 切换必须演练
很多团队配置了主从��却从未做过切换演练。真正故障时才发现应用连接没切、连接池缓存旧地址、只读节点误接写流量。
建议定期在测试或预发环境进行手工切换演练。
4. 高可用不等于自动切换
主从复制本身只解决"数据同步",并不自动完成故障检测和 VIP/路由漂移。
如果想实现真正自动化高可用,还需要结合:
- Patroni
- repmgr
- Pacemaker
- keepalived
- 或云厂商提供的高可用组件
本文重点是打牢主从复制基础,理解这些后再看自动化方案会更轻松。
十二、结语
PostgreSQL 主从复制,是数据库高可用体系里最值得优先掌握的一项能力。它不仅能帮助你摆脱单点故障,还能为读写分离、备份卸载、容灾恢复、运维演练打下基础。
从技术实现上看,它并不神秘:核心就是主库输出 WAL,从库持续接收并回放。真正决定成败的,不只是"能配起来",而是是否做好了完整闭环------配置正确、验证有效、延迟可监控、切换可执行、故障后可恢复。
如果你只是刚开始接触 PostgreSQL,建议你先亲手完成一遍本文中的实验:
搭一个主库、搭一个从库、插入一条数据、看它同步、再手工 promote 一次。只要这个流程真正跑通,你对 PostgreSQL 高可用的理解就会立刻从"概念"进入"实战"。