强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

PostgreSQL 完全指南 / 12 - 复制机制

第 12 章 · 复制机制

复制是高可用和读扩展的基础。PostgreSQL 提供流复制(物理复制)和逻辑复制两种方式。


12.1 复制概览

类型数据格式用途版本
流复制(Streaming Replication)WAL 字节流主从热备、读扩展PG 9.0+
逻辑复制(Logical Replication)逻辑变更(行级)跨版本迁移、部分同步PG 10+
┌──────────┐     WAL Stream     ┌──────────┐
│  Primary │ ─────────────────→ │ Standby  │
│ (主库)    │  物理复制           │ (从库)    │
└──────────┘                    └──────────┘

┌──────────┐   逻辑复制/发布订阅  ┌──────────┐
│  Source  │ ─────────────────→ │  Target  │
│ (源库)    │  行级变更           │ (目标库)  │
└──────────┘                    └──────────┘

12.2 流复制(Streaming Replication)

主库配置

# postgresql.conf
wal_level = replica                  # 必须 ≥ replica
max_wal_senders = 5                  # 最大发送进程数
wal_keep_size = 1GB                  # 保留的 WAL 大小
hot_standby = on                     # 从库可读(建议开启)
synchronous_commit = on              # 同步提交
# synchronous_standby_names = 'standby1'  # 同步从库(可选)
# pg_hba.conf
# 允许从库连接
host    replication    replicator    10.0.0.0/8    scram-sha-256
-- 创建复制用户
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'securepassword';

从库搭建

# 方式 1:pg_basebackup(推荐)
pg_basebackup -h primary_host -U replicator -D /var/lib/postgresql/data \
  --checkpoint=fast --wal-method=stream -R

# -R 选项自动创建 standby.signal 和配置 primary_conninfo

# 方式 2:手动配置
# 停止从库
# 清空从库数据目录
# 复制主库数据
# 创建 standby.signal 文件

从库配置:

# postgresql.conf(从库)
hot_standby = on
primary_conninfo = 'host=primary_host port=5432 user=replicator password=securepassword'
# 创建 standby.signal(pg_basebackup -R 自动创建)
touch /var/lib/postgresql/data/standby.signal

# 启动从库
pg_ctl -D /var/lib/postgresql/data start

复制监控

-- 主库:查看从库状态
SELECT
    client_addr,
    state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replication_lag_bytes
FROM pg_stat_replication;

-- 从库:查看复制状态
SELECT
    status,
    received_lsn,
    latest_end_lsn,
    last_msg_send_time,
    last_msg_receipt_time
FROM pg_stat_wal_receiver;

-- 复制延迟
SELECT
    CASE WHEN pg_is_in_recovery()
        THEN pg_last_wal_receive_lsn()
        ELSE pg_current_wal_lsn()
    END AS current_lsn,
    CASE WHEN pg_is_in_recovery()
        THEN pg_last_wal_replay_lsn()
    END AS replay_lsn;

12.3 同步复制

# 主库 postgresql.conf
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
# ANY 1: 至少 1 个从库确认写入即可
# FIRST 2 (standby1, standby2): 前 2 个必须确认
模式配置说明
异步不设置主库不等待从库确认,可能丢数据
同步synchronous_standby_names等待从库确认,数据零丢失

⚠️ 注意事项:同步复制会增加写入延迟。建议使用 ANY 1 模式,确保至少一个从库确认即可。


12.4 逻辑复制(Logical Replication)

发布端(Publisher)

# postgresql.conf
wal_level = logical  # 必须
max_replication_slots = 4
max_wal_senders = 4
-- 创建发布
CREATE PUBLICATION my_pub FOR TABLE employees, orders;

-- 发布所有表
CREATE PUBLICATION all_tables FOR ALL TABLES;

-- 发布特定表的特定操作
CREATE PUBLICATION insert_only FOR TABLE orders
    WITH (publish = 'insert');

-- 查看发布
SELECT * FROM pg_publication;
SELECT * FROM pg_publication_tables;

订阅端(Subscriber)

-- 创建订阅
CREATE SUBSCRIPTION my_sub
    CONNECTION 'host=publisher_host dbname=mydb user=replicator password=pass'
    PUBLICATION my_pub;

-- 查看订阅状态
SELECT * FROM pg_subscription;
SELECT * FROM pg_stat_subscription;

逻辑复制 vs 流复制

特性流复制逻辑复制
数据粒度整个集群特定表
从库可写❌ 只读✅ 可写
跨版本❌ 必须同版本✅ 支持不同版本
跨平台❌ 必须同平台✅ 支持不同平台
DDL 同步✅ 自动❌ 需手动
表结构要求完全一致订阅端需提前建表
冲突处理无冲突需处理冲突
大表初始同步全量复制自动初始数据复制

12.5 复制槽(Replication Slot)

-- 物理复制槽
SELECT pg_create_physical_replication_slot('standby1_slot');

-- 逻辑复制槽(通常由 CREATE SUBSCRIPTION 自动创建)
SELECT pg_create_logical_replication_slot('my_slot', 'pgoutput');

-- 查看所有复制槽
SELECT
    slot_name,
    slot_type,
    active,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots;

-- 删除不再使用的复制槽
SELECT pg_drop_replication_slot('my_slot');

⚠️ 注意事项:不活跃的复制槽会导致 WAL 文件堆积,最终撑满磁盘!必须及时删除不再使用的复制槽。


业务场景

场景推荐方案
主从高可用流复制 + 自动故障切换(Patroni)
读写分离流复制(从库读)+ 连接池路由
跨版本升级逻辑复制迁移数据
部分表同步逻辑复制
数据分发(多源)逻辑复制发布/订阅

扩展阅读