synchronous_standby_names
synchronous_standby_names 是同步复制的「开关」参数。它回答两个问题:等谁(哪些备库算数)和等几个(需要几个备库确认)。上一节的 synchronous_commit 只回答「等到哪一步」,本参数才决定「同步复制是否成立」。
它的值是一段有特定语法的字符串,包含三种写法:FIRST num_sync (standby_name, ...)、ANY num_sync (standby_name, ...),以及省略关键字的简写 standby_name, ...。前两种分别对应「优先级模式」与「quorum 模式」,是理解本参数的核心。
一个非常关键的运维事实是:本参数为 sighup 级,通过 pg_reload_conf() 即可生效,不需要重启。这让「临时摘除同步备库以解除写阻塞」成为一个可以在线执行的应急操作,而不需要付出重启数据库的代价。
另一个需要牢记的点是:备库名的匹配依赖 application_name。如果备库没有正确设置 application_name,那么无论主库这边写什么名字都可能匹配不上,结果是同步复制「配置了但不生效」。这是本参数最常见的配置故障。
前置知识
建议先阅读:synchronous_commit 配置
基础概念
在讲语法之前,先把几个反复出现的术语固定下来。这些术语在 pg_stat_replication 的 sync_state 列里会直接出现,理解它们才能读懂监控输出。
| 术语 | 含义 |
|---|---|
num_sync | 需要多少个备库确认才算提交成功 |
standby_name | 备库的名字,通常对应备库的 application_name |
FIRST | 优先级模式,按列表顺序取前 num_sync 个可用的 |
ANY | quorum 模式,列表中任意 num_sync 个备库确认即可 |
sync | 当前真正承担同步确认的备库 |
potential | FIRST 模式下排在其后、随时可补位的备库 |
async | 完全不参与同步确认的备库 |
quorum | ANY 模式下的同步备库角色 |
同步复制成立的两个条件
同步复制的成立需要同时满足三个条件,缺一不可。把它们列清楚,可以避免「配了但没生效」的困惑:
| 条件 | 检查位置 |
|---|---|
synchronous_standby_names 非空 | SHOW synchronous_standby_names; |
| 至少有一个备库匹配到列表中的名字 | pg_stat_replication.application_name |
备库连接状态为 streaming | pg_stat_replication.state |
任何一条不满足,同步复制都不会实际发生。其中第二条最容易被忽略:即使主库写了 synchronous_standby_names = 'standby1',如果备库的 application_name 是默认的 walreceiver,两者就对不上,备库会被归入 async,同步复制静默失效。
备库名从哪来
备库的 standby_name 来源有明确优先级。PostgreSQL 按下面的顺序确定一个 walsender 对应的名字:
| 优先级 | 来源 | 说明 |
|---|---|---|
| 1 | application_name | 备库在 primary_conninfo 中设置的 application_name |
| 2 | cluster_name | 若 application_name 为空,则使用备库的 cluster_name |
| 3 | walreceiver | 若两者都为空,则为固定的 walreceiver |
因此最可靠的实践是:在备库的 primary_conninfo 中显式设置 application_name,不要依赖默认值。这样主库的 synchronous_standby_names 才能稳定匹配。
# 备库 postgresql.conf
primary_conninfo = 'host=10.0.0.10 port=5432 user=repl password=*** application_name=standby1'名字匹配的大小写规则
standby_name 的匹配是大小写不敏感的。也就是说,主库写 standby1、备库设 Standby1,仍然可以匹配上。这一规则同样适用于 application_name 的比较。
但这并不意味着可以随意混用大小写。包含特殊字符或需要保留大小写含义的名字必须用双引号括起来,就像 SQL 标识符的规则一样。不加引号时,名字会被折叠为小写。
# 不加引号:名字会被规范化为小写
synchronous_standby_names = 'standby1'
# 含空格或需保留原样:必须用双引号
synchronous_standby_names = '"standby 1"'空值就是异步
synchronous_standby_names 的默认值是空字符串。空值意味着没有任何同步备库,此时实例处于异步复制模式,synchronous_commit 的备库相关档位全部退化为本地等待。
这一点之所以重要,是因为它让「关闭同步复制」变成了一个极低成本的应急动作:只要把本参数置空并 reload,所有被同步复制卡住的写操作会立刻恢复。这也是本页后面「应急摘除」一节的基础。
语法与用法
本参数支持三种写法,分别对应不同的语义。
写法一:FIRST(优先级模式)
# 需要 1 个备库确认,按顺序优先 standby1,不可用时用 standby2
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'
# 需要 2 个备库确认(列表前两个可用的)
synchronous_standby_names = 'FIRST 2 (standby1, standby2, standby3)'写法二:ANY(quorum 模式,PostgreSQL 10 引入)
# 列表中任意 2 个备库确认即可,不要求特定的备库
synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)'
# 任意 1 个备库确认即可
synchronous_standby_names = 'ANY 1 (standby1, standby2, standby3)'写法三:省略关键字的简写
# 等价于 FIRST 1 (standby1, standby2)
synchronous_standby_names = 'standby1, standby2'
# 等价于 FIRST 1 (任意名字) —— 通配所有备库
synchronous_standby_names = '*'* 是一个特殊值,表示「匹配任意备库名」。使用 * 时,任何已连接的备库都可能被选为同步备库,具体选谁由 sync_priority 决定。
生效方式
-- 在线修改(无需重启)
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby1, standby2)';
SELECT pg_reload_conf();
-- 确认生效
SHOW synchronous_standby_names;也可以直接改 postgresql.conf 后执行 pg_ctl reload 或 SELECT pg_reload_conf();。两者的区别在于,ALTER SYSTEM 写入的是 postgresql.auto.conf,优先级高于 postgresql.conf。
查看当前同步备库状态
SELECT application_name, client_addr, state, sync_state, sync_priority
FROM pg_stat_replication
ORDER BY sync_priority DESC, application_name; application_name | client_addr | state | sync_state | sync_priority
------------------+-------------+-----------+------------+---------------
standby1 | 10.0.0.11 | streaming | sync | 1
standby2 | 10.0.0.12 | streaming | potential | 2
analytics | 10.0.0.13 | streaming | async | 0
(3 rows)详细说明
FIRST 与 ANY 的语义差异
FIRST 与 ANY 是两种截然不同的设计取向,理解差异是选型的关键。
| 维度 | FIRST(优先级) | ANY(quorum) |
|---|---|---|
| 选择方式 | 按列表顺序,取前 num_sync 个可用的 | 任意 num_sync 个确认即可 |
| 是否保证特定备库收到 | 是(优先列表中靠前的) | 否(不保证某一个具体备库收到) |
| 备库故障时的行为 | 顺延到列表中的下一个可用备库 | 用剩余可用备库凑够 num_sync |
| 适用场景 | 有明确的主备层级(如同一机房优先) | 多副本对等,追求更高可用性 |
| 引入版本 | 早期版本 | PostgreSQL 10 |
一个形象的比喻是:FIRST 像「按值班表叫人」,叫不到 A 就叫 B、再叫不到就叫 C;ANY 像「在大厅里喊一声,谁先应算谁」。
这个差异在实际运维中的表现是:使用 FIRST 时,可以预期「确认提交的总是机房内那台低延迟备库」;使用 ANY 时,确认提交的可能是任何一台,包括跨机房的高延迟备库,因此延迟表现可能不稳定。
FIRST 的顺延行为
FIRST 模式下,PostgreSQL 会把列表中的备库按顺序「填位」:先尝试让第一个成为 sync,如果它不可用(断连或落后),则把第二个提上来成为 sync,原来的第二个变为 sync,后续依此类推。
这一点可以用 pg_stat_replication 直观验证:
-- standby1 断开后
application_name | sync_state | sync_priority
------------------+------------+---------------
standby2 | sync | 2
standby3 | potential | 3standby1 消失后,standby2 自动变成了 sync。整个过程不需要人工干预,也不会阻塞写入(前提是列表里还有可用的备库)。
这个顺延能力是 FIRST 模式的重要价值:它让「主备切换后的同步复制」能够自动衔接。但要注意,顺延的前提是「列表里还有其他可用备库」。如果列表里只有 standby1 一个,那么它断连时同步复制会直接变成写阻塞。
num_sync 与备库数量的关系
num_sync 与列表中备库的数量之间有一个必须满足的关系,违反它会造成严重后果:
| 情况 | 结果 |
|---|---|
num_sync ≤ 可用备库数 | 正常,提交按预期等待确认 |
num_sync > 可用备库数 | 提交永久阻塞,写操作全部卡住 |
同步备库数不足会导致提交永久阻塞
如果把 FIRST 2 (standby1, standby2) 中的 standby2 停掉,而 standby1 也恰好不可用,那么没有任何备库能凑够 num_sync = 2,主库上的所有写事务会无限期阻塞在 SyncRep 等待上,直到有备库恢复或参数被改回。这不是超时,而是真正的「永久等待」,因为 PostgreSQL 的设计目标是「宁可不返回,也不违反同步承诺」。
应急恢复手段:执行 ALTER SYSTEM SET synchronous_standby_names = ''; 然后 SELECT pg_reload_conf();,把同步复制临时关闭,写操作会立刻恢复;等备库修好后再把参数改回来。
因此 num_sync 的设置必须结合「有多少备库可以在故障时顶上」来考虑。如果只有两台备库,把 num_sync 设为 2 意味着「任何一台备库不可用,主库就写不动」——这是非常脆弱的配置。
* 通配符的用法与风险
synchronous_standby_names = '*' 表示匹配任意备库名,等价于 FIRST 1 (*)。它的优点是配置简单,不需要逐个维护备库名;缺点是任何连上来的备库都会被纳入同步候选,包括临时的分析库或测试库。
这在多租户或环境混用的机器上是一个隐患:某个临时从主库拉流做测试的实例,可能会因为 * 被选为同步备库,从而影响主库的提交延迟;如果它随后断连,还可能引发写阻塞。
因此 * 只建议用在「备库集合固定、且都应由主库同步保护」的场景。生产环境更推荐显式列出备库名。
同步与异步混合部署
一个实例上可以同时存在同步备库与异步备库,这对读写分离架构非常有用:用同步备库保证不丢数据,用异步备库承接只读查询(避免只读查询拖慢主库提交)。
# 只把 standby1、standby2 纳入同步候选,analytics 保持异步
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'pg_stat_replication.sync_state 的四种取值正好描述了这种混合局面:
sync_state | 含义 | 是否影响提交 |
|---|---|---|
sync | 当前承担同步确认的备库 | 是 |
potential | FIRST 模式下可补位的备库 | 否(除非被提升为 sync) |
async | 异步备库 | 否 |
quorum | ANY 模式下已确认的同步备库 | 是 |
在 FIRST 1 (s1, s2) 的情形下,s1 是 sync、s2 是 potential,两者都在同步列表里,但只有 s1 实际参与当前确认;把 s1 停掉,s2 会自动变成 sync。
sync_priority 的意义
sync_priority 表示备库在同步列表中的优先级。它的取值规则是:
| 情况 | sync_priority |
|---|---|
在 FIRST 列表中,排在第一位 | 正整数,越小越优先(按列表位置编号) |
在 FIRST 列表中,排在后面 | 依次递增 |
| 异步备库 | 0(不参与同步) |
在 ANY(quorum)模式下,sync_priority 通常都是 0,因为 quorum 不关心顺序。因此不要用 sync_priority 去判断 quorum 模式下的同步状态,应该看 sync_state 是否为 quorum。
一个实用的监控规则是:只要存在 sync_state = 'sync' 的备库,就说明同步复制在正常工作;如果所有备库都是 async,说明同步复制实际未生效,需要立刻排查备库名匹配问题。
备库名匹配不上时的表现
备库名匹配失败是同步复制最常见的故障,其表现具有隐蔽性:没有任何报错,只是同步复制静默失效。
典型症状:
synchronous_standby_names的值看起来是对的;pg_stat_replication里有备库在streaming,但sync_state全是async;- 主库的提交延迟没有变化(说明根本没在等备库);
- 用
SHOW synchronous_standby_names;确认参数已生效。
排查方法是对比两边的名字:
-- 主库侧:看备库实际报到主库的名字
SELECT application_name, client_addr, sync_state
FROM pg_stat_replication; application_name | client_addr | sync_state
------------------+-------------+------------
walreceiver | 10.0.0.11 | async
(1 row)上面的输出中,备库的名字是默认的 walreceiver,而主库配置的是 standby1,两者不匹配,所以 sync_state 是 async。修复方式是到备库上修改 primary_conninfo:
# 备库 postgresql.conf
primary_conninfo = 'host=10.0.0.10 port=5432 user=repl application_name=standby1'改完后需要重启备库(primary_conninfo 是 postgresql.conf 参数,备库侧修改后需重启恢复进程)或在备库上执行 SELECT pg_reload_conf();。
写阻塞的排查与恢复
当同步备库不可用导致写入阻塞时,快速恢复是第一优先级。一个标准的排查与处置流程如下:
-- 第一步:确认是否有大量会话在等同步复制
SELECT count(*) AS waiting_sessions, min(query_start) AS oldest
FROM pg_stat_activity
WHERE wait_event = 'SyncRep'; waiting_sessions | oldest
------------------+-------------------------------
218 | 2026-09-30 10:12:41.220+08
(1 row)-- 第二步:确认同步备库状态(是否还有 sync)
SELECT application_name, state, sync_state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication; application_name | state | sync_state | replay_lag_bytes
------------------+-----------+------------+------------------
standby1 | streaming | async | 918273645
(1 row)第三步——如果确认同步备库已不可用且业务写入已受影响,临时摘除:
ALTER SYSTEM SET synchronous_standby_names = '';
SELECT pg_reload_conf();执行后,等待 SyncRep 的会话会立刻被唤醒,写入恢复。需要注意的是,这是一次数据保护等级的临时降级:在此期间提交的事务没有同步备库保护,主库崩溃仍可能丢数据。因此必须在故障排除后立刻改回,并记录这次降级的时间窗口。
如果希望「暂时只摘掉故障的那一台」,也可以把参数改成只包含健康备库的列表:
-- 从 FIRST 1 (standby1, standby2) 改成 FIRST 1 (standby2)
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby2)';
SELECT pg_reload_conf();这种方式比整体置空更精细,保留了同步保护,是在「还有健康备库」时应该优先采用的处置方式。
与复制槽的配合
复制槽与同步复制是两个正交的机制,常常一起使用:
| 机制 | 解决的问题 |
|---|---|
| 复制槽 | 主库不会在备库收到之前回收 WAL,避免备库断连后需要重建 |
| 同步复制 | 提交时等待备库确认,主库故障时不丢已提交事务 |
一个常见的组合配置是:为每个备库建一个物理复制槽,同时用 synchronous_standby_names 指定同步备库。这样既能避免备库短暂断连导致的 WAL 断档,又能保证提交的持久性。
需要注意,复制槽由备库通过 primary_slot_name 指定:
# 备库 postgresql.conf
primary_conninfo = 'host=10.0.0.10 port=5432 user=repl application_name=standby1'
primary_slot_name = 'standby1_slot'复制槽的存在会让主库「等到备库收到为止」地保留 WAL,这在同步复制失效(例如被临时置空)时提供了一个额外缓冲:即使同步复制被摘除,只要备库最终恢复连接,仍有可能通过复制槽追上进度。
与 Patroni 的配合
使用 Patroni 时,synchronous_standby_names 通常不要手工维护。Patroni 会根据集群状态自动生成这个参数,其行为由配置项控制:
| 配置项 | 作用 |
|---|---|
synchronous_mode | 开启同步复制,选中一个同步备库 |
synchronous_mode_strict | 严格模式,不自动降级为异步 |
synchronous_node_count | 同步备库数量,对应 num_sync |
Patroni 的做法是:先选出一个延迟最低的备库,把它写进 synchronous_standby_names,并把其他备库列为候选。当该备库故障时,Patroni 会自动改写参数切换到下一个候选。
因此在使用 Patroni 的环境中,手工 ALTER SYSTEM SET synchronous_standby_names 往往会被 Patroni 覆盖。正确的调整方式是修改 Patroni 的配置文件并重启 Patroni 进程。判断参数是否被托管,可以观察 synchronous_standby_names 是否在备库切换时自动变化——如果会自动变,说明有工具在管理。
多备库下的选型建议
不同规模下,synchronous_standby_names 的推荐写法不同:
| 场景 | 推荐写法 | 理由 |
|---|---|---|
| 一主一备 | FIRST 1 (standby1) | 简单明确,但备库故障即写阻塞 |
| 一主两备 | FIRST 1 (standby1, standby2) | 有顺延能力,单备库故障不阻塞 |
| 一主三备(同机房优先) | FIRST 1 (local1, local2, remote1) | 优先同机房低延迟 |
| 一主三备(对等) | ANY 2 (s1, s2, s3) | 任意两个确认,容错性更强 |
| 备库动态增减 | * 或 FIRST 1 (*) | 免维护,但需确保备库集合可控 |
一个经验法则是:num_sync 不要等于备库总数。留出至少一个余量,才能在单台备库故障时不阻塞写入。例如三台备库配 ANY 2,可以容忍任意一台故障而写入不受影响;配 ANY 3 则任何一台故障都会导致写阻塞。
参数变化的可见性
调整同步备库列表后,可以立即从几个地方验证效果:
| 观察点 | 期望 |
|---|---|
SHOW synchronous_standby_names; | 返回最新值 |
pg_stat_replication.sync_state | 出现 sync(或 quorum) |
pg_stat_activity.wait_event = 'SyncRep' | 出现等待(说明确实在等) |
| 应用侧提交延迟 | 相应上升(这是同步生效的代价) |
如果前三项都对但第四项没变化,需要确认应用连接是否复用了旧连接(synchronous_commit 是 user 级参数,老连接不会自动更新),或者备库的 fsync 太快导致延迟增量被噪声淹没。
实战示例
示例一:一主两备的完整配置
主库(postgresql.conf):
# 主库配置
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1GB
synchronous_commit = on
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'主库的复制授权(pg_hba.conf):
# 允许复制用户从备库网段连接
host replication repl 10.0.0.0/24 scram-sha-256备库(postgresql.conf):
# 备库 1
primary_conninfo = 'host=10.0.0.10 port=5432 user=repl password=*** application_name=standby1'
primary_slot_name = 'standby1_slot'
hot_standby = on# 备库 2
primary_conninfo = 'host=10.0.0.10 port=5432 user=repl password=*** application_name=standby2'
primary_slot_name = 'standby2_slot'
hot_standby = on验证结果应该形如:
SELECT application_name, sync_state, sync_priority, state
FROM pg_stat_replication ORDER BY sync_priority DESC; application_name | sync_state | sync_priority | state
------------------+------------+---------------+-----------
standby1 | sync | 1 | streaming
standby2 | potential | 2 | streaming
(2 rows)示例二:模拟备库故障时的顺延
先把 standby1 停掉:
# 在备库 1 上停止实例
pg_ctl -D /var/lib/pgsql/18/data stop -m fast在主库上观察:
SELECT application_name, sync_state, sync_priority
FROM pg_stat_replication ORDER BY sync_priority DESC; application_name | sync_state | sync_priority
------------------+------------+---------------
standby2 | sync | 2
(1 row)standby2 从 potential 变成了 sync,写入没有被阻塞。这就是 FIRST 模式顺延能力的价值:只要列表里还有备库,单台故障不会影响可用性。
示例三:模拟 num_sync 过大导致的写阻塞
把参数改成需要两个备库确认,然后停掉其中一台:
-- 主库:需要 2 个确认,但只有 2 台备库
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 2 (standby1, standby2)';
SELECT pg_reload_conf();# 停掉 standby1
pg_ctl -D /var/lib/pgsql/18/data stop -m fast此时在主库执行写入:
INSERT INTO t_probe(id, ts) VALUES (1, now());这条语句会一直挂起不返回。用另一个会话查看:
SELECT pid, state, wait_event_type, wait_event, query
FROM pg_stat_activity
WHERE wait_event = 'SyncRep'; pid | state | wait_event_type | wait_event | query
-------+--------+-----------------+------------+----------------------------------
21044 | active | IPC | SyncRep | INSERT INTO t_probe(id, ts) ...
(1 row)这正是「num_sync 大于可用备库数导致永久阻塞」。恢复方式:
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby1, standby2)';
SELECT pg_reload_conf();改回 num_sync = 1 后,挂起的 INSERT 会立刻完成。
示例四:应急摘除同步复制
-- 记录当前值与时间,便于事后恢复
SELECT current_setting('synchronous_standby_names') AS before_removal; before_removal
------------------------------
FIRST 1 (standby1, standby2)
(1 row)-- 临时置空,解除写阻塞
ALTER SYSTEM SET synchronous_standby_names = '';
SELECT pg_reload_conf();
-- 确认已生效
SHOW synchronous_standby_names; synchronous_standby_names
---------------------------
(1 row)确认写入恢复:
SELECT count(*) FROM pg_stat_activity WHERE wait_event = 'SyncRep'; count
-------
0
(1 row)故障排除后,务必恢复同步保护:
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby1, standby2)';
SELECT pg_reload_conf();示例五:排查备库名不匹配
-- 主库配置的名字
SHOW synchronous_standby_names; synchronous_standby_names
---------------------------
FIRST 1 (standby1)
(1 row)-- 备库实际报到的名字
SELECT application_name, sync_state FROM pg_stat_replication; application_name | sync_state
------------------+------------
walreceiver | async
(1 row)两边名字不一致,导致 sync_state 是 async,同步复制没有生效。在备库上修正 primary_conninfo 中的 application_name 后重启备库恢复进程即可。
示例六:用 ANY 配置 quorum 并观察状态
ALTER SYSTEM SET synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)';
SELECT pg_reload_conf();SELECT application_name, state, sync_state
FROM pg_stat_replication
ORDER BY application_name; application_name | state | sync_state
------------------+-----------+------------
standby1 | streaming | quorum
standby2 | streaming | quorum
standby3 | streaming | quorum
(3 rows)在 ANY 模式下,参与同步的备库 sync_state 显示为 quorum,而非 sync/potential。这是区分 FIRST 与 ANY 的一个直观标志。
注意事项
备库名必须有对应的 application_name。 这是本参数第一大故障源。备库没有正确设置 application_name 时,主库配置再正确也无法匹配,且不会有任何报错。
num_sync 大于可用备库数会导致永久写阻塞。 这不是超时或重试,而是真正的无限等待。设计 num_sync 时必须留出至少一台备库的余量。
本参数是 sighup 级,可以 reload 生效,无需重启。 这使得在线应急摘除同步复制成为可能,应把这条命令写进应急手册。
改动 synchronous_standby_names 会影响正在等待的后端。 把备库从列表中移除会让正在等待该备库确认的事务立刻被唤醒(因为不再需要等它),这是应急处置能立即生效的原因;反过来,把备库加入列表可能让后续提交开始变慢。
FIRST 与 ANY 不要混写在同一个值里。 两种写法互斥,必须二选一。写错会导致参数解析失败或语义不符预期。
含有特殊字符的备库名要加双引号。 与 SQL 标识符规则一致,不加引号时名字会被规范化为小写,可能导致匹配失败。
* 通配符会把所有备库纳入候选。 在有临时实例连入主库的环境中,这可能带来意料之外的同步备库与提交延迟。
延迟备库不要放进同步列表。 设置了 recovery_min_apply_delay 的备库如果在同步列表中且档位是 remote_apply,会让主库提交等待整个延迟时间,等价于数据库写死。
托管方案下不要手工改这个参数。 Patroni 等工具会自动覆盖它,手工修改会导致「改了又变回去」,应通过工具的配置项调整。
监控 sync_state 而不是只看参数值。 参数非空不等于同步生效,唯一可靠的判断是 pg_stat_replication 中存在 sync 或 quorum 状态的备库。
最佳实践
为每个备库显式设置
application_name。 不要依赖cluster_name或默认的walreceiver,显式命名是避免匹配失败最有效的手段。num_sync永远留出至少一台余量。 三台备库配ANY 2或FIRST 1,都能容忍单台故障;配到与备库数相同则非常脆弱。优先使用
FIRST以获得可预期的延迟。 如果备库分布在不同机房,FIRST可以确保确认来自低延迟的那一台;ANY的延迟不确定性更高。把同步备库按网络延迟排序。 在
FIRST列表中,把同机房、低延迟的备库放前面,跨机房的放后面作为后备。同时配置复制槽与同步复制。 复制槽保证断连后能续上,同步复制保证不丢提交,两者互补。
把「临时置空
synchronous_standby_names」写进应急手册。 同时写清恢复命令与「事后必须改回」的检查项,避免应急后忘记恢复导致长期无保护运行。对
sync_state消失设置告警。 当实例上「存在同步备库」变成「全部为async」时,说明同步复制已经失效,这应当是一个高优先级告警。对
SyncRep等待会话数设置告警。 等待数突然升高是同步备库变慢或掉线的第一信号;等待数长期不为零则说明同步复制成了常态瓶颈。定期在演练环境模拟单台备库故障。 验证顺延是否按预期发生、写入是否被阻塞,把「
num_sync是否留了余量」变成一次实测而不是纸上推演。使用托管方案时,在工具配置中声明同步需求。 不要在 PostgreSQL 层面手工维护
synchronous_standby_names,避免与自动化逻辑互相打架。变更同步备库列表时同步更新监控与文档。 备库名、
num_sync、模式(FIRST/ANY)都应记录在架构文档里,避免后续排查时靠猜。不要用
*作为长期配置。 它适合动态环境或临时场景;稳态生产环境应显式列出备库名,避免临时实例意外成为同步备库。
参考链接
- PostgreSQL 官方文档:Replication — Configuration Parameters
- PostgreSQL 官方文档:Write Ahead Log — Configuration Parameters
- PostgreSQL 官方文档:Log-Shipping Standby Servers
- PostgreSQL 官方文档:Monitoring Database Activity
- PostgreSQL 官方文档:High Availability, Load Balancing, and Replication
- PostgreSQL 官方文档:ALTER SYSTEM
- PostgreSQL 官方文档:Server Configuration — Managing Configuration Files
- PostgreSQL 官方文档:System Administration Functions
- PostgreSQL 官方文档:pg_stat_replication View
- PostgreSQL 官方文档:The pg_hba.conf File