✅ PostgreSQL 复制与高可用架构详解
在生产环境中,数据安全、服务连续性、读写扩展 是核心需求。PostgreSQL 提供了强大的复制机制和灵活的高可用方案。本篇将带你从原理到实战,深入掌握流复制、逻辑复制、高可用架构设计及故障切换。
🧭 一、复制类型总览
| 类型 | 机制 | 数据一致性 | 延迟 | 用途 | PostgreSQL 版本 |
|---|---|---|---|---|---|
| 流复制 | 物理复制 | 强一致 | 毫秒级 | 高可用、读扩展、备份 | 9.0+ |
| 逻辑复制 | 逻辑复制 | 最终一致 | 秒级 | 跨版本、选择性复制、ETL | 10+ |
| 文件复制 | 物理复制 | 强一致 | 分钟级 | 基础备份(pg_basebackup) | 所有版本 |
💡 本篇重点:流复制(高可用) + 逻辑复制(灵活同步)
一、流复制(Streaming Replication)— 高可用核心
✅ 1. 原理
- 主库(Primary):接受写操作,生成 WAL(Write-Ahead Logging)日志
- 备库(Standby):实时接收并应用 WAL 日志,保持数据同步
- 传输方式:通过 TCP 连接传输 WAL 记录(非文件)
主库 → (WAL Sender) → 网络 → (WAL Receiver) → 备库
✅ 2. 部署步骤(主从复制)
▶ 环境准备:
- 主库:192.168.1.10
- 备库:192.168.1.11
- PostgreSQL 版本:16.x
▶ 步骤1:主库配置
# postgresql.conf
listen_addresses = '*' # 监听所有IP
port = 5432
wal_level = replica # 必须设置
max_wal_senders = 10 # 最大WAL发送进程数
wal_keep_size = 1GB # 保留WAL大小(防止备库断开后跟不上)
archive_mode = on # 可选,用于基础备份
archive_command = 'cp %p /path/to/archive/%f' # 归档命令
# pg_hba.conf
host replication replicator 192.168.1.11/32 md5
# 创建复制用户
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'replpass';
重启主库:
pg_ctl restart -D /path/to/data
▶ 步骤2:备库初始化(使用 pg_basebackup)
# 在备库服务器执行
pg_basebackup -h 192.168.1.10 -U replicator -D /var/lib/postgresql/16/main -P -v -R -X stream -C -S standby1
# 参数说明:
# -R:自动生成 recovery.conf(PG 12+ 为 standby.signal + postgresql.auto.conf)
# -X stream:使用流复制协议
# -C -S:创建复制槽(确保WAL不被过早删除)
▶ 步骤3:备库配置
# postgresql.conf(备库)
listen_addresses = '*'
port = 5432
hot_standby = on # 允许备库接受只读查询
# 自动创建的 postgresql.auto.conf(PG 12+)
primary_conninfo = 'host=192.168.1.10 port=5432 user=replicator password=replpass'
primary_slot_name = 'standby1'
启动备库:
pg_ctl start -D /path/to/data
▶ 步骤4:验证复制状态
-- 在主库查看复制状态
SELECT * FROM pg_stat_replication;
-- 在备库查看是否只读
SHOW transaction_read_only; -- 应返回 on
-- 在备库查看延迟
SELECT
pg_last_wal_receive_lsn(),
pg_last_wal_replay_lsn(),
pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) as lag_bytes;
✅ 3. 同步复制 vs 异步复制
| 类型 | 配置 | 优点 | 缺点 |
|---|---|---|---|
| 异步 | synchronous_commit = on(默认) | 主库性能高 | 备库可能丢失数据 |
| 同步 | synchronous_standby_names = 'standby1' | 数据零丢失 | 主库写入延迟增加 |
# postgresql.conf(主库)
synchronous_commit = on
synchronous_standby_names = 'standby1' # 指定同步备库名称
💡 生产环境建议:异步复制 + WAL 归档,或半同步(多数派)
✅ 4. 读写分离与负载均衡
备库可接受只读查询:
-- 在备库执行
SELECT * FROM users WHERE id = 1; -- ✅ 允许
INSERT INTO users VALUES (...); -- ❌ 报错:cannot execute INSERT in a read-only transaction
应用层实现读写分离:
- 使用连接池(PgBouncer + HAProxy)
- ORM 框架路由(如 Django 的 DATABASE_ROUTERS)
二、逻辑复制(Logical Replication)— 灵活同步
✅ 1. 原理
- 复制逻辑变更(INSERT/UPDATE/DELETE),而非物理 WAL
- 支持选择性复制(指定表)
- 支持跨版本、跨平台复制
- 备库可写(非只读)
主库 → (逻辑解码) → 逻辑变更 → 网络 → 备库 → (应用变更)
✅ 2. 部署步骤
▶ 步骤1:主库配置
# postgresql.conf
wal_level = logical # 必须设置
max_replication_slots = 10
max_wal_senders = 10
▶ 步骤2:创建发布(Publication)
-- 发布指定表
CREATE PUBLICATION mypub FOR TABLE users, orders;
-- 发布所有表
CREATE PUBLICATION allpub FOR ALL TABLES;
▶ 步骤3:备库配置
# postgresql.conf
wal_level = logical
▶ 步骤4:备库创建订阅(Subscription)
-- 创建与主库相同的表结构(需手动或使用 pg_dump --schema-only)
CREATE TABLE users (...);
CREATE TABLE orders (...);
-- 创建订阅
CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.10 port=5432 user=replicator password=replpass dbname=mydb'
PUBLICATION mypub;
▶ 步骤5:验证逻辑复制
-- 在主库插入数据
INSERT INTO users (name) VALUES ('Alice');
-- 在备库查询
SELECT * FROM users; -- 应看到 'Alice'
-- 查看复制状态
SELECT * FROM pg_stat_subscription;
✅ 3. 逻辑复制 vs 流复制对比
| 特性 | 流复制 | 逻辑复制 |
|---|---|---|
| 复制内容 | 物理 WAL | 逻辑 SQL 变更 |
| 备库状态 | 只读 | 可读写 |
| 复制粒度 | 整个数据库集群 | 指定表 |
| 跨版本支持 | ❌ 必须相同版本 | ✅ 支持 |
| 冲突处理 | 无冲突(物理一致) | 可能冲突(需处理) |
| 适用场景 | 高可用、备份 | 数据分发、ETL、升级 |
三、高可用架构设计
✅ 1. 架构模式
▶ 模式1:主从 + 手动切换(基础)
应用 → 主库(读写)
↖
备库(只读,手动切换)
缺点:故障切换需人工干预,RTO(恢复时间)长。
▶ 模式2:主从 + 自动切换(推荐)
使用 Patroni + etcd/Consul + HAProxy:
HAProxy
↓
┌─────────┐
│ Patroni │ ←─ etcd(分布式锁)
└─────────┘
↓
主库 / 备库(自动故障切换)
组件说明:
- Patroni:管理 PostgreSQL 集群状态,自动故障切换
- etcd/Consul:分布式配置存储,选举主库
- HAProxy:负载均衡,自动路由到主库
▶ 模式3:多副本 + 读写分离
应用 → HAProxy → 主库(写)
↘ 备库1(读)
↘备库2(读)
✅ 2. Patroni 部署示例(简化版)
▶ 安装 Patroni
pip install patroni[etcd]
▶ 配置 patroni.yml
scope: postgres
name: node1
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.1.10:8008
etcd:
hosts: 192.168.1.100:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
hot_standby: on
wal_keep_size: 1GB
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.10:5432
data_dir: /var/lib/postgresql/16/main
bin_dir: /usr/lib/postgresql/16/bin
authentication:
replication:
username: replicator
password: replpass
superuser:
username: postgres
password: postgres
▶ 启动 Patroni
patroni patroni.yml
✅ 3. 故障切换测试
# 模拟主库宕机
sudo systemctl stop postgresql
# 查看 Patroni 日志,备库应自动提升为主库
# 应用通过 HAProxy 自动连接到新主库
四、监控与维护
✅ 1. 复制延迟监控
-- 流复制延迟(字节)
SELECT
application_name,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) as lag_bytes,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) as lag_pretty
FROM pg_stat_replication;
-- 逻辑复制延迟
SELECT
subscription_name,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), received_lsn)) as lag_bytes
FROM pg_stat_subscription;
✅ 2. 高可用监控
# Patroni 状态
curl http://192.168.1.10:8008/patroni
# 输出示例:
{
"state": "running",
"role": "master",
"server_version": 160000,
"xlog": {
"location": 123456789
}
}
✅ 3. 常见问题处理
❓ 1. 复制中断
# 检查网络、防火墙
ping 192.168.1.10
telnet 192.168.1.10 5432
# 检查复制槽
SELECT * FROM pg_replication_slots;
❓ 2. 备库数据不一致
# 重建备库
pg_basebackup -h 主库IP -U replicator -D /new/data/dir -P -R
❓ 3. 主库切换后应用连接失败
# 检查 HAProxy 配置
# 确保应用连接的是 HAProxy VIP,而非直接连数据库
五、最佳实践
✅ 1. 流复制最佳实践
- 使用复制槽:防止 WAL 被过早删除
- 监控延迟:设置告警阈值(如 > 1GB)
- 定期测试故障切换:确保高可用有效
- 备库资源:CPU/内存不低于主库
- 网络隔离:复制流量走独立网络
✅ 2. 逻辑复制最佳实践
- 主键约束:复制表必须有主键或唯一索引
- DDL 同步:ALTER TABLE 需手动在备库执行
- 冲突处理:设置
session_replication_role = replica避免触发器冲突 - 监控状态:
pg_stat_subscription
✅ 3. 高可用架构最佳实践
- 至少3节点:避免脑裂(etcd/Patroni)
- 自动切换 + 人工确认:重要业务可设置手动确认
- 定期演练:模拟故障,验证恢复流程
- 监控告警:集成 Prometheus + Grafana
- 备份策略:复制 ≠ 备份!仍需 pg_dump + WAL 归档
🎯 六、实践任务
请完成以下操作:
- 在两台机器上部署 PostgreSQL 流复制(主从)
- 验证复制状态和延迟
- 部署 Patroni + etcd 实现自动故障切换
- 模拟主库宕机,观察自动切换过程
- 配置 HAProxy 实现读写分离
- 部署逻辑复制,实现单表跨库同步
📊 架构选择指南
| 需求 | 推荐方案 |
|---|---|
| 高可用 + 数据零丢失 | 流复制 + 同步提交 |
| 读扩展 + 报表分离 | 流复制 + 只读备库 |
| 跨版本升级 | 逻辑复制 |
| 选择性表同步 | 逻辑复制 |
| 企业级高可用 | Patroni + etcd + HAProxy |
| 云环境 | 云厂商托管服务(RDS) |
1077

被折叠的 条评论
为什么被折叠?



