PostgreSQL 18.4 高可用 Docker 部署:3 节点流复制集群搭建实战

在当今微服务架构盛行的时代,数据库高可用性已成为保障业务连续性的关键要素。PostgreSQL 作为最先进的开源关系型数据库,其流复制技术结合 Docker 容器化部署,能够为关键业务系统提供稳定可靠的数据服务。本文将深入探讨如何利用 Docker Compose 构建 1 主 2 从的 PostgreSQL 流复制集群,涵盖从环境准备到故障转移演练的全流程。

1. 环境准备与架构设计

1.1 基础组件选型

构建高可用 PostgreSQL 集群需要以下核心组件:

  • PostgreSQL 18.4 :选择当前稳定版本,具备 WAL 日志传输和热备能力
  • Docker 20.10+ :建议使用最新稳定版以获得最佳容器支持
  • Docker Compose 2.20+ :用于定义和管理多容器应用
  • pg_auto_failover :轻量级自动故障转移管理工具(或 Patroni)

1.2 网络拓扑设计

采用三节点部署架构确保法定人数(quorum)机制:

                   +-----------------+
                   |   Application   |
                   +--------+--------+
                            |
           +----------------+-----------------+
           |                |                 |
     +-----+------+   +-----+------+   +------+-----+
     |  Primary   |   |  Standby   |   |  Standby   |
     | (Node1)    |   | (Node2)    |   | (Node3)    |
     +------------+   +------------+   +------------+

关键配置参数对比:

参数 Primary 节点 Standby 节点
hot_standby off on
wal_level replica replica
synchronous_commit remote_apply off

2. Docker Compose 配置详解

2.1 完整 docker-compose.yml 配置

version: '3.8'

services:
  pg-primary:
    image: postgres:18.4
    container_name: pg-primary
    environment:
      POSTGRES_PASSWORD: Str0ngP@ss
      POSTGRES_USER: replicator
      POSTGRES_DB: app_db
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - pgdata1:/var/lib/postgresql/data
    networks:
      - pg-network
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U replicator"]
      interval: 5s
      timeout: 5s
      retries: 5

  pg-standby1:
    image: postgres:18.4
    container_name: pg-standby1
    environment:
      POSTGRES_PASSWORD: Str0ngP@ss
      POSTGRES_USER: replicator
      POSTGRES_DB: app_db
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - pgdata2:/var/lib/postgresql/data
    networks:
      - pg-network
    depends_on:
      pg-primary:
        condition: service_healthy
    command: >
      bash -c '
      until pg_isready -h pg-primary -U replicator; do sleep 2; done;
      rm -rf /var/lib/postgresql/data/pgdata/*;
      pg_basebackup -h pg-primary -U replicator -D /var/lib/postgresql/data/pgdata -P -R -X stream -C -S standby1;
      echo "hot_standby = on" >> /var/lib/postgresql/data/pgdata/postgresql.auto.conf;
      exec docker-entrypoint.sh postgres
      '

  pg-standby2:
    image: postgres:18.4
    container_name: pg-standby2
    environment:
      POSTGRES_PASSWORD: Str0ngP@ss
      POSTGRES_USER: replicator
      POSTGRES_DB: app_db
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - pgdata3:/var/lib/postgresql/data
    networks:
      - pg-network
    depends_on:
      pg-primary:
        condition: service_healthy
    command: >
      bash -c '
      until pg_isready -h pg-primary -U replicator; do sleep 2; done;
      rm -rf /var/lib/postgresql/data/pgdata/*;
      pg_basebackup -h pg-primary -U replicator -D /var/lib/postgresql/data/pgdata -P -R -X stream -C -S standby2;
      echo "hot_standby = on" >> /var/lib/postgresql/data/pgdata/postgresql.auto.conf;
      exec docker-entrypoint.sh postgres
      '

volumes:
  pgdata1:
  pgdata2:
  pgdata3:

networks:
  pg-network:
    driver: bridge

2.2 关键配置解析

  1. 主节点配置要点 :

    • 设置 PGDATA 环境变量指定数据目录
    • 通过健康检查确保服务可用性
    • 暴露 5432 端口供应用连接
  2. 备节点特殊处理 :

    • 使用 pg_basebackup 从主节点初始化数据
    • -R 参数自动生成 recovery.conf
    • -X stream 启用流式 WAL 传输
    • -S 指定复制槽名称避免 WAL 堆积
  3. 网络配置 :

    • 专用 bridge 网络确保节点间低延迟通信
    • 容器间通过服务名直接访问

提示:生产环境中建议为每个节点配置独立的物理卷,避免单点故障

3. 流复制与自动故障转移配置

3.1 主节点参数调优

在主节点执行以下 SQL 配置流复制参数:

ALTER SYSTEM SET wal_level = 'replica';
ALTER SYSTEM SET max_wal_senders = 5;
ALTER SYSTEM SET wal_keep_size = '1GB';
ALTER SYSTEM SET synchronous_standby_names = 'standby1,standby2';
ALTER SYSTEM SET synchronous_commit = 'remote_apply';

验证配置生效:

docker exec -it pg-primary psql -U replicator -c "SELECT name, setting FROM pg_settings WHERE name LIKE '%wal%' OR name LIKE '%replica%';"

3.2 配置 pg_auto_failover

  1. 添加监控节点服务到 compose 文件:
pg-auto-failover:
  image: postgres:18.4
  container_name: pg-auto-failover
  environment:
    POSTGRES_PASSWORD: monitor@123
    PGDATA: /var/lib/postgresql/data/pgdata
  volumes:
    - pgmonitor:/var/lib/postgresql/data
  networks:
    - pg-network
  command: >
    bash -c '
    if [ ! -f /var/lib/postgresql/data/pgdata/postgresql.conf ]; then
      pg_autoctl create monitor --pgdata /var/lib/postgresql/data/pgdata --auth trust --no-ssl;
    fi;
    pg_autoctl run
    '
  1. 修改主备节点命令启用自动故障转移:
# 主节点命令改为:
command: >
  bash -c '
  if [ ! -f /var/lib/postgresql/data/pgdata/postgresql.conf ]; then
    pg_autoctl create postgres --pgdata /var/lib/postgresql/data/pgdata \
    --monitor postgres://autoctl_node@pg-auto-failover/pg_auto_failover \
    --hostname pg-primary --auth trust --no-ssl;
  fi;
  exec docker-entrypoint.sh postgres
  '

# 备节点命令改为:
command: >
  bash -c '
  until pg_isready -h pg-primary -U replicator; do sleep 2; done;
  rm -rf /var/lib/postgresql/data/pgdata/*;
  pg_autoctl create postgres --pgdata /var/lib/postgresql/data/pgdata \
  --monitor postgres://autoctl_node@pg-auto-failover/pg_auto_failover \
  --hostname pg-standby1 --auth trust --no-ssl;
  exec docker-entrypoint.sh postgres
  '

3.3 验证复制状态

在主节点执行:

SELECT client_addr, state, sync_priority, sync_state 
FROM pg_stat_replication;

预期输出应显示两个备节点信息:

 client_addr  |   state   | sync_priority | sync_state 
--------------+-----------+---------------+------------
 172.20.0.3   | streaming |             1 | sync
 172.20.0.4   | streaming |             2 | potential

4. 故障转移演练与监控

4.1 模拟主节点故障

  1. 强制停止主节点容器:
docker stop pg-primary
  1. 观察自动故障转移过程:
docker logs pg-auto-failover
  1. 验证新主节点选举:
docker exec -it pg-standby1 psql -U replicator -c "SELECT pg_is_in_recovery();"

4.2 故障恢复流程

  1. 修复原主节点后重新加入集群:
docker start pg-primary
docker exec -it pg-primary pg_autoctl rejoin --pgdata /var/lib/postgresql/data/pgdata
  1. 验证节点角色:
docker exec -it pg-auto-failover psql -U autoctl_node -d pg_auto_failover -c "SELECT formation_id, node_id, node_name, node_host, node_port, candidate_priority, replication_quorum, node_role, node_active FROM pgautofailover.node;"

4.3 监控指标配置

建议监控以下关键指标:

指标名称 监控方法 告警阈值
复制延迟 pg_stat_replication.replay_lag > 1MB
主备连接状态 pg_is_in_recovery() 备节点返回 true
WAL 积压量 pg_current_wal_lsn() 差值 > 4GB
数据库连接数 pg_stat_activity 计数 > 最大连接数 80%

示例 Prometheus 配置:

scrape_configs:
  - job_name: 'postgres'
    static_configs:
      - targets: ['pg-primary:9187', 'pg-standby1:9187', 'pg-standby2:9187']
    metrics_path: '/metrics'
    params:
      dsn: ['postgresql://monitor:password@localhost:5432/postgres?sslmode=disable']

5. 性能优化与生产建议

5.1 关键参数调优

根据节点角色调整以下参数:

主节点优化 :

ALTER SYSTEM SET shared_buffers = '4GB';
ALTER SYSTEM SET effective_cache_size = '12GB';
ALTER SYSTEM SET maintenance_work_mem = '1GB';
ALTER SYSTEM SET checkpoint_completion_target = 0.9;

备节点优化 :

ALTER SYSTEM SET max_standby_streaming_delay = '30s';
ALTER SYSTEM SET hot_standby_feedback = on;

5.2 连接池配置

使用 PgBouncer 作为连接池:

pgbouncer:
  image: edoburu/pgbouncer
  environment:
    DB_USER: replicator
    DB_PASSWORD: Str0ngP@ss
    DB_HOST: pg-primary
    DB_NAME: app_db
    POOL_MODE: transaction
    MAX_CLIENT_CONN: 1000
    DEFAULT_POOL_SIZE: 20
  ports:
    - "6432:6432"
  networks:
    - pg-network
  depends_on:
    - pg-primary

5.3 备份策略

配置每日基础备份 + WAL 归档:

# 在主节点 crontab 添加
0 2 * * * pg_basebackup -D /backups/base_$(date +\%Y\%m\%d) -Ft -z -Xs -P
* * * * * test ! -f /backups/archived/$(date +\%Y\%m\%d).log && pg_archivecleanup /backups/archived/ $(ls -t /backups/archived/ | head -n 1)

6. 常见问题排查

6.1 复制中断处理

症状 :备节点日志出现 FATAL: could not receive data from WAL stream

解决步骤 :

  1. 检查主节点 WAL 发送进程状态:

    docker exec -it pg-primary psql -U replicator -c "SELECT * FROM pg_stat_replication;"
    
  2. 必要时重建备节点:

    docker-compose stop pg-standby1
    docker volume rm pg_pgdata2
    docker-compose up -d pg-standby1
    

6.2 脑裂场景处理

当网络分区导致多主情况时:

  1. 确定最新时间线:

    docker exec -it pg-node1 cat /var/lib/postgresql/data/pgdata/pg_wal/*.history | tail -n 1
    
  2. 将旧主节点切换为备节点:

    docker exec -it pg-primary pg_rewind --target-pgdata=/var/lib/postgresql/data/pgdata --source-server="host=pg-standby1 user=replicator password=Str0ngP@ss"
    

6.3 性能问题诊断

使用 pg_stat_statements 分析慢查询:

CREATE EXTENSION pg_stat_statements;
SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit / 
       nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent 
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;

更多推荐