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) |
| 读写分离 | 流复制(从库读)+ 连接池路由 |
| 跨版本升级 | 逻辑复制迁移数据 |
| 部分表同步 | 逻辑复制 |
| 数据分发(多源) | 逻辑复制发布/订阅 |