数据库运维5 min read

PostgreSQL高可用架构实战:从流复制到Patroni

PostgreSQL高可用架构实战:从流复制到Patroni

前言

PostgreSQL凭借其强大的功能、出色的扩展性和活跃的社区,在企业级应用中越来越受欢迎。然而,要保证数据库7×24小时不间断服务,仅仅部署一个单机实例是远远不够的。本文将系统性地介绍PostgreSQL高可用架构的搭建与运维实践。

一、PostgreSQL复制原理

1.1 WAL(Write-Ahead Logging)

事务流程:
  Client → WAL Buffer → WAL File → 磁盘
                ↓
          Shared Buffer → 磁盘 (Checkpoint)
                ↓
          WAL Sender → Standby (流复制)

WAL是PostgreSQL复制的基础,记录了所有对数据库的修改操作。

1.2 流复制架构

         ┌─────────────────┐
         │    Primary       │
         │  (读写)          │
         └────────┬─────────┘
                  │ WAL Stream (streaming)
         ┌────────┼─────────┐
         ▼        ▼         ▼
    ┌────────┐┌────────┐┌────────┐
    │Standby ││Standby ││Standby │
    │ (只读) ││ (只读) ││ (只读) │
    └────────┘└────────┘└────────┘

二、搭建流复制主备集群

2.1 Primary配置

# postgresql.conf
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1024        # MB
hot_standby = on
archive_mode = on
archive_command = 'cp %p /data/pg_archive/%f'

# pg_hba.conf
host replication repl_user 192.168.1.0/24 md5

2.2 创建复制用户

CREATE ROLE repl_user WITH LOGIN REPLICATION PASSWORD 'repl_pass';

2.3 搭建Standby

# 从Primary做基础备份
pg_basebackup -h 192.168.1.10 -U repl_user \
    -D /var/lib/pgsql/14/data -Fp -Xs -P -R

# Standby自动生成的配置
# standby.signal (空文件,表示这是standby)
# postgresql.auto.conf
primary_conninfo = 'host=192.168.1.10 port=5432 user=repl_user password=repl_pass'

2.4 验证复制状态

-- Primary上查看
SELECT
    application_name,
    client_addr,
    state,
    sync_state,
    replay_lag
FROM pg_stat_replication;

-- Standby上查看
SELECT
    pg_is_in_recovery(),
    pg_last_wal_receive_lsn(),
    pg_last_wal_replay_lsn();

三、同步复制配置

3.1 同步vs异步

模式 数据安全性 性能影响 适用场景
异步 可能丢数据 无影响 报表、分析
同步 零数据丢失 写入延迟增加 核心交易
半同步(ANY) 至少一备确认 中等 平衡方案

3.2 配置同步复制

# Primary postgresql.conf
synchronous_commit = on
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
# ANY 1: 至少一个同步备库确认
# FIRST 2: 列表中前两个按顺序确认

四、自动故障切换 — Patroni

4.1 Patroni架构

┌─────────────────────────────────────────┐
│                 etcd/dcs                 │
│           (分布式一致性存储)              │
└──┬──────────────┬──────────────┬────────┘
   │              │              │
   ▼              ▼              ▼
┌──────┐      ┌──────┐      ┌──────┐
│Patroni│     │Patroni│     │Patroni│
│  pg1  │◄───▶│  pg2  │◄───▶│  pg3  │
└──┬───┘      └──┬───┘      └──┬───┘
   │             │             │
   ▼             ▼             ▼
┌──────┐      ┌──────┐      ┌──────┐
│ PG   │      │ PG   │      │ PG   │
│Primary│     │Standby│    │Standby│
└──────┘      └──────┘      └──────┘

4.2 Patroni配置

# /etc/patroni/patroni.yml
scope: pg_cluster
namespace: /service/

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

etcd:
  hosts: 192.168.1.11:2379,192.168.1.12:2379,192.168.1.13:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        wal_keep_size: 1024
        max_wal_senders: 10
        max_replication_slots: 10

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 192.168.1.10:5432
  data_dir: /var/lib/pgsql/14/data
  pgpass: /tmp/pgpass
  authentication:
    replication:
      username: repl_user
      password: repl_pass
    superuser:
      username: postgres
      password: postgres_pass

4.3 日常运维命令

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

# 手动切换
patronictl -c /etc/patroni/patroni.yml switchover

# 故障切换(紧急)
patronictl -c /etc/patroni/patroni.yml failover

# 重新加入集群
patronictl -c /etc/patroni/patroni.yml reinit pg_cluster <node>

五、连接管理 — PgBouncer

5.1 配置

# /etc/pgbouncer/pgbouncer.ini
[databases]
mydb = host=192.168.1.10 port=5432 dbname=mydb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25

5.2 连接池模式对比

模式 特性 适用场景
session 连接绑定到会话 需要会话状态
transaction 事务结束后释放 推荐,通用场景
statement 语句结束后释放 无状态应用

六、监控与告警

6.1 关键监控指标

-- 复制延迟
SELECT
    client_addr,
    pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
    EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag_seconds
FROM pg_stat_replication;

-- 长事务
SELECT pid, now() - xact_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle' AND xact_start < now() - interval '5 minutes';

6.2 告警规则

  • 复制延迟 > 10秒 → 紧急告警
  • 复制延迟 > 1秒 → 警告
  • Standby异常下线 → 紧急告警
  • 连接数 > 80% → 警告

总结

PostgreSQL高可用是一个渐进式的过程:

  1. 起步:主备流复制(手动切换)
  2. 进阶:Patroni + etcd(自动切换)
  3. 完善:PgBouncer连接池 + 监控告警
  4. 终极:跨机房容灾 + 读写分离

选择适合业务阶段的高可用方案,避免过度设计。

分享:

相关文章