主库配置(wal_level / max_wal_senders)
要让一台 PostgreSQL 实例成为「能对外提供 WAL 的发送方」,需要在主库上完成四项配置:提高 WAL 记录级别、开放足够的 walsender 名额、让监听地址对外可达、创建一个只用于复制的账号并放行 pg_hba.conf。这四项缺任何一项,备库都无法建立复制连接,而且失败原因往往分散在日志与网络层,排查起来很费时间。
本页把主库侧的配置按「必须改的」和「按需改的」两类讲清楚。必须改的是 wal_level、max_wal_senders、listen_addresses 和复制账号授权;按需改的是 wal_keep_size、max_replication_slots、max_slot_wal_keep_size、wal_sender_timeout、synchronous_standby_names。之所以要区分,是因为前者涉及重启窗口,后者多数可以在线调整,规划变更时的风险完全不同。
有一个前提需要反复强调:主库配置的参数在备库提升为主库之后依然生效,含义不变。这些参数描述的是「发送方的能力」,而不是「这台机器是不是主库」。因此把同样的配置保留在所有节点上,会让故障切换后的行为更可预测。本页所有示例都假定运行 PostgreSQL 18。
前置知识
建议先阅读:流复制原理
基础概念
主库侧配置的核心目标是「让 WAL 足够完整、让发送通道足够宽、让连接能被授权」。下表汇总了这些参数的角色与生效方式。
| 参数 | 默认值 | 生效方式 | 是否必须调整 |
|---|---|---|---|
wal_level | replica | 重启 | 是(若当前为 minimal) |
max_wal_senders | 10 | 重启 | 是(若为 0 或名额不足) |
listen_addresses | localhost | 重启 | 是(备库不在本机时) |
wal_keep_size | 0 | reload | 按需(不使用复制槽时) |
max_replication_slots | 10 | 重启 | 按需(使用复制槽且数量较多时) |
max_slot_wal_keep_size | -1 | reload | 推荐调整(防磁盘撑爆) |
wal_sender_timeout | 60s | reload | 一般保持默认 |
synchronous_standby_names | 空 | reload | 按需(要 RPO=0 时) |
wal_level 的三档含义
wal_level 决定写入 WAL 的信息量,也就是「WAL 里记录了多少可用于重建的数据」。它有三个取值:
| 取值 | 记录内容 | 支持的复制方式 | 典型用途 |
|---|---|---|---|
minimal | 只记录崩溃恢复所需的最小信息 | 不支持任何复制 | 单机、可容忍重做备份的批处理 |
replica | 记录足够重建数据页的信息(含物理复制所需) | 物理复制、PITR 归档 | 生产默认、流复制 |
logical | 在 replica 基础上额外记录逻辑解码所需信息(如旧值) | 物理复制 + 逻辑复制 | 需要逻辑解码 / 逻辑订阅 |
logical 与 replica 的关系是包含:logical 能做 replica 能做的一切,代价是 WAL 体积更大。生产上如果没有逻辑复制需求,用 replica(默认值)即可。
需要特别记住 minimal 的两个「坑」:第一,minimal 模式下部分操作(ALTER TABLE ... SET TABLESPACE、CLUSTER、CREATE TABLE、REFRESH MATERIALIZED VIEW(不带 CONCURRENTLY)、REINDEX、TRUNCATE)会走「不写 WAL」的优化路径,因为它假设重放时会重新执行整条命令而非逐页复制;第二,max_wal_senders 非零时服务器无法在 minimal 下启动,两者配置互斥。
max_wal_senders 与 walsender 名额
max_wal_senders 限制同时运行的 walsender 进程数,即「同时能有多少个复制连接或流式基础备份连接」。默认 10,值为 0 表示复制被完全禁用。
需要理解两点:其一,流式基础备份(pg_basebackup 使用 -X stream 时)也会占用一个 walsender 名额,所以实际规划时要把备份工具也算进去;其二,客户端异常断开时连接槽可能被短暂占用直到超时,因此建议配置值比「预期客户端数」略高一些,让断线的客户端能立即重连而不必等待。
max_wal_senders 只能通过重启设置,这一点在扩容备库数量时容易踩坑——加备库之前必须先确认名额并对需要的情况重启。
wal_keep_size 的定位
wal_keep_size 指定 pg_wal 目录中为备库保留的最小 WAL 容量,单位 MB,默认 0。要理解它的两个限定词:
- 最小:它设定的是下限,实际保留量可能更多。系统还需要为归档或从检查点恢复保留额外的段,这些都不受此参数约束。
- 备库用途:它只为「可能落后很多的备库」多留一些缓冲,不保证某个具体备库所需的 WAL 一定存在。
如果值为 0(默认),系统不会为备库额外保留任何 WAL,备库能取到多少历史 WAL,完全取决于「上一个检查点在哪」以及「归档状态如何」。因此在不使用复制槽的方案里,wal_keep_size 是唯一的兜底手段。
一个重要的版本事实:PostgreSQL 13 之前,这个参数叫 wal_keep_segments,单位是 WAL 段数(每段 16MB)。从 PostgreSQL 13 起它被 wal_keep_size 取代,单位改为 MB。关键词是「取代」——wal_keep_size 不是 wal_keep_segments 的别名,在新版本文档里不应该再提 wal_keep_segments。
max_replication_slots 与复制槽上限
max_replication_slots 指定服务器能支持的复制槽数量上限,默认 10,只能在启动时设置。两个使用要点:
- 设置成低于当前已有槽数的值,会导致服务器无法启动。缩容前必须先删除多余槽。
wal_level必须为replica或更高,复制槽才能被使用。
如果集群里既有物理复制槽(给备库)又有逻辑复制槽(给下游订阅),它们共享这个上限,规划时要一起算。
synchronous_standby_names 概览
synchronous_standby_names 是打开同步复制的开关,留空表示不使用同步复制。它的语法有两种模式:
# FIRST 模式:按优先级选出前 num_sync 个作为同步备库
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'
# ANY 模式:从列表里任选 num_sync 个确认即可(quorum 语义)
synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)'备库名来自备库 primary_conninfo 里的 application_name(若未设置,则默认取备库的 cluster_name,都没有时回退为 walreceiver)。因此「给每台备库设置唯一的 application_name」是配置同步复制的前置条件。
这个参数只能是「主库在等备库」,方向不可逆;且它无法跨越级联复制——同步复制要求备库直连主库,级联中的下游备库不能被声明为同步备库。
listen_addresses 与复制可达性
listen_addresses 决定 PostgreSQL 监听哪些网络接口,默认 localhost(只监听回环地址)。备库在另一台机器上时,必须让主库监听对外的网卡地址或使用 *:
listen_addresses = '*'同时相关的还有 port(默认 5432)。监听地址修改需要重启。修改后务必用 ss -lntp 之类的命令确认端口真的在对外监听,而不是只改了配置文件却忘了重启。
wal_sender_timeout 的作用
wal_sender_timeout 是主库判定「备库已经失活」的超时时间,默认 60 秒。walsender 在超过这段时间没有收到备库的任何回复(包括心跳)时,会终止这条复制连接,并在日志里记录一条类似 terminating walsender process due to replication timeout 的消息。
值为 0 会禁用超时机制。禁用之后,一条半死的连接(例如网络中断但没有 FIN 包)会一直挂在那里,占用 walsender 名额,因此除非有明确理由,不建议设为 0。备库侧对应的参数是 wal_receiver_timeout,一般保持两侧接近。
pg_hba.conf 的 replication 条目
复制连接的鉴权与普通连接走同一套 pg_hba.conf,但数据库字段必须写 replication——这是复制协议使用的伪数据库名。写成具体的库名不会匹配,表现为备库连接被拒绝。
# TYPE DATABASE USER ADDRESS METHOD
# 允许 192.168.1.0/24 网段用 repl 账号做复制
host replication repl 192.168.1.0/24 scram-sha-256规则顺序很重要:pg_hba.conf 是自上而下第一条匹配即生效,所以不要把宽泛的 all all all trust 之类的条目放在复制条目之前把它盖掉。修改后需要 reload 生效(pg_ctl reload 或 SELECT pg_reload_conf())。
CREATE ROLE ... REPLICATION
复制账号只需要 REPLICATION 与 LOGIN 两个属性,不需要超级用户。赋予 REPLICATION 之后,该角色可以发起复制连接、也能读取全部 WAL(等价于能读全库数据),所以密码强度必须按高敏感凭据对待。
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'Ch4ngeM3_Str0ng';REPLICATION 是一个独立的角色属性,与 SUPERUSER、CREATEDB、CREATEROLE 并列。查看已有复制角色:
SELECT rolname, rolreplication, rolcanlogin
FROM pg_roles
WHERE rolreplication
ORDER BY rolname;主库侧配置的检查清单
在动手配置备库之前,用下面这张清单把主库确认一遍,可以避免把主库问题误判为备库问题。
| 检查项 | 期望结果 |
|---|---|
SHOW wal_level | replica 或 logical |
SHOW max_wal_senders | 大于实际备库数 + 备份客户端数 |
SHOW listen_addresses | 包含备库可访问的地址 |
| 复制角色存在 | pg_roles.rolreplication = true |
pg_hba.conf 有 replication 条目 | 数据库字段为 replication |
| 复制端口可达 | 从备库 psql replication=database 能成功 |
pg_replication_slots | 规划中的槽已创建(若使用槽) |
语法与用法
主库配置本身就是「改 postgresql.conf + 改 pg_hba.conf + 执行 SQL」三件事。下面给出可照抄的模板。
postgresql.conf 主库侧模板:
# ---------- 必需项(修改后需要重启) ----------
wal_level = replica # 流复制最低要求
max_wal_senders = 10 # 并发 walsender 数,至少为备库数
max_replication_slots = 10 # 复制槽数量上限(使用槽时)
listen_addresses = '*' # 允许备库访问
port = 5432
# ---------- 建议项(reload 生效) ----------
wal_keep_size = 512 # 不使用复制槽时的兜底保留量(MB)
max_slot_wal_keep_size = 10GB # 单槽允许保留的 WAL 上限,防止撑爆磁盘
wal_sender_timeout = 60s # 备库失活判定超时
# ---------- 可选:异步为默认,开启同步复制时再配置 ----------
# synchronous_standby_names = 'FIRST 1 (standby1)'pg_hba.conf 模板:
# 复制连接:DATABASE 字段必须为 replication
host replication repl 192.168.1.20/32 scram-sha-256
host replication repl 192.168.1.21/32 scram-sha-256创建复制角色并验证:
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'Ch4ngeM3_Str0ng';# 从主库本机测试复制连接(IDENTIFY_SYSTEM 是复制协议命令)
psql "host=192.168.1.10 port=5432 user=repl dbname=postgres replication=database" \
-c "IDENTIFY_SYSTEM;"创建物理复制槽:
SELECT pg_create_physical_replication_slot('standby1_slot');让配置生效:
# 只改了可 reload 参数
pg_ctl reload -D /var/lib/postgresql/18/main
# 改了 wal_level / max_wal_senders / listen_addresses 时必须重启
pg_ctl restart -D /var/lib/postgresql/18/main用 SQL 确认实际生效值(尤其是确认 pending_restart):
SELECT name, setting, unit, pending_restart
FROM pg_settings
WHERE name IN ('wal_level', 'max_wal_senders', 'max_replication_slots',
'wal_keep_size', 'max_slot_wal_keep_size', 'wal_sender_timeout')
ORDER BY name; name | setting | unit | pending_restart
--------------------------+---------+------+-----------------
max_replication_slots | 10 | | f
max_slot_wal_keep_size | 10240 | MB | f
max_wal_senders | 10 | | f
wal_keep_size | 512 | MB | f
wal_level | replica | | f
wal_sender_timeout | 60000 | ms | f
(6 rows)详细说明
wal_level 为什么必须至少是 replica
WAL 是「重放即得数据」的日志。要让另一台机器只靠 WAL 重建出与主库逐字节一致的页面,WAL 里必须包含足够的信息。replica 级别保证了两件事:一是数据页变更以「整页镜像 + 行级变更」的形式被完整记录(配合全页写入机制,见WAL 写流程);二是记录粒度细到足以支持任意时刻的崩溃恢复。
minimal 之所以不够,是因为它做了一些「假设重放时会重新执行整条命令」的优化:例如 CREATE TABLE 在 minimal 下可能只记录「发生了建表」,而依赖重放端自己重新执行。这种依赖重放端「再跑一遍逻辑」的方式无法保证与主库物理页一致,因此不能支撑物理复制。
结论:只要打算做流复制,就把 wal_level 设为 replica(或 logical)。这是所有复制能力的第一块基石,也是唯一一个「改了就必须重启」的 WAL 相关参数。
修改 wal_level 的正确顺序
wal_level 的修改有连带影响,尤其是从高改低的时候。正确顺序是:
- 确认当前没有依赖高 WAL 级别的功能在跑(归档、复制、逻辑解码);
- 修改
wal_level; - 重启实例;
- 重新做一次基础备份(从高降到低时尤其重要)。
之所以降级后要重做备份,是因为降低 wal_level 会让先前基于较高 wal_level 产生的 WAL 与新产生的 WAL 在信息量上不一致,用旧备份 + 新 WAL 恢复可能缺少必要信息。反过来,从 minimal 升到 replica 同样建议重做备份,因为升级前的 WAL 缺少复制所需信息。
计算 max_wal_senders 的合理值
max_wal_senders 的规划需要把三类消费者都算上:
| 消费者 | 占用名额 |
|---|---|
| 每个流复制备库 | 1 |
| 每个级联的上游(备库向更下游发送) | 该备库自身需要配置,主库侧不占 |
每次流式基础备份(pg_basebackup -X stream) | 1 |
| 备用余量(断线重连窗口) | 建议 2 以上 |
一个常见的经验公式是「预期同时连接数 + 2」。例:3 台备库 + 偶尔做基础备份,可设为 6~8。设得太紧的典型症状是:一台备库重启后主库日志报 no free replication slots(注意这条消息说的是 walsender 名额,不是复制槽),备库连不上直到某条旧连接超时释放。
复制槽与 wal_keep_size 的取舍
不使用复制槽时,主库无法知道每台备库的进度,只能用 wal_keep_size 保底。这种方案的弱点很明显:保留容量是按「最落后的备库」的假设来定的,如果某台备库停了很久,它需要的 WAL 可能已经被回收。
使用复制槽后,主库为每台备库精确记账,代价是槽会无限制保留 WAL。因此两种方案的风险方向相反:
| 方案 | 主要风险 | 缓解手段 |
|---|---|---|
只用 wal_keep_size | 备库落后过多导致 WAL 缺失、复制中断 | 加大 wal_keep_size、配置归档 |
| 只用复制槽 | 备库长期不连导致 pg_wal 撑爆磁盘 | max_slot_wal_keep_size、idle_replication_slot_timeout |
| 槽 + 归档 + 上限(推荐) | — | 三者互补 |
生产上的稳健组合是:使用复制槽保证不误删 WAL,同时配置 max_slot_wal_keep_size 给磁盘设上限,另外保留 WAL 归档作为「一旦截断还能补齐」的后路。复制槽的创建与维护参见复制槽。
wal_keep_size 与归档的配合
wal_keep_size 只影响 pg_wal 里保留多少段,不影响归档。也就是说,即便 wal_keep_size = 0,只要归档链路正常,主库在段写满时仍会先调用 archive_command 归档,归档成功后才允许回收。
因此备库在 WAL 缺失时,如果没有复制槽,可以从归档目录里补齐(前提是配置了 restore_command)。这就是「流复制 + 归档」组合的额外价值:它给复制中断提供了一条恢复路径,而不必立刻重做基础备份。归档与检查点的关系参见WAL 与检查点最佳实践。
max_slot_wal_keep_size 的行为
max_slot_wal_keep_size 限制单个复制槽允许保留的 WAL 容量,单位 MB,默认 -1(无限)。当某个槽的 restart_lsn 落后当前 LSN 超过这个值时,主库会在检查点删除那些「只被该槽需要」的 WAL 段。
这带来的后果是:使用该槽的备库可能因为所需 WAL 被删除而无法继续复制,必须重做基础备份。这是一个「主动选择丢掉备库、保住主库磁盘」的取舍——相比让主库磁盘写满导致全库不可用,牺牲一台备库显然是更好的选择。
槽的 WAL 可用性可以通过 pg_replication_slots.wal_status 观察,取值包括 reserved(充足)、extended、unreserved、lost。当出现 lost 时,该槽对应的备库已确定无法继续,需要重建。
复制槽相关视图的读法
主库上判断「谁在用哪个槽、落后多少」主要看两个视图:
SELECT slot_name, slot_type, active, active_pid,
restart_lsn, confirmed_flush_lsn
FROM pg_replication_slots
ORDER BY slot_name; slot_name | slot_type | active | active_pid | restart_lsn | confirmed_flush_lsn
---------------+-----------+--------+------------+-------------+---------------------
standby1_slot | physical | t | 12345 | 0/2FF8D18 |
standby2_slot | physical | f | | 0/2F00120 |
(1 row)active = f的物理槽表示备库当前没连上;如果它长期不活跃,pg_wal会因这个槽而持续增长。restart_lsn是槽「还能保证提供 WAL 的最低位置」,它与pg_current_wal_lsn()的差值就是该槽的落后字节数。- 物理槽的
confirmed_flush_lsn通常为空,它主要用于逻辑槽。
PostgreSQL 18 引入了 idle_replication_slot_timeout,可以让长期不活跃的槽在检查点时被自动失效,从而避免「僵尸槽」无限占盘。该参数默认 0(禁用),且只能在 postgresql.conf 或命令行设置。
reload 与 restart 的边界
主库侧参数分两类,改错类别会导致「以为改好了其实没生效」。
| 参数 | 生效方式 | 备注 |
|---|---|---|
wal_level | 重启 | 不能用 pg_reload_conf() |
max_wal_senders | 重启 | 只能启动时设置 |
max_replication_slots | 重启 | 只能启动时设置 |
listen_addresses | 重启 | 涉及 socket 重建 |
port | 重启 | 同上 |
wal_keep_size | reload | 只能在 postgresql.conf 或命令行设置 |
max_slot_wal_keep_size | reload | 只能在 postgresql.conf 或命令行设置 |
idle_replication_slot_timeout | reload | 只能在 postgresql.conf 或命令行设置 |
wal_sender_timeout | reload | 用户/超级用户上下文 |
synchronous_standby_names | reload | 不能在 postgresql.auto.conf 中设置 |
注意最后一条的细节:synchronous_standby_names 和 wal_keep_size 这类参数被限定为「只能在 postgresql.conf 或命令行设置」,意味着用 ALTER SYSTEM SET 写进 postgresql.auto.conf 会被视为无效(而不是报错),这点很容易被忽略。用 pg_settings.pending_restart 可以判断「是否有参数改了但还没重启生效」:
SELECT name, setting, pending_restart
FROM pg_settings
WHERE pending_restart; name | setting | pending_restart
--------------+---------+-----------------
wal_level | replica | t
(1 row)pending_restart = t 表示该参数已修改但需要重启才能生效——这是一个非常值得纳入日常巡检的信号。
复制认证方式的选择
pg_hba.conf 的 METHOD 决定了复制连接的认证方式。常见选择:
| 方法 | 说明 | 适用场景 |
|---|---|---|
scram-sha-256 | 强口令认证(默认推荐) | 跨主机复制的标准选择 |
md5 | 旧式口令认证 | PostgreSQL 18 已弃用,应迁移 |
cert | 客户端证书认证 | 有 PKI 体系时可用,安全性高 |
trust | 无认证放行 | 禁止用于复制连接 |
reject | 明确拒绝 | 用于兜底规则 |
trust 绝不应该出现在复制条目里:它等于把「读取全部 WAL」的权限对网络敞开。PostgreSQL 18 已经弃用 MD5 密码(CREATE ROLE / ALTER ROLE 设置 MD5 密码时会发出弃用警告),新部署应直接用 scram-sha-256。
主库侧的容量与性能影响
开启流复制会给主库带来几项可度量的开销:
- WAL 体积增大:
wal_level从minimal升到replica会增加 WAL 写入量,进而影响磁盘 I/O 与归档量。 - 全页写入开销:为保证备库与崩溃恢复可用,检查点后首次修改的页面会写整页镜像,这会放大 WAL 体积(见全页写入)。
- walsender CPU 与网络:每个 walsender 需要读取 WAL 并序列化发送,备库数量多时 CPU 与出口带宽是可观开销。
- 复制槽引发的 WAL 驻留:槽越落后,
pg_wal越大,占用磁盘并可能影响检查点效率。
因此在规划主库容量时,应把 WAL 目录的磁盘空间、网络出口带宽、以及 walsender 的 CPU 开销一并算进去,而不是只按「单机数据库」估算。
实战示例
示例一:从默认配置改造为可复制的主库
假设主库当前是默认配置(wal_keep_size = 0、listen_addresses = localhost),需要改造成可对外复制。
# 1. 备份原配置
cp /var/lib/postgresql/18/main/postgresql.conf \
/var/lib/postgresql/18/main/postgresql.conf.bak# 2. 编辑 postgresql.conf,加入以下几行
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 512
max_slot_wal_keep_size = 10GB
listen_addresses = '*'
wal_sender_timeout = 60s# 3. 重启使需要重启的参数生效
pg_ctl restart -D /var/lib/postgresql/18/main-- 4. 确认生效
SELECT name, setting, unit, pending_restart
FROM pg_settings
WHERE name IN ('wal_level','max_wal_senders','wal_keep_size','listen_addresses'); name | setting | unit | pending_restart
--------------------+---------+------+-----------------
listen_addresses | * | | f
max_wal_senders | 10 | | f
wal_keep_size | 512 | MB | f
wal_level | replica | | f
(4 rows)示例二:创建复制角色并放行 pg_hba
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'Ch4ngeM3_Str0ng';# pg_hba.conf 追加(注意放在宽泛规则之前)
host replication repl 192.168.1.20/32 scram-sha-256
host replication repl 192.168.1.21/32 scram-sha-256# reload 让 pg_hba 生效
pg_ctl reload -D /var/lib/postgresql/18/main-- 在主库上确认角色属性
SELECT rolname, rolreplication, rolcanlogin, rolsuper
FROM pg_roles WHERE rolname = 'repl'; rolname | rolreplication | rolcanlogin | rolsuper
---------+----------------+-------------+----------
repl | t | t | f
(1 row)注意 rolsuper = f:复制角色不需要超级用户,权限越高风险越大。
示例三:用 IDENTIFY_SYSTEM 验证复制通道
IDENTIFY_SYSTEM 是复制协议自带的「握手 + 自报家门」命令,用它测试可以在动备库之前把认证问题排掉。
psql "host=192.168.1.10 port=5432 user=repl password=Ch4ngeM3_Str0ng \
dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;" systemid | timeline | xlogpos | dbname
---------------------+----------+-----------+--------
7230697861213143552 | 1 | 0/3000000 |
(1 row)如果这条命令失败,常见原因与对应检查点:
| 报错/现象 | 可能原因 |
|---|---|
no pg_hba.conf entry for replication connection | pg_hba.conf 缺少 replication 条目或网段不匹配 |
password authentication failed | 密码错误、password_encryption 与存储方式不一致 |
could not connect to server | listen_addresses 未开放、防火墙拦截、端口错误 |
FATAL: replication is not enabled | wal_level 为 minimal 或 max_wal_senders 为 0 |
示例四:创建物理复制槽并观察状态
SELECT pg_create_physical_replication_slot('standby1_slot'); pg_create_physical_replication_slot
-------------------------------------
(standby1_slot,0/3000000)
(1 row)-- 稍后再观察,槽在备库连上后会变为 active
SELECT slot_name, slot_type, active, restart_lsn, wal_status
FROM pg_replication_slots; slot_name | slot_type | active | restart_lsn | wal_status
---------------+-----------+--------+-------------+------------
standby1_slot | physical | f | 0/3000000 | reserved
(1 row)wal_status = reserved 表示槽需要保留的 WAL 都还在,备库随时可以连接。若某天变成 lost,就意味着该槽需要的 WAL 已被删除,备库必须重建。
示例五:评估是否打开了同步复制
如果业务要求 RPO = 0,需要配置 synchronous_standby_names。先确认备库名(即备库 primary_conninfo 中的 application_name),再设置:
synchronous_standby_names = 'FIRST 1 (standby1)'
synchronous_commit = 'on'-- reload 后确认
SELECT name, setting FROM pg_settings
WHERE name IN ('synchronous_standby_names','synchronous_commit'); name | setting
---------------------------+--------------
synchronous_standby_names | FIRST 1 (standby1)
synchronous_commit | on
(1 row)-- 观察每个备库是否被识别为同步
SELECT application_name, sync_priority, sync_state, state
FROM pg_stat_replication; application_name | sync_priority | sync_state | state
------------------+---------------+------------+-----------
standby1 | 1 | sync | streaming
standby2 | 0 | potential | streaming
(1 row)sync_state = sync 表示该备库当前被计为同步确认者;potential 表示它是候选(在当前同步备库故障后可顶上);async 表示它不参与同步确认。同步复制的完整机制参见同步复制配置。
注意事项
wal_keep_size 取代了 wal_keep_segments,不是别名。 从 PostgreSQL 13 起旧参数被移除并换成以 MB 为单位的 wal_keep_size。在 PostgreSQL 18 上不存在 wal_keep_segments,不要再按段数配置。
listen_addresses 改了不重启等于没改。 这是最隐蔽的问题之一:配置文件里写好了新值,但实例还是旧 socket,表现为备库连不上而主库自己完全正常。用 pg_settings.pending_restart 可以确认是否有未生效的参数。
pg_hba.conf 的匹配顺序是自上而下第一条命中。 如果前面有一条宽泛的规则(例如针对同网段的 all all)先命中,后面精心写的 replication 条目根本不会生效。放行范围应尽量收窄。
max_replication_slots 设得比现有槽数少会导致实例无法启动。 这是「改小参数」的经典事故。缩容的正确顺序是先删槽再改参数再重启。
max_wal_senders = 0 会彻底禁用复制。 包括 pg_basebackup 的流式备份在内,全部失败。如果有人为了「省资源」把它设为 0,任何复制能力都会消失。
synchronous_standby_names 与 wal_keep_size 不能在 postgresql.auto.conf 生效。 这两个参数被限定为「只能在 postgresql.conf 或命令行设置」,用 ALTER SYSTEM SET 写入不会生效,且不一定报错,容易造成困惑。
同步复制的备库名必须与备库 application_name 严格一致。 备库未设置 application_name 时默认值是 walreceiver(或备库的 cluster_name),如果主库按自以为的名字配置同步,结果会是「同步复制静默地不生效」——因为没有任何备库匹配上。配置完成后务必用 pg_stat_replication.sync_state 确认。
复制账号的密码是高敏感凭据。 拥有 REPLICATION 的角色可以读取全部 WAL,等价于能还原全库数据。密码要按数据库管理员账号的级别保护,不要写在明文脚本或镜像里。
开启 wal_level = logical 会显著增加 WAL 体积。 它额外记录逻辑解码所需的信息,对写入密集型系统的磁盘与带宽影响不可忽略。没有逻辑复制需求时就用 replica。
不要在主库上手工删除 pg_wal 中的文件。 无论是为了「省空间」还是「清理旧的」,手工删除都会造成 WAL 断档或复制中断。要控制占用,应通过复制槽上限、归档修复等正常手段。
最佳实践
把主库配置模板化,并在所有节点保持一致。
wal_level、max_wal_senders、max_replication_slots、wal_keep_size这类参数描述的是「发送能力」,提升后的备库同样需要,统一配置可以避免切换后行为不一致。max_wal_senders按「备库数 + 备份客户端数 + 2」规划。 留足断线重连的余量,避免一台备库重启后长时间连不上。优先使用复制槽,同时必须设置
max_slot_wal_keep_size。 光有槽没有上限,就是给磁盘埋雷;只设上限不用槽,则进度无法精确跟踪。两者要成对使用。在 PostgreSQL 18 上评估启用
idle_replication_slot_timeout。 它可以自动失效长期不活跃的槽,防止僵尸槽无限占盘。注意槽失效在检查点触发,配置的时长不是精确的失效时刻。复制账号专用、最小权限、强密码。 只授予
REPLICATION与LOGIN,绝不授予SUPERUSER,认证方式使用scram-sha-256。pg_hba.conf复制条目按最小网段放行。 使用/32单机精度而不是整段/24,并按业务需要精确到每台备库。把「待重启参数」纳入巡检。 定期查询
pg_settings中pending_restart = true的行,避免有人在事故中改了wal_level却忘了重启,导致复制始终失败。wal_sender_timeout保持默认或按网络质量微调,不要设为 0。 高延迟或抖动大的跨地域链路可以适当调大;禁用超时则会让半死连接长期占用 walsender 名额。主库同时保留 WAL 归档。 归档既支撑 PITR,也是复制 WAL 缺失时的补齐来源。归档配置参见WAL 归档配置。
给
pg_wal目录与网络出口分别设置告警。pg_wal突增通常指向复制槽落后或归档故障;出口带宽饱和则说明备库数量或传输量已经超出链路承载能力。配置同步复制前,先明确「备库不可用时主库是否接受阻塞」。 同步复制的代价是可用性与写入延迟,必须与业务方共同确认,而不是由 DBA 单方面决定。
每次修改主库复制相关参数后,都从备库侧验证一次。 主库
SHOW出来的值只是「主库以为的」,真正的健康判定要靠备库能否连上并持续回放(见pg_stat_replication)。
下一节
参考链接
- PostgreSQL 官方文档:Replication — Configuration Parameters
- PostgreSQL 官方文档:Write Ahead Log — Configuration Parameters
- PostgreSQL 官方文档:Log-Shipping Standby Servers
- PostgreSQL 官方文档:The pg_hba.conf File
- PostgreSQL 官方文档:CREATE ROLE
- PostgreSQL 官方文档:Streaming Replication Protocol
- PostgreSQL 官方文档:Connection and Authentication — Settings
- PostgreSQL 官方文档:Monitoring Database Activity — Cumulative Statistics System
- PostgreSQL 官方文档:pg_basebackup
- PostgreSQL 官方文档:Release 18