PostgreSQL 复制与高可用架构详解

PostgreSQL 复制与高可用架构详解

在生产环境中,数据安全、服务连续性、读写扩展 是核心需求。PostgreSQL 提供了强大的复制机制和灵活的高可用方案。本篇将带你从原理到实战,深入掌握流复制、逻辑复制、高可用架构设计及故障切换。


🧭 一、复制类型总览

类型机制数据一致性延迟用途PostgreSQL 版本
流复制物理复制强一致毫秒级高可用、读扩展、备份9.0+
逻辑复制逻辑复制最终一致秒级跨版本、选择性复制、ETL10+
文件复制物理复制强一致分钟级基础备份(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. 流复制最佳实践

  1. 使用复制槽:防止 WAL 被过早删除
  2. 监控延迟:设置告警阈值(如 > 1GB)
  3. 定期测试故障切换:确保高可用有效
  4. 备库资源:CPU/内存不低于主库
  5. 网络隔离:复制流量走独立网络

✅ 2. 逻辑复制最佳实践

  1. 主键约束:复制表必须有主键或唯一索引
  2. DDL 同步:ALTER TABLE 需手动在备库执行
  3. 冲突处理:设置 session_replication_role = replica 避免触发器冲突
  4. 监控状态pg_stat_subscription

✅ 3. 高可用架构最佳实践

  1. 至少3节点:避免脑裂(etcd/Patroni)
  2. 自动切换 + 人工确认:重要业务可设置手动确认
  3. 定期演练:模拟故障,验证恢复流程
  4. 监控告警:集成 Prometheus + Grafana
  5. 备份策略:复制 ≠ 备份!仍需 pg_dump + WAL 归档

🎯 六、实践任务

请完成以下操作:

  1. 在两台机器上部署 PostgreSQL 流复制(主从)
  2. 验证复制状态和延迟
  3. 部署 Patroni + etcd 实现自动故障切换
  4. 模拟主库宕机,观察自动切换过程
  5. 配置 HAProxy 实现读写分离
  6. 部署逻辑复制,实现单表跨库同步

📊 架构选择指南

需求推荐方案
高可用 + 数据零丢失流复制 + 同步提交
读扩展 + 报表分离流复制 + 只读备库
跨版本升级逻辑复制
选择性表同步逻辑复制
企业级高可用Patroni + etcd + HAProxy
云环境云厂商托管服务(RDS)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值