上个月给项目搭主从,照着老教程一路配下来"看起来都对了",结果主库跑两天后 WAL 把磁盘撑爆,主库直接罢工。排查完才明白是复制没配防漂移,WAL 只进不出。这篇把一次配稳的完整流程和坑都写出来,你可以直接抄。
先说架构:一主一从,异步流复制(生产最常用),主库 192.168.1.10,从库 192.168.1.11,都是 PG 16。
编辑主库的 postgresql.conf:
listen_addresses = '*' wal_level = replica # 流复制最低要求,默认就是它,确认一下 max_wal_senders = 10 # wal 发送进程上限,留点余量 max_replication_slots = 10 # 复制槽上限,后面要用
建专用复制用户(别拿超级用户跑复制):
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'ReplPass_2026';
# TYPE DATABASE USER ADDRESS METHOD host replication repl 192.168.1.0/24 scram-sha-256
host all all ... 是两回事。改完 reload 即可:SELECT pg_reload_conf();(但 listen_addresses 是 postmaster 级参数,第一次改要 restart)。从库装同版本 PG 16 后,先停服务,用 pg_basebackup 从主库拉基线:
sudo systemctl stop postgresql sudo -i -u postgres pg_basebackup -h 192.168.1.10 -U repl -D /var/lib/postgresql/16/main \ -Fp -Xs -P -R --slot=standby1 --create-slot
参数说人话:
-Fp:纯文件格式,和普通数据目录一样
-Xs:备份期间 WAL 以流的方式同步过来,不依赖主库留旧日志
-R:自动生成 standby.signal 并写好 primary_conninfo,省手写
--slot=standby1 --create-slot:创建并绑定复制槽,防 WAL 被提前清理的关键,下面细说
确认属主后启动:
exit sudo systemctl start postgresql
主库上看发送状态:
SELECT client_addr, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;
看到 state = streaming 就成了。replay_lag 是从库回放延迟,平时盯着它就知道主从落后多少。
从库上确认身份:
SELECT pg_is_in_recovery(); -- true,说明是从库,只读
CREATE TABLE t1(id int);,报 cannot execute CREATE TABLE in a read-only transaction 就是正常的——从库天生只读,别想着手工改。wal_keep_size 留 WAL。从库断线超过保留窗口后重连,只能从头再来一次 basebackup。我一开始按老教程只设了 wal_keep_size,从库断了一天,重搭。用复制槽后,主库会替从库保留未消费的 WAL,从库断了多久都能续上——这就是上面 --slot 的意义。但注意反向风险,见坑2。standby1 在,但从库所在机器被回收了没人管,主库一直替它留 WAL,留到磁盘 100%。所以生产上复制槽必须配监控:盯 pg_replication_slots 的 active 和 restart_lsn,从库确认不要了就 SELECT pg_drop_replication_slot('standby1'); 及时删。同步复制:主库设 synchronous_standby_names='ANY 1 (standby1)',至少一台从库确认后才返回提交,防单点丢数据,代价是写入延迟。金融类场景再开,一般业务异步够用。
故障切换:手动 pg_promote() 能把从库提成主库,但生产别靠手速,上 Patroni 这类自动切换组件——正好也是 PGCCC PCP/PCM 课程里高可用模块的实操内容,想系统学的可以去看。
扫码联系我们
电话:19165199818