环境:Ubuntu 22.04 × 2 · PostgreSQL 16 · 适合生产参考
上个月给项目搭主从,照着老教程一路配下来"看起来都对了",结果主库跑两天后 WAL 把磁盘撑爆,主库直接罢工。排查完才明白是复制没配防漂移,WAL 只进不出。这篇把一次配稳的完整流程和坑都写出来,你可以直接抄。
先说架构:一主一从,异步流复制(生产最常用),主库 192.168.1.10,从库 192.168.1.11,都是 PG 16。
一、主库配置:三个参数一个用户
编辑主库的 postgresql.conf:
ini
listen_addresses = '*'
wal_level = replica # 流复制最低要求,默认就是它,确认一下
max_wal_senders = 10 # wal 发送进程上限,留点余量
max_replication_slots = 10 # 复制槽上限,后面要用
建专用复制用户(别拿超级用户跑复制):
sql
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'ReplPass_2026';
二、pg_hba.conf 放行复制连接
sql
# TYPE DATABASE USER ADDRESS METHOD
host replication repl 192.168.1.0/24 scram-sha-256
注意这行的 DATABASE 是 replication ,不是业务库名。它匹配的是复制流的专用通道,和业务连接的 host all all ... 是两回事。改完 reload 即可:SELECT pg_reload_conf();(但 listen_addresses 是 postmaster 级参数,第一次改要 restart)。
三、从库:pg_basebackup 一把梭
从库装同版本 PG 16 后,先停服务,用 pg_basebackup 从主库拉基线:
css
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 被提前清理的关键,下面细说
确认属主后启动:
bash
exit
sudo systemctl start postgresql
四、验证:两条命令定乾坤
主库上看发送状态:
sql
SELECT client_addr, state, sync_state, write_lag, flush_lag, replay_lag
FROM pg_stat_replication;
看到 state = streaming 就成了。replay_lag 是从库回放延迟,平时盯着它就知道主从落后多少。
从库上确认身份:
csharp
SELECT pg_is_in_recovery(); -- true,说明是从库,只读
顺手验证只读 :在从库执行 CREATE TABLE t1(id int);,报 cannot execute CREATE TABLE in a read-only transaction 就是正常的------从库天生只读,别想着手工改。
五、我踩的坑,帮你提前踩了
坑1:不配复制槽,WAL 漂移撑爆主库
不用复制槽时,主库按 wal_keep_size 留 WAL。从库断线超过保留窗口后重连,只能从头再来一次 basebackup。我一开始按老教程只设了 wal_keep_size,从库断了一天,重搭。用复制槽后,主库会替从库保留未消费的 WAL,从库断了多久都能续上 ------这就是上面 --slot 的意义。但注意反向风险,见坑2。
坑2:复制槽是把双刃剑------从库长期下线,WAL 堆积照样爆盘
我那次爆盘的真正原因:复制槽 standby1 在,但从库所在机器被回收了没人管,主库一直替它留 WAL,留到磁盘 100%。所以生产上复制槽必须配监控 :盯 pg_replication_slots 的 active 和 restart_lsn,从库确认不要了就 SELECT pg_drop_replication_slot('standby1'); 及时删。
坑3:两台机器 PG 小版本不一致
从库装的是 16.4,主库后来升到 16.6,某次重启后复制直接报版本不匹配。流复制要求主从小版本一致(大版本更不用说)。上生产前把两台的 apt 源锁到同一个版本,升级一起升。
六、再进一步的两个方向
- 同步复制 :主库设
synchronous_standby_names='ANY 1 (standby1)',至少一台从库确认后才返回提交,防单点丢数据,代价是写入延迟。金融类场景再开,一般业务异步够用。 - 故障切换 :手动
pg_promote()能把从库提成主库,但生产别靠手速,上 Patroni 这类自动切换组件------正好也是 PGCCC PCP/PCM 课程里高可用模块的实操内容,想系统学的可以去看。
环境:PostgreSQL 16 on Ubuntu 22.04。命令以 PG 16 为准,15 及以前参数名略有差异(如 wal_keep_segments → wal_keep_size)。