PostgreSQL高可用实战:流复制配置与Patroni自动故障转移

PostgreSQL流复制(Streaming Replication)通过实时传输WAL日志实现主从同步,是构建数据库高可用架构的基础。Patroni作为开源的PostgreSQL高可用管理工具,基于etcd实现自动故障检测和主节点切换,结合HAProxy可实现无感知的数据库故障转移。以下是从单机搭建到高可用集群的完整实战配置。

PostgreSQL流复制原理

PostgreSQL流复制的核心是WAL(Write-Ahead Logging)机制。主节点将事务日志写入WAL文件后,通过TCP连接实时发送给备节点,备节点接收WAL日志并回放,实现数据同步。根据同步模式不同,分为同步复制和异步复制:

异步复制(async)  - 主节点写入WAL后立即返回,不等备节点确认
                     优点:低延迟  缺点:主节点宕机可能丢失少量数据

同步复制(sync)   - 主节点等待至少一个备节点确认收到WAL后才返回
                     优点:零数据丢失  缺点:备节点故障时主节点阻塞

生产环境通常采用”一主一同步备+一异步备”的架构,平衡数据安全和可用性。

主节点配置

修改postgresql.conf:

# postgresql.conf
listen_addresses = '*'
port = 5432

# WAL配置
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1024       # 保留1GB WAL
hot_standby = on

# 同步复制配置
synchronous_standby_names = 'FIRST 1 (sync_standby)'

# 归档配置
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'

# 连接配置
max_connections = 200
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 64MB
maintenance_work_mem = 512MB

创建复制用户:

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'StrongRepPass2026';

修改pg_hba.conf允许备节点连接:

# pg_hba.conf
# TYPE  DATABASE    USER        ADDRESS          METHOD
host    replication  replicator  192.168.1.0/24   scram-sha-256
host    all          all         192.168.1.0/24   scram-sha-256

备节点搭建

使用pg_basebackup从主节点创建备节点:

# 停止备节点PostgreSQL
systemctl stop postgresql

# 清空备节点数据目录
rm -rf /var/lib/postgresql/15/main/*

# 从主节点拉取基础备份
pg_basebackup \
    -h 192.168.1.10 \
    -U replicator \
    -D /var/lib/postgresql/15/main \
    -Fp \
    -Xs \
    -P \
    -R    # 自动创建standby.signal和primary.conninfo

# 验证standby.signal文件
ls -la /var/lib/postgresql/15/main/standby.signal

# 检查primary_conninfo配置
cat /var/lib/postgresql/15/main/postgresql.auto.conf
# 应包含:
# primary_conninfo = 'user=replicator password=... host=192.168.1.10 port=5432 sslmode=prefer'

# 启动备节点
systemctl start postgresql

验证复制状态:

-- 主节点执行:查看复制状态
SELECT 
    pid,
    usename,
    application_name,
    client_addr,
    state,
    sync_state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    write_lag,
    flush_lag,
    replay_lag
FROM pg_stat_replication;

-- 备节点执行:确认处于恢复模式
SELECT pg_is_in_recovery();  -- 返回true

-- 备节点执行:查看接收和回放的WAL位置
SELECT 
    pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
    pg_last_wal_receive_lsn() AS receive_lsn,
    pg_last_wal_replay_lsn() AS replay_lsn,
    pg_last_xact_replay_timestamp() AS last_replay_time;

Patroni自动故障转移配置

Patroni依赖分布式配置存储(etcd)管理集群状态。以etcd为例,在所有节点安装Patroni:

pip3 install patroni[etcd]

各节点Patroni配置 /etc/patroni/patroni.yml:

scope: pg-cluster
namespace: /service/
name: node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 192.168.1.10:8008

etcd:
  hosts: 192.168.1.10:2379,192.168.1.11:2379,192.168.1.12:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576  # 1MB
    synchronous_mode: true
    synchronous_mode_strict: false
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_level: replica
        hot_standby: on
        max_wal_senders: 10
        wal_keep_size: 1024

  initdb:
    - encoding: UTF8
    - data-checksums
    - locale: C

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 192.168.1.10:5432
  data_dir: /var/lib/postgresql/15/main
  bin_dir: /usr/lib/postgresql/15/bin
  authentication:
    superuser:
      username: postgres
      password: SuperSecretPass2026
    replication:
      username: replicator
      password: StrongRepPass2026
    rewind:
      username: rewinder
      password: RewindPass2026
  parameters:
    shared_buffers: 4GB
    effective_cache_size: 12GB
    max_connections: 200

启动Patroni集群:

# 在三个节点上分别执行
systemctl start patroni
systemctl enable patroni

# 查看集群状态
patronictl -c /etc/patroni/patroni.yml list

# 输出示例:
# + Cluster: pg-cluster ---+---------+----+-----------+
# | Member | Host        | Role    | State     | TL | Lag in MB |
# +--------+-------------+---------+-----------+----+-----------+
# | node1  | 192.168.1.10| Leader  | running   |  1 |           |
# | node2  | 192.168.1.11| Replica | streaming |  1 |         0 |
# | node3  | 192.168.1.12| Replica | streaming |  1 |         0 |
# +--------+-------------+---------+-----------+----+-----------+

手动switchover与自动failover

计划内切换(switchover):将主节点切换到指定备节点,不丢数据:

# 手动切换主节点到node2
patronictl switchover -c /etc/patroni/patroni.yml

# 交互式选择
# Primary [node1]:
# Candidate []: node2
# Are you sure you want to switch leaders? [y/N]: y

自动故障转移(failover):主节点宕机后Patroni自动选举新主:

# 模拟主节点故障
systemctl stop patroni  # 在node1上执行

# 等待TTL超时(30秒)后,Patroni自动选举node2为新主
patronictl -c /etc/patroni/patroni.yml list

# node1恢复后自动加入集群作为备节点
systemctl start patroni

自动故障转移的选举逻辑:Patroni根据WAL LSN位置选择数据最新的备节点作为新主。如果所有备节点的LSN都落后于主节点最后的LSN,且maximum_lag_on_failover配置不满足,则拒绝故障转移以避免数据丢失。

HAProxy读写分离配置

# haproxy.cfg
frontend pg_write_frontend
    bind *:5432
    default_backend pg_write_backend

frontend pg_read_frontend
    bind *:5433
    default_backend pg_read_backend

backend pg_write_backend
    mode tcp
    option tcp-check
    server node1 192.168.1.10:5432 check port 8008
    server node2 192.168.1.11:5432 check port 8008
    server node3 192.168.1.12:5432 check port 8008

backend pg_read_backend
    mode tcp
    balance roundrobin
    server node1 192.168.1.10:5432 check
    server node2 192.168.1.11:5432 check
    server node3 192.168.1.12:5432 check

Patroni的REST API端点(8008端口)提供健康检查接口:

# 检查是否为主节点(返回200)
curl -s http://192.168.1.10:8008/primary -o /dev/null -w "%{http_code}"

# 检查是否为可读备节点(返回200)
curl -s http://192.168.1.10:8008/replica -o /dev/null -w "%{http_code}"

# 获取集群状态JSON
curl -s http://192.168.1.10:8008/cluster | python3 -m json.tool

pg_rewind修复脑裂后的数据同步

脑裂场景:网络分区导致旧主节点继续接受写入,恢复后其WAL timeline与新主分叉。需要使用pg_rewind回退到分叉点后重新同步:

# 在旧主节点(node1)上执行
systemctl stop postgresql

# pg_rewind回退到新主的分叉点
pg_rewind \
    --target-data=/var/lib/postgresql/15/main \
    --source-server="host=192.168.1.11 user=postgres password=SuperSecretPass2026"

# 创建standby.signal
touch /var/lib/postgresql/15/main/standby.signal

# 启动Patroni,自动以备节点身份加入集群
systemctl start patroni

Patroni配置中use_pg_rewind: true允许自动执行pg_rewind,无需人工干预。pg_rewind通过比较两个节点的WAL历史找到最后共同点,将旧主的数据文件回退到该点,然后从新主同步差异部分。整个过程比重新pg_basebackup快得多,特别适合大数据库的脑裂恢复。

监控与告警配置

通过Patroni的Prometheus exporter采集集群指标:

# prometheus.yml
scrape_configs:
  - job_name: 'patroni'
    static_configs:
      - targets:
        - 192.168.1.10:8008
        - 192.168.1.11:8008
        - 192.168.1.12:8008
    metrics_path: /metrics

关键监控指标:

patroni_cluster_unlocked       # 集群是否处于无主状态(应为0)
patroni_postgres_running         # PostgreSQL是否运行(应为1)
patroni_postgres_role            # 节点角色(1=master, 0=replica)
patroni_postgres_xlog_location   # WAL位置(用于计算复制延迟)
patroni_dcs_last_seen            # 最后一次与DCS通信时间

告警规则示例:

groups:
  - name: patroni
    rules:
      - alert: PatroniClusterUnlocked
        expr: patroni_cluster_unlocked == 1
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PostgreSQL集群无主节点"
          
      - alert: PatroniReplicationLag
        expr: max(patroni_postgres_xlog_location) - min(patroni_postgres_xlog_location) > 10485760
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "复制延迟超过10MB"

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-gao-ke-yong-shi-zhan-liu-fu-zhi-pei-zhi-yu/

(0)
小编小编
上一篇 10小时前
下一篇 10小时前

相关推荐