目录

pgsql-34 主从复制与高可用

1. 概述

复制(Replication)是高可用和读扩展的基础。PostgreSQL 的复制建立在 WAL与检查点机制 之上:主库把 WAL 传给从库重放,从而保持数据一致。

复制解决两类问题:

  1. 高可用(HA):主库宕机时从库顶上,减少停机。
  2. 读扩展:读请求分流到从库,减轻主库压力。

对比 MySQL:MySQL 主从基于 binlog(逻辑日志)传输并在从库重放;PostgreSQL 流复制基于 WAL(物理日志)。MySQL 复制默认异步、也支持半同步;PG 支持异步和同步复制。两者概念相通,但 PG 的物理流复制是"字节级完全一致的副本",MySQL binlog 复制是"逻辑重放"。

2. 复制的两大维度

2.1 物理复制 vs 逻辑复制

维度 物理复制(流复制) 逻辑复制
传输内容 WAL 字节流(整实例) 解码后的行变更(按表/发布)
粒度 整个实例,全量一致 可只复制部分表
跨版本 需同大版本 可跨版本(升级利器)
从库可写 只读 可写(双向/聚合场景)
典型用途 HA、读副本 部分同步、跨版本升级、数据分发

2.2 同步 vs 异步

模式 提交何时返回 数据安全 性能
异步(默认) 主库写完 WAL 即返回 主库宕机可能丢最后几笔
同步 等至少一个从库确认收到 WAL 不丢已提交数据 慢(受网络影响)
# 同步复制配置(主库)
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'  # 至少1个从库确认
synchronous_commit = on

3. 搭建流复制(物理)

3.1 主库配置

# postgresql.conf
wal_level = replica
max_wal_senders = 10           # 允许的复制连接数
wal_keep_size = 1GB            # 保留WAL供从库追赶(或用复制槽更可靠)
# pg_hba.conf:允许从库以复制身份连接
host replication replicator 10.0.0.0/24 md5
-- 创建复制专用角色
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'xxx';

3.2 复制槽(推荐)

复制槽(replication slot)确保主库在从库确认前不删除对应 WAL,避免从库落后太多后追不上。

SELECT pg_create_physical_replication_slot('standby1_slot');

3.3 从库搭建

# 用基础备份初始化从库,-R 自动生成复制连接配置
pg_basebackup -h primary_host -D $PGDATA -U replicator -P -R \
    -X stream -S standby1_slot
# -R 会自动写入 primary_conninfo 并创建 standby.signal
pg_ctl start   # 启动即进入流复制

4. 监控复制状态

-- 主库上看各从库同步情况和延迟
SELECT client_addr, state, sync_state,
       pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS 延迟字节
FROM pg_stat_replication;

-- 从库上看复制延迟(时间)
SELECT now() - pg_last_xact_replay_timestamp() AS 复制延迟;

5. 读写分离

从库默认只读,可承接读请求:

-- 从库上查询会报错的写操作
INSERT INTO t VALUES (1);   -- ERROR: cannot execute INSERT in a read-only transaction

读写分离实现方式:

  • 应用层:写连主库、读连从库(代码或 ORM 路由)。
  • 中间件:Pgpool-II、或在 PgBouncer 前加路由层。
  • ⚠️ 复制延迟坑:异步复制下从库可能读到旧数据(写完立刻读从库读不到)。对一致性敏感的读要走主库,或用同步复制。

6. 自动故障转移与高可用

流复制本身不会自动切换主库——主库挂了需要有机制把某个从库提升为新主库并让应用重连。生产用专门的 HA 方案:

方案 说明
Patroni 最流行。用 etcd/Consul/ZooKeeper 做分布式选主,自动故障转移 + 配置管理
repmgr 轻量,复制管理和手动/自动故障转移
Pgpool-II 连接池 + 负载均衡 + 故障转移一体
云托管 RDS/云数据库自带高可用,最省心

Patroni 架构:每个 PG 节点跑一个 Patroni 进程,通过 etcd 竞争"leader key",持有者为主库;主库失联后其他节点重新选主并提升,配合 HAProxy/VIP 让应用透明重连。

# patroni.yml 关键片段
scope: pg-cluster
etcd:
  hosts: 10.0.0.10:2379
postgresql:
  data_dir: /var/lib/postgresql/data
  parameters:
    max_wal_senders: 10

7. 面试高频问答

Q1:PostgreSQL 流复制基于什么?和 MySQL 有何不同? 基于 WAL 物理日志传输并在从库重放,是字节级完全一致的副本;MySQL 基于 binlog 逻辑日志重放。PG 也有逻辑复制(解码 WAL 成行变更),可按表复制、跨版本。

Q2:同步复制和异步复制怎么选? 异步性能好但主库宕机可能丢最后几笔已提交数据;同步不丢数据但每次提交要等从库确认、受网络影响慢。金融等强一致场景用同步,一般场景用异步。

Q3:物理复制和逻辑复制的区别? 物理复制传 WAL 字节流、整实例一致、从库只读、需同版本;逻辑复制传解码后的行变更、可只复制部分表、可跨版本、从库可写。跨大版本升级常用逻辑复制。

Q4:复制槽有什么用? 保证主库在从库确认消费前不回收对应 WAL,防止从库落后过多导致所需 WAL 被删而无法追赶。

Q5:流复制能自动故障转移吗?怎么实现 HA? 不能,流复制只负责数据同步。自动故障转移需 Patroni(+etcd)、repmgr 或 Pgpool-II 等方案选主并提升从库,配合 VIP/HAProxy 让应用重连。

Q6:读写分离要注意什么? 异步复制存在延迟,从库可能读到旧数据。对一致性敏感的"写后立即读"应走主库,或采用同步复制/延迟检测。

8. 下一步

学习 监控与日志管理,保障数据库可观测性。