PostgreSQL + Pgpool + Barman WAL Streaming 到 S3 SOP

1. 背景与目标

  • 现状:生产环境使用 pgpool 管理 PostgreSQL 高可用(主从切换由 pgpool 决策)。
  • 目标:在不调整任何 PostgreSQL 或 pgpool 配置的前提下,新增 Barman,使用 WAL Streaming 持续备份到本地,并将备份仓库近实时同步到 S3;提供可操作的 SOP,支持点时间恢复(PITR)。
  • 原理要点:
    • WAL Streaming 提供低延迟、持续复制能力,适合高可用场景。
    • 将 Barman 仓库同步到 S3 提供异地冗余与时间点恢复能力。
    • 不启用 archive_command;通过流式拉取实现冗余与补齐。

2. 架构概览

  • 组件:
    • barman:拉取 WAL、管理备份与保留策略、执行 cron。
    • s3sync:周期性使用 awscli 将 Barman 仓库同步到 S3。
    • primary-watcher:连接 pgpool,查询当前 primary 节点,动态更新 barman 的连接目标,自动感知主从切换。
    • scheduler(可选):每日触发一次基线备份(base backup)。
  • 数据流:PostgreSQL 主库 → Barman(pg_receivewal 流式)→ 本地仓库 → S3 同步。
  • 约束:不修改 postgresql.conf、pgpool 配置或启用 archive_command。

架构图(Mermaid)

flowchart LR
  %% 对外应用经由 pgpool 访问数据库;Barman 直连主库做 WAL 拉取与备份,并将仓库同步到 S3;primary-watcher 通过 pgpool 感知主从切换

  subgraph Clients[业务访问层]
    APP[应用/服务]
  end

  APP -->|读写路由| PGPOOL[(pgpool)]

  subgraph DB[数据库高可用集群]
    PG_PRIMARY[(PostgreSQL 主库)] --- PG_STANDBY[(PostgreSQL 备库)]
  end

  PGPOOL -->|主库连接| PG_PRIMARY
  PGPOOL -->|只读连接| PG_STANDBY

  subgraph BackupPlane[备份平面]
    PRIMARY_WATCHER[primary-watcher\n通过 pgpool 感知主库]
    BARMAN[Barman\nWAL Streaming + Base Backup]
    LOCAL[(本地Barman仓库)]
    S3SYNC[s3sync\naws s3 sync]
    S3[(S3 Bucket/prefix)]
    SCHEDULER[scheduler\n每日基线备份]
  end

  %% 感知与更新
  PRIMARY_WATCHER -->|show pool_nodes| PGPOOL
  PRIMARY_WATCHER -->|更新 conninfo.host| BARMAN

  %% 备份与同步
  BARMAN -->|直连| PG_PRIMARY
  BARMAN --> LOCAL
  SCHEDULER -->|触发 base backup| BARMAN
  S3SYNC --> LOCAL
  S3SYNC -->|同步到云端| S3

  %% 只用于感知,不经 pgpool 进行物理复制
  classDef note fill:#fff9c4,stroke:#fbc02d,color:#8a6d3b
flowchart LR
  %% 对外应用经由 pgpool 访问数据库;Barman 直连主库做 WAL 拉取与备份,并将仓库同步到 S3;primary-watcher 通过 pgpool 感知主从切换

  subgraph Clients[业务访问层]
    APP[应用/服务]
  end

  APP -->|读写路由| PGPOOL[(pgpool)]

  subgraph DB[数据库高可用集群]
    PG_PRIMARY[(PostgreSQL 主库)] --- PG_STANDBY[(PostgreSQL 备库)]
  end

  PGPOOL -->|主库连接| PG_PRIMARY
  PGPOOL -->|只读连接| PG_STANDBY

  subgraph BackupPlane[备份平面]
    PRIMARY_WATCHER[primary-watcher\n通过 pgpool 感知主库]
    BARMAN[Barman\nWAL Streaming + Base Backup]
    LOCAL[(本地Barman仓库)]
    S3SYNC[s3sync\naws s3 sync]
    S3[(S3 Bucket/prefix)]
    SCHEDULER[scheduler\n每日基线备份]
  end

  %% 感知与更新
  PRIMARY_WATCHER -->|show pool_nodes| PGPOOL
  PRIMARY_WATCHER -->|更新 conninfo.host| BARMAN

  %% 备份与同步
  BARMAN -->|直连| PG_PRIMARY
  BARMAN --> LOCAL
  SCHEDULER -->|触发 base backup| BARMAN
  S3SYNC --> LOCAL
  S3SYNC -->|同步到云端| S3

  %% 只用于感知,不经 pgpool 进行物理复制
  classDef note fill:#fff9c4,stroke:#fbc02d,color:#8a6d3b
flowchart LR
  %% 对外应用经由 pgpool 访问数据库;Barman 直连主库做 WAL 拉取与备份,并将仓库同步到 S3;primary-watcher 通过 pgpool 感知主从切换

  subgraph Clients[业务访问层]
    APP[应用/服务]
  end

  APP -->|读写路由| PGPOOL[(pgpool)]

  subgraph DB[数据库高可用集群]
    PG_PRIMARY[(PostgreSQL 主库)] --- PG_STANDBY[(PostgreSQL 备库)]
  end

  PGPOOL -->|主库连接| PG_PRIMARY
  PGPOOL -->|只读连接| PG_STANDBY

  subgraph BackupPlane[备份平面]
    PRIMARY_WATCHER[primary-watcher\n通过 pgpool 感知主库]
    BARMAN[Barman\nWAL Streaming + Base Backup]
    LOCAL[(本地Barman仓库)]
    S3SYNC[s3sync\naws s3 sync]
    S3[(S3 Bucket/prefix)]
    SCHEDULER[scheduler\n每日基线备份]
  end

  %% 感知与更新
  PRIMARY_WATCHER -->|show pool_nodes| PGPOOL
  PRIMARY_WATCHER -->|更新 conninfo.host| BARMAN

  %% 备份与同步
  BARMAN -->|直连| PG_PRIMARY
  BARMAN --> LOCAL
  SCHEDULER -->|触发 base backup| BARMAN
  S3SYNC --> LOCAL
  S3SYNC -->|同步到云端| S3

  %% 只用于感知,不经 pgpool 进行物理复制
  classDef note fill:#fff9c4,stroke:#fbc02d,color:#8a6d3b

3. 前提条件

  • 网络:barman 容器到各 PostgreSQL 节点 5432 可达;pgpool 5432/PCP 端口可达(用于“感知”主从,不用于复制)。
  • 账号:
    • 复制用户(主库执行):

      1
      
      CREATE ROLE barman REPLICATION LOGIN PASSWORD '强密码';
    • pgpool 管理查询用户(可执行 show pool_nodes 的只读账号)。

  • S3:已创建 bucket 与前缀(如 s3://pg-backup/cluster-a/),配置最小权限的 IAM。
  • 运行方式:所有第三方组件使用 Docker 容器运行。

4. 环境变量与目录布局

  • 建议在部署目录设置以下环境变量(通过 .env 或 Compose 环境段传入):

    • PRIMARY_WATCH_HOST=pgpool 地址
    • PRIMARY_WATCH_PORT=5432
    • PRIMARY_WATCH_USER=只读管理用户
    • PRIMARY_WATCH_PASSWORD=该用户密码
    • BARMAN_PASSWORD=barman 复制用户密码
    • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION
    • S3_BUCKET=pg-backup
    • S3_PREFIX=cluster-a
  • 目录结构(宿主机):

    • ./barman/etc/barman.conf
    • ./barman/etc/conf.d/my_pg_server.conf
    • ./barman/var/ (Barman 仓库数据)
    • ./barman/log/ (日志)

5. Barman 配置示例

  • /barman/etc/barman.conf:

    1
    2
    3
    4
    5
    6
    7
    
    [barman]
    barman_user = barman
    barman_home = /var/lib/barman
    log_file = /var/log/barman/barman.log
    compression = gzip
    reuse_backup = link
    retention_policy = REDUNDANCY 2
  • /barman/etc/conf.d/my_pg_server.conf:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    [my_pg_server]
    description = "Primary PostgreSQL"
    conninfo = host=INIT_PRIMARY port=5432 user=barman dbname=postgres password=BARMAN_PASSWORD
    backup_method = postgres
    streaming_archiver = on
    slot_name = barman
    create_slot = auto
    archiver = off
    streaming_backup_name = streaming
    retention_policy_mode = auto
    retention_policy = REDUNDANCY 2

说明:conninfo 的 host 将由 primary-watcher 自动更新为当前主库地址。

6. Docker Compose 部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
version: "3.8"
services:
  barman:
    image: ghcr.io/pgcentralfoundation/barman:3
    container_name: barman
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./barman/etc:/etc/barman
      - ./barman/var:/var/lib/barman
      - ./barman/log:/var/log/barman
    command: /bin/sh -c "while true; do barman cron; sleep 60; done"
    restart: always

  s3sync:
    image: amazon/aws-cli:2.15.0
    container_name: s3sync
    environment:
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
      - S3_BUCKET=${S3_BUCKET}
      - S3_PREFIX=${S3_PREFIX}
    volumes:
      - ./barman/var:/var/lib/barman:ro
    command: /bin/sh -c "while true; do aws s3 sync /var/lib/barman s3://${S3_BUCKET}/${S3_PREFIX} --delete; sleep 30; done"
    restart: always

  primary-watcher:
    image: bitnami/postgresql:16
    container_name: primary-watcher
    environment:
      - PGPOOL_HOST=${PRIMARY_WATCH_HOST}
      - PGPOOL_PORT=${PRIMARY_WATCH_PORT}
      - PRIMARY_USER=${PRIMARY_WATCH_USER}
      - PRIMARY_PASSWORD=${PRIMARY_WATCH_PASSWORD}
    volumes:
      - ./barman/etc:/etc/barman
    command: /bin/bash -c '
      LAST="";
      while true; do
        OUT=$(psql "host=$PGPOOL_HOST port=$PGPOOL_PORT user=$PRIMARY_USER password=$PRIMARY_PASSWORD dbname=postgres" -Atc "show pool_nodes" 2>/dev/null | awk -F"|" '\''$7=="primary"{print $2}'\'');
        if [ -n "$OUT" ] && [ "$OUT" != "$LAST" ]; then
          sed -i.bak "s/^conninfo = .*/conninfo = host=$OUT port=5432 user=barman dbname=postgres password=BARMAN_PASSWORD/" /etc/barman/conf.d/my_pg_server.conf;
          LAST="$OUT";
        fi
        sleep 10;
      done
    '
    restart: always

  scheduler:
    image: ghcr.io/pgcentralfoundation/barman:3
    container_name: backup-scheduler
    volumes:
      - ./barman/etc:/etc/barman
      - ./barman/var:/var/lib/barman
      - ./barman/log:/var/log/barman
    command: /bin/sh -c "while true; do barman backup my_pg_server; sleep 86400; done"
    restart: always

部署:

1
docker compose up -d

7. 验证步骤

  • 列出服务器并检查:

    1
    2
    
    docker exec barman barman list-server
    docker exec barman barman check my_pg_server
  • 触发一次基线备份:

    1
    
    docker exec barman barman backup my_pg_server
  • 查看本地 WAL 与备份生成情况:

    1
    
    ls ./barman/var/my_pg_server -R | head
  • 校验 S3 同步:

    1
    
    aws s3 ls s3://${S3_BUCKET}/${S3_PREFIX}/ --recursive | head

8. 故障切换感知与演练

  • 原理:primary-watcher 通过 pgpool 的 show pool_nodes 获取 role=primary 的节点 IP/主机名;变化时更新 barman 的 conninfo,下一轮 cron 自动连接新主库继续拉 WAL。
  • 演练:
    • 触发一次主从切换(按现网流程)。
    • 10 秒内 primary-watcher 应更新 conninfo;barman cron 恢复拉流。
    • 执行 barman check 确认健康;观察 S3 继续出现新 WAL 文件。

9. 点时间恢复(PITR)

  • 目标:恢复到指定时间点。

  • 步骤:

    1
    2
    3
    4
    5
    6
    
    aws s3 sync s3://${S3_BUCKET}/${S3_PREFIX}/ /restore/barman
    docker run --rm \
      -v /restore/barman:/var/lib/barman \
      -v /pgdata:/pgdata \
      ghcr.io/pgcentralfoundation/barman:3 \
      barman recover my_pg_server latest /pgdata --target-time "2026-01-04 10:00:00"
  • 启动 PostgreSQL,等待 WAL 回放完成后对外服务。

  • 建议:每季度在隔离环境演练完整恢复;抽查任意日期的还原一致性。

10. 监控与告警

  • barman 健康:定时执行 barman check,采集返回码与关键日志。
  • 复制槽与延迟:监控 pg_replication_slots、pg_stat_wal_receiver。
  • S3 同步:比对本地与 S3 文件数量与更新时间;失败重试与告警。
  • 容量与成本:监控 S3 用量、请求次数;按需调整保留策略与备份频率。

11. 保留策略与运行维护

  • 保留:retention_policy = REDUNDANCY 2(保留最近两份备份及其 WAL)。
  • 运行:barman 每分钟 cron;scheduler 每日基线备份;s3sync 每 30 秒同步。
  • 维护:定期清理过期备份、验证备份可用性,评估同步频率与成本。

12. 权限与安全

  • IAM 最小权限,仅允许对指定 bucket/prefix 的读写与列举。
  • 凭证通过环境变量或 Docker Secrets 提供;不要写入镜像或代码仓库。
  • primary-watcher 账号仅需 show pool_nodes 的只读权限。

13. 故障排除

  • barman check 失败:查看 ./barman/log/barman.log;确认 conninfo 主机地址与复制用户权限。
  • WAL 积压:若复制槽长时间无消费者会导致主库 WAL 磁盘增长;需监控并及时恢复。
  • pgpool 列解析:不同版本 show pool_nodes 列位可能差异,必要时打印行样例确认 awk 列号。
  • S3 同步异常:检查 awscli 版本、凭证、网络连通性;开启重试与告警。

14. 风险与建议

  • 不通过 pgpool 做物理复制,仅用其感知主库角色,降低复制链路复杂度。
  • 监控复制槽与磁盘空间,避免 WAL 积压导致主库磁盘吃满。
  • 定期演练恢复,确保 RPO/RTO 达标;结合成本优化 S3 周期与保留窗口。

15. 附录:IAM 策略示例

16. 附录:参考

  • 云原生运维:https://www.kbsonlong.com/
  • Kubernetes 文档:https://kubernetes.io/zh-cn/docs/home/
  • Istio 官方文档:https://istio.io/latest/zh/docs/
  • Linux 内核文档:https://docs.kernel.org/translations/zh_CN/index.html
  • WAL 归档与流式原理:Understanding WAL Archiving and WAL Streaming in PostgreSQL(结合 WAL Streaming 与文件归档的优势,采用流式 + S3 冗余以满足不改主库配置的约束)
0%