PostgreSQL数据库技术 第 8 篇:高可用架构与复制技术

摘要

本文作为PostgreSQL数据库技术系列的最终篇,全面介绍数据库的高可用架构和复制技术。高可用性是现代企业级应用的核心需求,PostgreSQL提供了丰富的复制和故障切换方案来满足不同场景的可用性要求。文章将系统讲解主从复制架构、流复制配置、逻辑复制原理、故障切换机制、高可用工具(Patroni、repmgr)、读写分离策略以及分布式数据库架构等内容。通过本文学习,读者将能够设计和构建高可用的PostgreSQL数据库集群,确保系统在硬件故障、软件故障或网络分区等情况下保持持续可用。

学习目标

  • 理解数据库复制的基本原理和架构类型
  • 掌握流复制(Streaming Replication)的配置方法
  • 深入理解逻辑复制的工作原理和应用场景
  • 掌握故障切换和自动故障转移机制
  • 了解Patroni、repmgr等高可用工具的使用方法
  • 理解读写分离策略和负载均衡实现
  • 掌握同步复制与异步复制的区别及选择
  • 了解分布式数据库架构的设计考虑

一、复制架构概述

1.1 复制的定义与目的

数据库复制是指将数据从一个数据库服务器(主服务器/Primary)复制到一个或多个数据库服务器(从服务器/Standby)的技术。复制技术是构建高可用数据库架构的基础。

复制的核心目的包括:

  • 高可用性:主服务器故障时,从服务器可以接管服务
  • 负载均衡:读操作可以分散到多个从服务器
  • 数据备份:从服务器作为实时备份,提高数据安全性
  • 灾难恢复:远程从服务器提供异地容灾能力
  • 报表分析:在从服务器上执行分析查询,不影响主服务器性能

1.2 复制架构类型

PostgreSQL支持多种复制架构,每种架构适用于不同的场景需求。

主从复制(Master-Slave): 最简单的复制架构,一个主服务器负责写操作,多个从服务器复制主服务器的数据。从服务器只读,适合读多写少的场景。

级联复制(Cascading Replication): 从服务器可以作为其他从服务器的主服务器,形成复制链。这种架构可以减少主服务器的复制负载,适合大规模部署。

多主复制(Multi-Master): 多个主服务器都可以处理写操作,写操作在所有主服务器之间同步复制。这种架构提供最高的可用性,但实现复杂,需要处理冲突解决。

1.3 复制方式对比

复制方式传输内容延迟配置复杂度适用场景
流复制(物理)WAL记录极低简单通用高可用
逻辑复制数据变更中等选择性复制、跨版本
文件系统级复制数据块极低简单紧急备份
触发器复制应用逻辑复杂特殊业务需求

二、流复制(Streaming Replication)

2.1 流复制原理

流复制是PostgreSQL原生支持的物理复制方式,主服务器将WAL(Write-Ahead Log)记录流式传输到从服务器,从服务器应用这些WAL记录来复制数据变化。

流复制的核心组件:

  • 主服务器(Primary):处理写操作,生成WAL记录
  • 从服务器(Standby):接收并应用WAL,持续恢复数据
  • WAL发送进程(walsender):主服务器进程,负责发送WAL
  • WAL接收进程(walreceiver):从服务器进程,负责接收WAL

2.2 流复制配置

主服务器配置(postgresql.conf)

# WAL设置
wal_level = replica                # 支持复制
wal_keep_size = 1GB               # 保留足够的WAL
max_wal_senders = 10              # 最大WAL发送进程数
max_replication_slots = 10        # 最大复制槽数
 
# 复制槽(防止WAL过早删除)
# 如果使用复制槽,主服务器会为每个从服务器保留WAL
 
# 连接和认证
listen_addresses = '*'            # 监听所有地址

主服务器配置(pg_hba.conf)

# 允许复制连接
host    replication    replicator    192.168.1.0/24    scram-sha-256

从服务器配置

# 创建复制用户
主服务器上执行:
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'secure_password';
 
# 从服务器基础备份
pg_basebackup -h primary_host -D /data/postgresql -U replicator -P
 
# 从服务器配置(postgresql.conf)
hot_standby = on                  # 允许只读查询
max_standby_streaming_delay = 30s
max_standby_archive_delay = 30s
 
# 从服务器配置(standby.signal)
touch standby.signal
 
# 连接信息(postgresql.auto.conf)
primary_conninfo = 'host=primary_host port=5432 user=replicator password=secure_password'

2.3 流复制监控

-- 在主服务器上查询复制状态
SELECT
    client_addr,
    state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    sync_state,
    sync_priority
FROM pg_stat_replication;
 
-- 查看复制槽
SELECT
    slot_name,
    slot_type,
    active,
    restart_lsn,
    slot_status
FROM pg_replication_slots;
 
-- 在从服务器上查询延迟
SELECT
    now() - pg_last_xact_replay_timestamp() AS replication_lag;
 
-- 查看从服务器状态
SELECT
    pg_is_in_recovery(),
    pg_last_xact_replay_timestamp(),
    pg_last_wal_receive_lsn(),
    pg_last_wal_replay_lsn();

2.4 流复制架构图

flowchart TD
    subgraph Primary["主服务器 (Primary)"]
        A1[应用写操作]
        A2[PostgreSQL服务]
        A3[WAL生成<br/>写入wal_buffers]
        A4[WAL磁盘写入<br/>WAL files]
        A5[WAL Sender进程<br/>(walsender)]
    end

    subgraph Standby1["从服务器1 (Standby)"]
        B1[WAL Receiver进程<br/>(walreceiver)]
        B2[WAL接收<br/>Apply to disk]
        B3[持续恢复<br/>Recovery process]
        B4[只读查询<br/>Hot Standby]
    end

    subgraph Standby2["从服务器2 (Standby)"]
        C1[WAL Receiver进程<br/>(walreceiver)]
        C2[WAL接收<br/>Apply to disk]
        C3[持续恢复<br/>Recovery process]
        C4[只读查询<br/>Hot Standby]
    end

    A1 --> A2
    A2 --> A3
    A3 --> A4
    A4 --> A5

    A5 -->|TCP/IP<br/>Replication Protocol| B1
    A5 -->|TCP/IP<br/>Replication Protocol| C1

    B1 --> B2
    B2 --> B3
    B3 --> B4

    C1 --> C2
    C2 --> C3
    C3 --> C4

    B4 -->|读操作| B5[应用]
    C4 -->|读操作| C5[应用]

    style A1 fill:#f9f,stroke:#333
    style B4 fill:#bbf,stroke:#333
    style C4 fill:#bbf,stroke:#333

图表说明:此架构图展示了PostgreSQL流复制的完整数据流。主服务器处理应用写操作,生成WAL记录。WAL Sender进程将WAL通过TCP/IP连接发送到从服务器的WAL Receiver进程。从服务器接收WAL后,应用到磁盘,并通过恢复进程持续更新数据。从服务器可以同时处理只读查询,实现读写分离。图中展示了两个从服务器的典型配置,实际部署中可以有多个从服务器。这种架构提供了高可用性和读扩展能力。


三、同步与异步复制

3.1 同步复制

同步复制要求主服务器在提交事务前,确保至少一个从服务器已经接收并写入了WAL。这确保了在主服务器故障时,已提交的数据不会丢失。

-- 主服务器设置同步复制
ALTER SYSTEM SET synchronous_commit = on;           -- 启用同步提交
ALTER SYSTEM SET synchronous_standby_names = 'standby1';  -- 指定同步从服务器
 
-- 多个同步从服务器
ALTER SYSTEM SET synchronous_standby_names = '2 (standby1, standby2)';
 
-- 任意一个从服务器同步即可
ALTER SYSTEM SET synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)';
 
-- 重载配置
SELECT pg_reload_conf();

3.2 异步复制

异步复制是PostgreSQL的默认模式,主服务器提交事务后立即返回,不需要等待从服务器确认。这提供了最佳的性能,但在主服务器故障时可能丢失最近提交的事务。

-- 异步复制配置(默认)
synchronous_commit = off              -- 完全异步(最快但可能丢失数据)
synchronous_commit = local           -- 本地写入即成功
synchronous_commit = remote_write    -- 等待远程写入
synchronous_commit = on              -- 等待远程写入并持久化(同步)

3.3 复制模式选择决策图

flowchart TD
    A[复制模式选择] --> B{数据一致性要求}
    B --> C[强一致性<br/>零数据丢失]
    B --> D[最终一致性<br/>允许少量丢失]
    B --> E[性能优先<br/>允许可能丢失]

    C --> F[同步复制<br/>synchronous_commit=on]

    F --> F1[特点<br/>• 主服务器等待从服务器<br/>• 事务延迟增加<br/>• 零数据丢失]

    F --> F2[适用场景<br/>• 金融交易<br/>• 订单处理<br/>• 库存扣减]

    D --> G[远程写入复制<br/>synchronous_commit=remote_write]

    G --> G1[特点<br/>• 等待WAL写入从服务器<br/>• 不等待fsync<br/>• 低延迟]

    G --> G2[适用场景<br/>• 大多数生产环境<br/>• 平衡性能和安全性]

    E --> H[异步复制<br/>synchronous_commit=off]

    H --> H1[特点<br/>• 主服务器不等待<br/>• 最低延迟<br/>• 可能丢失数据]

    H --> H2[适用场景<br/>• 批量处理<br/>• 数据分析<br/>• 可重建数据]

    F1 --> I[权衡考虑<br/>数据安全性 vs 性能]
    G1 --> I
    H1 --> I

图表说明:此决策图展示了如何根据数据一致性要求选择合适的复制模式。同步复制提供最强的一致性保证,主服务器等待从服务器确认后才提交事务,确保零数据丢失,但会增加事务延迟。异步复制提供最佳性能,主服务器不等待从服务器,但可能在主服务器故障时丢失最近提交的数据。远程写入复制是折中方案,等待WAL写入从服务器但不等待fsync,在性能和安全性之间取得平衡。选择时需要根据业务场景权衡数据安全性和性能需求。


四、逻辑复制

4.1 逻辑复制原理

逻辑复制是PostgreSQL 10引入的基于数据变更的复制方式,不同于物理复制复制WAL记录,逻辑复制复制数据变更的逻辑操作(INSERT、UPDATE、DELETE)。

逻辑复制的特点:

  • 表级别选择性复制:可以只复制特定的表
  • 跨版本兼容:支持不同PostgreSQL版本之间的复制
  • 数据过滤:可以发布/订阅特定的行或列
  • 灵活性:可以在复制链中转换数据
  • 性能开销:比物理复制有更高的CPU开销

4.2 逻辑复制配置

发布端配置

-- postgresql.conf设置
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
 
-- 创建发布
CREATE PUBLICATION my_publication FOR TABLE products, orders;
 
-- 发布所有表
CREATE PUBLICATION all_tables FOR ALL TABLES;
 
-- 发布特定表的特定行
CREATE PUBLICATION filtered_publication
FOR TABLE users
WHERE (active = true);
 
-- 查看发布
SELECT * FROM pg_publication;
SELECT * FROM pg_publication_tables;

订阅端配置

-- 创建订阅
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=primary_host dbname=mydb user=replicator'
PUBLICATION my_publication;
 
-- 创建只复制特定表的订阅
CREATE SUBSCRIPTION products_subscription
CONNECTION 'host=primary_host dbname=mydb user=replicator'
PUBLICATION products_publication
WITH (create_slot = false);  -- 使用现有复制槽
 
-- 查看订阅状态
SELECT * FROM pg_stat_subscription;

4.3 逻辑复制监控

-- 发布端监控
SELECT
    pubname,
    CASE WHEN puballtables THEN 'ALL TABLES'
         ELSE array_agg(tablename::text)
    END AS tables
FROM pg_publication p
LEFT JOIN pg_publication_tables pt ON p.oid = pt.pubid
GROUP BY pubname, puballtables;
 
-- 订阅端监控
SELECT
    subname,
    subenabled,
    subslotname,
    substrings,
    subpublications
FROM pg_subscription;
 
-- 复制延迟
SELECT
    subname,
    pg_catalog.pg_logical_slot_get_binary_changes(
        slot_name,
        NULL,
        NULL
    ) AS changes;

4.4 物理复制与逻辑复制对比

特性物理复制(流复制)逻辑复制
复制粒度整个数据库实例表级别
WAL级别replica/minimumlogical
网络开销低(二进制WAL)高(逻辑解码)
CPU开销高(逻辑解码)
选择性可以选择表/行/列
跨版本困难支持
故障切换简单需要重新配置
典型用途高可用、灾难恢复数据集成、多主

五、故障切换与自动故障转移

5.1 故障切换场景

故障切换是指主服务器发生故障时,将一个从服务器提升为新的主服务器的过程。故障切换分为手动和自动两种方式。

需要故障切换的场景

  • 主服务器硬件故障
  • 主服务器软件故障或崩溃
  • 网络分区导致主服务器不可访问
  • 计划内维护(升级、配置更改)

5.2 手动故障切换

# 在从服务器上执行故障切换
 
# 1. 停止从服务器的复制
-- 从服务器上
SELECT pg_promote();  -- PostgreSQL 11+
-- 或者
pg_ctl promote -D /data/postgresql
 
# 2. 更新应用连接配置
# 将应用连接字符串指向新主服务器
 
# 3. 将其他从服务器重新指向新主服务器
-- 其他从服务器上
ALTER SYSTEM SET primary_conninfo = 'host=new_primary_host ...';
pg_ctl restart -D /data/postgresql
 
# 4. (可选)恢复旧主服务器作为从服务器
-- 旧主服务器上
rm -f standby.signal
ALTER SYSTEM SET primary_conninfo = 'host=new_primary_host ...';
pg_ctl restart -D /data/postgresql

5.3 自动故障转移工具

Patroni: Patroni是基于etcd或Consul的PostgreSQL高可用解决方案,提供自动故障转移、配置管理和监控功能。

# Patroni配置示例(YAML)
scope: postgres-cluster
name: postgresql-0
 
restapi:
  listen: 0.0.0.0:8008
  connect_address: 192.168.1.10:8008
 
etcd:
  hosts:
    - 192.168.1.20:2379
    - 192.168.1.21:2379
    - 192.168.1.22:2379
 
bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
  postgresql:
    use_pg_rewind: true
    remove_data_directory_on_rewind_failure: true
    use_slots: true
 
postgresql:
  listen: 0.0.0.0:5432
  connect_address: 192.168.1.10:5432
  data_dir: /var/lib/postgresql/data
  bin_dir: /usr/lib/postgresql/14/bin
  authentication:
    replication:
      username: replicator
      password: rep_pass
    superuser:
      username: postgres
      password: super_pass
  parameters:
    max_connections: 200
    shared_buffers: 4GB
    wal_level: replica
    hot_standby: on
    max_replication_slots: 10
    max_wal_senders: 10

repmgr: repmgr是专门用于管理PostgreSQL复制和故障切换的工具。

# repmgr配置
node_id=1
node_name=node1
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'
 
# 注册主服务器
repmgr primary register
 
# 注册从服务器
repmgr standby clone --host=node1
repmgr standby register
 
# 手动故障切换
repmgr standby switchover --siblings-follow
 
# 查看集群状态
repmgr cluster show

5.4 故障切换流程图

sequenceDiagram
    autonumber
    participant App as 应用
    participant HA as 高可用工具<br/>(Patroni/repmgr)
    participant Primary as 主服务器
    participant Standby1 as 从服务器1
    participant Standby2 as 从服务器2
    participant DCS as 分布式存储<br/>(etcd/Consul)

    Note over App,DCS: 正常运行状态

    App->>Primary: 1. 写操作
    Primary->>Standby1: 2. 复制WAL
    Primary->>Standby2: 3. 复制WAL
    HA->>DCS: 4. 定期心跳<br/>I am alive

    Note over App,DCS: 故障发生

    Primary--X: 5. 主服务器故障
    DCS--X: 6. 心跳超时
    HA->>DCS: 7. 检测到故障<br/>开始选举

    Standby1->>DCS: 8. 竞选主服务器
    Standby2->>DCS: 9. 竞选主服务器

    DCS->>Standby1: 10. 选举成功<br/>提升为主
    DCS->>Standby2: 11. 成为从<br/>跟随新主

    Standby1->>Standby1: 12. pg_promote()
    Standby1->>Standby2: 13. 开始复制

    HA->>App: 14. 更新连接配置<br/>指向新主

    App->>Standby1: 15. 写操作<br/>继续业务

图表说明:此序列图展示了自动故障转移的完整流程。正常运行时,应用向主服务器写操作,主服务器复制WAL到从服务器,高可用工具定期向分布式存储发送心跳。主服务器故障后,心跳超时触发故障检测,高可用工具在从服务器之间选举新主服务器。选举成功的从服务器被提升为主服务器,其他从服务器重新指向新主。应用连接配置更新,业务继续执行。整个过程自动完成,最大程度减少服务中断时间。


六、读写分离与负载均衡

6.1 读写分离原理

读写分离是指将读操作和写操作路由到不同的数据库服务器。写操作发送到主服务器,读操作分散到多个从服务器。这种架构可以显著提高系统的读处理能力。

读写分离的实现方式:

  • 应用层实现:应用程序直接维护主从连接,根据操作类型选择连接
  • 中间件代理:使用Pgpool-II、ProxySQL等代理自动路由
  • DNS轮询:为读操作配置多个从服务器的DNS记录

6.2 Pgpool-II配置

Pgpool-II是PostgreSQL的中间件,提供连接池、负载均衡、查询缓存和故障检测等功能。

# pgpool.conf配置
 
# 连接池设置
listen_addresses = '*'
port = 9999
socket_dir = '/var/run/postgresql'
 
# 后端数据库列表
backend_hostname0 = 'primary_host'
backend_port0 = 5432
backend_weight0 = 1
backend_data_directory0 = '/data'
backend_flag0 = 'ALLOW_TO_FAILOVER'
 
backend_hostname1 = 'standby1_host'
backend_port1 = 5432
backend_weight1 = 1
backend_flag1 = 'ALLOW_TO_FAILOVER'
 
# 负载均衡
load_balance_mode = on
replication_mode = replicate_select_to_all     -- 复制SELECT到所有节点
master_slave_mode = on                         -- 启用主从模式
master_slave_sub_mode = 'stream'               -- 流复制模式
 
# 健康检查
health_check_period = 5
health_check_timeout = 20
health_check_user = 'postgres'
health_check_password = 'password'
health_check_database = 'postgres'
 
# 故障切换
backend_error_message = off
detach_false_primary = off
search_primary_node_timeout = 300
 
# 连接池
connection_cache = on
max_pool = 4

6.3 读写分离架构图

flowchart LR
    subgraph Apps["应用层"]
        A1[Web服务器1]
        A2[Web服务器2]
        A3[API服务器]
    end

    subgraph Proxy["负载均衡层<br/>(Pgpool-II/HAProxy)"]
        B1[连接池管理]
        B2[读写分离<br/>路由规则]
        B3[健康检查<br/>故障检测]
    end

    subgraph Primary["主服务器<br/>(读写)"]
        C1[写操作]
        C2[数据持久化]
        C3[WAL生成]
    end

    subgraph Standby["从服务器集群<br/>(只读)"]
        D1[从服务器1<br/>只读查询]
        D2[从服务器2<br/>只读查询]
        D3[从服务器3<br/>只读查询]
    end

    A1 -->|读写请求| B1
    A2 -->|读写请求| B1
    A3 -->|读写请求| B1

    B2 -->|写操作| C1
    B2 -->|读操作<br/>负载均衡| D1
    B2 -->|读操作<br/>负载均衡| D2
    B2 -->|读操作<br/>负载均衡| D3

    C3 -->|WAL复制| D1
    C3 -->|WAL复制| D2
    C3 -->|WAL复制| D3

    B3 -.->|健康检查| C1
    B3 -.->|健康检查| D1
    B3 -.->|健康检查| D2
    B3 -.->|健康检查| D3

    style C1 fill:#f9f,stroke:#333
    style D1 fill:#bbf,stroke:#333
    style D2 fill:#bbf,stroke:#333
    style D3 fill:#bbf,stroke:#333

图表说明:此架构图展示了读写分离的典型部署。应用层通过负载均衡器(如Pgpool-II)访问数据库,负载均衡器根据请求类型进行路由:写操作发送到主服务器,读操作通过负载均衡算法分散到多个从服务器。主服务器将数据变更通过WAL复制到所有从服务器,保证数据一致性。负载均衡器还负责健康检查和故障检测,当某个数据库服务器故障时自动将其从服务列表中移除。这种架构大大提高了系统的读处理能力和可用性。


七、高可用架构设计

7.1 经典高可用架构

基本主从架构: 最简单的HA架构,一个主服务器、一个或多个从服务器。主服务器故障时手动或自动提升从服务器。

主从 + 仲裁架构: 使用仲裁节点(如Patroni + etcd)实现自动故障转移。etcd集群存储集群状态,当主服务器故障时,通过etcd选举新主服务器。

多数据中心架构: 在不同数据中心部署PostgreSQL集群,实现异地容灾。本地数据中心处理正常业务,远程数据中心作为灾难恢复备份。

7.2 分布式数据库架构

对于超大规模数据,可以考虑分布式数据库架构,将数据分片(Sharding)到多个PostgreSQL实例。

水平分片: 根据分片键将数据分布到多个数据库实例。例如,按用户ID取模,将不同用户的数据存储在不同实例上。

垂直分片: 将不同的表或业务模块分布到不同的数据库实例。例如,用户表在一个实例,订单表在另一个实例。

7.3 高可用架构设计图

flowchart TB
    subgraph DC1["数据中心1 (主数据中心)"]
        subgraph Cluster1["PostgreSQL集群1"]
            P1[主服务器<br/>Node1]
            S1[从服务器<br/>Node2]
            S2[从服务器<br/>Node3]
        end

        subgraph ETCD1["etcd集群"]
            E1[etcd-1]
            E2[etcd-2]
            E3[etcd-3]
        end

        subgraph App1["应用集群"]
            A1[应用1]
            A2[应用2]
        end

        subgraph LB1["负载均衡"]
            L1[Pgpool-II]
        end
    end

    subgraph DC2["数据中心2 (容灾中心)"]
        subgraph Cluster2["PostgreSQL集群2"]
            P2[主服务器<br/>Node4]
            S3[从服务器<br/>Node5]
            S4[从服务器<br/>Node6]
        end

        subgraph ETCD2["etcd集群"]
            E4[etcd-4]
            E5[etcd-5]
            E6[etcd-6]
        end
    end

    A1 --> L1
    A2 --> L1
    L1 --> P1
    L1 --> S1
    L1 --> S2

    P1 -.->|跨DC复制| P2
    S1 -.->|异步复制| S3
    S2 -.->|异步复制| S4

    E1 -.->|etcd集群同步| E4
    E2 -.->|etcd集群同步| E5
    E3 -.->|etcd集群同步| E6

    style P1 fill:#f9f,stroke:#333
    style P2 fill:#f9f,stroke:#333
    style S1 fill:#bbf,stroke:#333
    style S2 fill:#bbf,stroke:#333
    style S3 fill:#bbf,stroke:#333
    style S4 fill:#bbf,stroke:#333

图表说明:此架构图展示了一个完整的多数据中心高可用部署方案。主数据中心包含完整的PostgreSQL集群(一个主服务器和两个从服务器)和应用集群,通过负载均衡器提供服务。容灾中心部署了独立的PostgreSQL集群,通过跨数据中心的异步复制与主数据中心同步。两个数据中心各自维护etcd集群,用于故障检测和自动故障转移。这种架构提供了最高级别的可用性和灾难恢复能力,即使整个主数据中心故障,容灾中心也能接管服务。


八、高可用架构知识总结

复制方案对比表

方案复制延迟数据丢失风险复杂度适用场景
异步流复制毫秒级少量通用高可用
同步流复制较高关键业务
逻辑复制较低取决于配置选择性复制、数据集成
级联复制毫秒级少量大规模部署
多主复制多地域写入

高可用工具对比

工具类型自动故障转移配置复杂度特色功能
PatroniPython中等支持多种DCS、自动化程度高
repmgrPython/Bash可选专注于复制管理、配置简单
Pgpool-IIC中间件中等连接池、负载均衡、查询缓存
StolonGo原生云原生支持

九、常见问题解答

Q1:流复制和逻辑复制如何选择?

:流复制(物理复制)是大多数场景的首选,提供低延迟、低开销的完整数据库实例复制,适合高可用和灾难恢复。

逻辑复制适合需要选择性复制(只复制特定表)、跨版本复制或数据转换的场景。

如果需求是简单的主从复制和高可用,选择流复制。如果需要只复制部分表、需要在复制链中过滤或转换数据,或者需要在不同PostgreSQL版本之间复制,选择逻辑复制。对于复杂场景,可以同时使用两种复制方式。


Q2:如何避免脑裂问题?

:脑裂是指网络分区导致多个节点认为自己是主服务器的情况。

避免脑裂的方法包括:1)使用仲裁机制(如etcd、Consul),要求获得多数选票才能成为主服务器;2)配置fencing机制,通过STONITH(Shoot The Other Node In The Head)确保故障节点无法访问共享资源;3)使用奇数个节点的集群,确保总是有明确的多数派;4)使用网络隔离检测,避免因短暂网络抖动触发故障转移;5)配置合适的超时和重试参数,给网络恢复留出时间。

Patroni等成熟的高可用工具已经内置了这些机制。


Q3:读写分离的读一致性如何保证?

:读写分离的读一致性是主要挑战。

从服务器由于复制延迟,可能读到旧数据。保证读一致性的方法包括:1)对一致性要求高的读操作发送到主服务器;2)使用同步复制确保从服务器实时更新(但会增加延迟);3)在应用层实现会话粘性,同一会话的读操作发送到同一从服务器;4)监控复制延迟,当延迟超过阈值时将读操作切换到主服务器;5)对于需要最新数据的场景,使用显式的读主服务器策略。

实践中,大多数业务可以容忍毫秒到秒级的复制延迟,只需要对关键操作(如库存扣减后立即查询)读主服务器。


Q4:如何监控复制延迟?

:PostgreSQL提供了多种监控复制延迟的方法。

1)pg_stat_replication视图显示每个从服务器的复制状态,包括sent_lsn、write_lsn、flush_lsn、replay_lsn;2)pg_last_xact_replay_timestamp()函数返回从服务器最后重放的事务时间;3)使用now() - pg_last_xact_replay_timestamp()计算以时间为单位的延迟;4)使用pg_stat_wal_receiver查看WAL接收状态;5)使用外部监控工具(如Nagios、Prometheus)定期查询这些视图并设置告警阈值。

监控复制延迟时需要注意区分传输延迟、写入延迟和应用延迟,这三者分别表示WAL传输到从服务器、写入从服务器磁盘、应用到从服务器数据的时间差。


Q5:多数据中心架构如何设计?

:多数据中心架构需要考虑延迟、带宽和故障隔离。

典型设计包括:1)主数据中心部署活跃的PostgreSQL集群处理业务,容灾数据中心部署热备集群;2)数据中心之间使用异步复制(同步复制会因延迟严重影响性能);3)每个数据中心有独立的etcd集群用于本地故障检测,etcd集群之间同步状态;4)应用部署在多个数据中心,优先访问本地数据中心,故障时切换到远程数据中心;5)使用全局负载均衡(GSLB)或DNS根据用户位置和数据中心健康状态路由流量。

关键决策是数据分布模式(活跃-活跃还是活跃-备用),活跃-活跃提供更好的性能和资源利用,但数据冲突解决更复杂。


十、总结

本文作为PostgreSQL数据库技术系列的最终篇,全面介绍了数据库的高可用架构和复制技术。流复制提供了简单高效的物理复制方案,是构建高可用架构的基础。逻辑复制支持表级别的选择性复制和跨版本复制,为复杂场景提供了灵活的解决方案。同步与异步复制的权衡是数据安全性和性能之间的经典选择。自动故障转移工具(Patroni、repmgr)大大简化了高可用架构的运维复杂度。读写分离架构通过分散读操作到多个从服务器,显著提高了系统的读处理能力。多数据中心架构提供了企业级的灾难恢复能力。

至此,PostgreSQL数据库技术系列八篇文章全部完成。从第一篇的数据库入门和SQL基础,到第二篇的高级查询,到第三篇的数据库设计,到第四篇的索引优化,到第五篇的数据类型,到第六篇的事务并发,到第七篇的运维管理,到本篇的高可用架构,完整覆盖了PostgreSQL从入门到精通的学习路径。读者通过本系列文章的学习,应该已经建立了完整的PostgreSQL知识体系,能够胜任从数据库开发到运维管理的各种工作。

希望本系列文章能够帮助读者深入理解PostgreSQL数据库技术,在实际工作中发挥应有的作用。


本文作为PostgreSQL数据库技术系列的第八篇(完结篇),专注于高可用架构与复制技术的深入讲解。至此,整个系列八篇文章全部完成,为读者提供了从入门到精通的完整PostgreSQL学习路径。