分享实战心得PostgreSQL 主从复制:告别单点故障,附主从切换与延迟监控命令

一、为什么 PostgreSQL 需要主从复制

先从业务价值说起。主从复制至少能解决以下几个问题:

1. 避免单点故障

如果只有一个主库,那么数据库就是全系统的核心单点。一旦这台机器宕机,整个应用基本瘫痪。部署从库后,主库出问题时可以把从库提升为新主库,从而恢复服务。

2. 提高恢复能力

主从复制意味着数据会持续同步到另一台机器。相比只有逻辑备份,复制能提供更快的恢复路径,尤其适合对 RTO(恢复时间目标)有要求的系统。

3. 支持读写分离

虽然本文重点是高可用,但从库还可以承担读请求,例如报表查询、统计分析、后台管理等,从而减轻主库压力。

4. 支持备份与运维操作卸载

很多备份、校验、只读分析任务都可以放在从库执行,减少对主库的干扰。


二、PostgreSQL 主从复制的基本原理

理解原理后,配置过程会清晰很多。

PostgreSQL 的主从复制主要依赖 WAL(Write-Ahead Log,预写式日志)。主库在处理事务时,会先把数据变更写入 WAL;从库则通过流复制(Streaming Replication)接收这些 WAL 记录,并在本地回放,从而让数据保持一致。

整体过程可以概括为:

  1. 主库产生 WAL
  2. WAL Sender 进程把日志流发送给从库
  3. 从库 WAL Receiver 接收日志
  4. 从库回放 WAL,更新数据文件
  5. 从库持续追赶主库,保持同步或准同步状态

异步复制与同步复制

  • 异步复制:主库提交事务时不等待从库确认,性能更高,但主库突然故障时可能丢少量尚未同步的数据。
  • 同步复制:主库提交事务时要等待从库确认,数据安全性更高,但写性能会下降。

生产中很多团队先用异步复制,在更高安全要求场景再评估同步复制。


三、实验环境规划

为了便于说明,假设我们使用两台 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,说明从库已经提升为主库。

提升后需要做什么

  1. 应用连接地址切到新主库
  2. 原主库修复后,不能直接重新加入,必须重新初始化为从库
  3. 检查业务写入是否恢复正常

八、原主恢复后如何重新加入集群

假设原主库修好后,要变成新主库的从库,通常做法是重新基准备份:

  1. 停止原主库服务
  2. 清空原主库旧数据目录
  3. 从当前新主库执行 pg_basebackup 拉取数据
  4. 以从库身份启动

命令思路与前面的从库初始化完全类似,只是主从角色已经变化。

如果你追求更高级的"时间线追赶"和最小化重建,可以进一步研究 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 高可用的理解就会立刻从"概念"进入"实战"。

相关推荐
minebmw78 小时前
Oracle 19.29 中 ORA-00600 [4193] 错误完全解析与恢复指南
数据库·oracle
m0_377618238 小时前
Golang怎么连接MySQL数据库_Golang MySQL连接教程【总结】
jvm·数据库·python
weixin_586061469 小时前
C#怎么通过反射获取类属性_C#如何动态读取元数据【进阶】
jvm·数据库·python
Pluto_CSND9 小时前
PostgreSQL 聚合函数总览
数据库·postgresql
资深数据库专家9 小时前
总账EBS 应用服务器1 的监控分析
java·网络·数据库
m0_6784854510 小时前
CSS如何控制表格单元格边框合并_通过border-collapse实现
jvm·数据库·python
m0_7488394910 小时前
如何用组合继承模式实现父类方法复用与子类属性独立
jvm·数据库·python
qq_3345635510 小时前
PHP源码是否依赖特定芯片组_Intel与AMD平台差异【操作】
jvm·数据库·python
qq_2069013910 小时前
如何使用C#调用Oracle存储过程_OracleCommand配置CommandType.StoredProcedure
jvm·数据库·python