PostgreSQL 高可用集群(Pgpool-II + PostgreSQL)

一、Pgpool-II + PostgreSQL 高可用方案介绍

核心能力

|------------|--------------------------------------------------------|
| 能力 | 实现方式 |
| 读写分离 | Pgpool load_balance_mode = on,读请求分发到从节点 |
| 连接池 | num_init_children = 32max_pool = 5,复用连接 |
| 故障检测 | health_check_period = 10,每10秒检测后端节点状态 |
| 自动故障转移 | failover_on_backend_shutdown = on,主节点宕机时 Pgpool 自动切换 |
| 自动恢复 | PGPOOL_AUTO_FAILBACK=yes,节点恢复后自动加入集群 |
| 高可用 | PostgreSQL 通过 repmgr 实现流复制 + 自动主从切换 |

架构说明

1. PostgreSQL 层(repmgr 流复制)

  • 3个节点:pg-0(主)、pg-1(从)、pg-2(从)

  • 使用 bitnami/postgresql-repmgr 镜像,内置 repmgr 扩展

  • POSTGRESQL_SHARED_PRELOAD_LIBRARIES=repmgr 启用 repmgr

  • repmgr 负责:流复制管理、主从选举、自动故障转移

2. Pgpool-II 层(中间件)

  • 监听 :9999,应用连接 Pgpool 而非直连 PostgreSQL

  • backend_clustering_mode = 'streaming_replication' --- 流复制模式

  • 自动感知主从:通过 sr_check_user = 'repmgr' 检测各节点角色

  • 写请求 → 主节点,读请求 → 负载均衡到所有节点

  • 主节点故障时,repmgr 选举新主,Pgpool 自动感知并切换

二、部署过程

1.环境准备

|----------|---------------|---------------------------|-----------------------------|
| 主机名 | ip | 操作系统 | 备注 |
| master01 | 192.168.48.80 | openEuler 24.03 (LTS-SP2) | docker、postgresql主节点、pgpool |
| node01 | 192.168.48.81 | openEuler 24.03 (LTS-SP2) | docker、postgresql从节点1 |
| node02 | 192.168.48.82 | openEuler 24.03 (LTS-SP2) | docker、postgresql从节点2 |

2.Postgresql

master01

.env

绝对路径:/root/pg-cluster/postgresql/.env

复制代码
# PostgreSQL 数据库配置
# PostgreSQL 超级用户密码
POSTGRESQL_POSTGRES_PASSWORD=postgres

# 应用用户配置
POSTGRESQL_USERNAME=mydiy
POSTGRESQL_PASSWORD=mydiy
POSTGRESQL_DATABASE=mydiy

# repmgr 配置
REPMGR_USERNAME=repmgr
REPMGR_PASSWORD=repmgr
REPMGR_DATABASE=repmgr

# 备份服务配置(使用 POSTGRES_ 前缀,与图片中的变量名一致)
POSTGRES_DB=flygpt
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost            # host模式使用(如需要可取消注释)
POSTGRES_PORT=5432                 # host模式使用(如需要可取消注释)
BACKUP_DIR=/backups
RETENTION_DAYS=7

# 时区配置
TZ=Asia/Shanghai
custom.conf

postgresql默认会自己生成配置文件,这里指定自定义custom.conf文件为配置文件

绝对路径:/data/postgresql/conf.d/custom.conf

复制代码
# PostgreSQL 配置文件 - 分类整理版本
# 1. 网络与连接配置
# 网络监听设置
listen_addresses = '*'                    # 监听所有网络接口
port = 5432                              # 监听端口(更改需要重启)
# 连接限制
max_connections = 300                    # 最大连接数(更改需要重启)
# 2. 内存配置
# 共享内存设置
shared_buffers = 3GB                     # 共享缓冲区大小,最小128kB(更改需要重启)
# 工作内存设置
work_mem = 16MB                          # 每个操作的工作内存,最小64kB
maintenance_work_mem = 8GB               # 维护操作的工作内存
# 缓存配置
effective_cache_size = 8GB               # 操作系统和磁盘缓存的有效大小
# 3. 并行处理配置
# 并行工作进程
max_worker_processes = 10                # 最大工作进程数(更改需要重启)
max_parallel_workers = 8                 # 最大并行工作进程数
# 并行查询配置
max_parallel_workers_per_gather = 4      # 每个Gather节点的最大并行工作进程
# 4. 预写日志(WAL)配置
# WAL缓冲区设置
wal_buffers = 64MB                       # WAL缓冲区大小,最小32kB(更改需要重启)
# WAL文件大小限制
max_wal_size = 2GB                       # 最大WAL大小
min_wal_size = 160MB                     # 最小WAL大小
# 5. 检查点配置
checkpoint_completion_target = 0.9       # 检查点目标持续时间,0.0 - 1.0
# 6. 查询优化配置
# 成本估算参数
random_page_cost = 1.1                   # 随机页面访问成本(SSD建议1.0-1.5)
# 统计信息配置
default_statistics_target = 500          # 默认统计目标,范围1-10000
# 7. 自动清理配置
# 自动清理工作进程
autovacuum_max_workers = 4               # 自动清理子进程的最大数量
# 自动清理性能调整
autovacuum_vacuum_cost_delay = 10ms      # 自动清理的成本延迟,以毫秒为单位


#密码加密方式
password_encryption = scram-sha-256

wal_log_hints = on 
logging_collector = on
archive_mode = on 
docker-compose.yaml

/root/pg-cluster/postgresql/docker-compose.yaml

复制代码
# PostgreSQL 主节点 docker-compose.yaml(部署在master01节点:192.168.48.80)
services:
  # PostgreSQL 主节点配置
  pg-0:
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/bitnami/postgresql-repmgr:17.5.0-debian-12-r7
    container_name: pg-0
    restart: unless-stopped  # 改为 unless-stopped,避免异常时无限重启
    stop_grace_period: 60s   # 给 PostgreSQL 60 秒优雅停止时间
    stop_signal: SIGTERM     # 使用 SIGTERM 信号优雅停止
    network_mode: "host"  # 使用主机网络模式,容器直接使用主机网络栈,便于节点间通信
    volumes:
      - pg_data:/bitnami/postgresql  # PostgreSQL 数据目录持久化
      - /data/postgresql/conf.d:/opt/bitnami/postgresql/conf/conf.d:ro  # 挂载自定义配置文件目录(只读)
      - /etc/localtime:/etc/localtime:ro  # 同步主机时区
    environment:
      # PostgreSQL 基本配置(从 .env 文件读取)
      - POSTGRESQL_POSTGRES_PASSWORD=${POSTGRESQL_POSTGRES_PASSWORD}  # PostgreSQL 超级用户 postgres 的密码
      # 创建应用用户 flydiy
      - POSTGRESQL_USERNAME=${POSTGRESQL_USERNAME}
      # 设置应用用户密码
      - POSTGRESQL_PASSWORD=${POSTGRESQL_PASSWORD}
      # 创建应用数据库
      - POSTGRESQL_DATABASE=${POSTGRESQL_DATABASE}

      # repmgr 必要认证配置(从 .env 文件读取)
      - REPMGR_USERNAME=${REPMGR_USERNAME}  # repmgr 管理用户
      - REPMGR_PASSWORD=${REPMGR_PASSWORD}  # repmgr 用户密码
      - REPMGR_DATABASE=${REPMGR_DATABASE}  # repmgr 元数据数据库
      
      # 时区配置
      - TZ=${TZ}

      # repmgr 集群配置 - 主节点特定配置
      - REPMGR_NODE_ID=1  # 当前节点在集群中的唯一标识符
      - REPMGR_USE_SUPERUSER=yes  # 允许 repmgr 使用超级用户权限执行管理操作
      - REPMGR_NODE_NAME=pg-0  # 节点在集群中的逻辑名称
      - REPMGR_NODE_NETWORK_NAME=192.168.48.80  # 节点对外提供服务的网络地址
      - REPMGR_PRIMARY_HOST=192.168.48.80  # 初始主节点地址(启动时指向自己)
      - REPMGR_PRIMARY_PORT=5432  # 主节点端口
      - REPMGR_PARTNER_NODES=192.168.48.80:5432,192.168.48.81:5432,192.168.48.82:5432  # 集群中所有节点的地址列表
      - REPMGR_PORT_NUMBER=5432  # 当前节点监听端口

      # 流复制关键配置
      - POSTGRESQL_WAL_LEVEL=replica  # WAL日志级别设置为副本,支持流复制
      - POSTGRESQL_MAX_WAL_SENDERS=10  # 最大WAL发送进程数,限制可连接的备用节点数量
      - POSTGRESQL_MAX_REPLICATION_SLOTS=10  # 最大复制槽数量,用于跟踪备用节点状态
      - POSTGRESQL_SHARED_PRELOAD_LIBRARIES=repmgr  # 预加载 repmgr 扩展

      # 主节点初始化配置
      - REPMGR_INIT_PRIMARY=true  # 将该节点初始化为集群的主节点
      - REPMGR_CREATE_MASTER_RECORD=true  # 在 repmgr 元数据中创建主节点记录
      - BITNAMI_DEBUG=true  # 启用 Bitnami 镜像的调试日志输出

      # 同步提交配置(可选,提高数据一致性但可能影响性能)
      #- POSTGRESQL_SYNCHRONOUS_COMMIT=on  # 启用同步提交,确保事务在多个节点确认后才返回
      #- POSTGRESQL_SYNCHRONOUS_STANDBY_NAMES=*  # 指定所有备用节点为同步副本

      # 测试环境使用,生产环境建议关闭(允许所有连接无需密码验证)
      #- REPMGR_PGHBA_TRUST_ALL=yes

      # 内存优化配置
      - POSTGRESQL_MAINTENANCE_WORK_MEM=1GB  # 维护操作(如VACUUM、索引创建)可用的内存大小
      
      # 多数据库vector扩展自动安装
      - POSTGRESQL_EXTRA_INIT_SCRIPTS=/opt/bitnami/scripts/postgresql/multi-db-vector-setup.sh

    # 添加主机名映射
    extra_hosts:
      - "pg-0:192.168.48.80"
      - "pg-1:192.168.48.81"
      - "pg-2:192.168.48.82"
    
    # 健康检查配置
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres || exit 1"]
      interval: 10s      # 每 10 秒检查一次
      timeout: 5s        # 超时时间 5 秒
      retries: 5         # 失败 5 次后标记为 unhealthy
      start_period: 60s  # 启动后 60 秒才开始健康检查

# 定义持久化卷
volumes:
  pg_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/postgresql  # 将主机的 /data/postgresql 目录绑定挂载为数据卷

node01

.env

绝对路径:/root/pg-cluster/postgresql/.env

复制代码
# PostgreSQL 数据库配置
# PostgreSQL 超级用户密码
POSTGRESQL_POSTGRES_PASSWORD=postgres

# 应用用户配置
POSTGRESQL_USERNAME=mydiy
POSTGRESQL_PASSWORD=mydiy
POSTGRESQL_DATABASE=mydiy

# repmgr 配置
REPMGR_USERNAME=repmgr
REPMGR_PASSWORD=repmgr
REPMGR_DATABASE=repmgr

# 备份服务配置(使用 POSTGRES_ 前缀,与图片中的变量名一致)
POSTGRES_DB=flygpt
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost            # host模式使用(如需要可取消注释)
POSTGRES_PORT=5432                 # host模式使用(如需要可取消注释)
BACKUP_DIR=/backups
RETENTION_DAYS=7

# 时区配置
TZ=Asia/Shanghai
custom.conf

postgresql默认会自己生成配置文件,这里指定自定义custom.conf文件为配置文件

绝对路径:/data/postgresql/conf.d/custom.conf

复制代码
# PostgreSQL 配置文件 - 分类整理版本
# 1. 网络与连接配置
# 网络监听设置
listen_addresses = '*'                    # 监听所有网络接口
port = 5432                              # 监听端口(更改需要重启)
# 连接限制
max_connections = 300                    # 最大连接数(更改需要重启)
# 2. 内存配置
# 共享内存设置
shared_buffers = 3GB                     # 共享缓冲区大小,最小128kB(更改需要重启)
# 工作内存设置
work_mem = 16MB                          # 每个操作的工作内存,最小64kB
maintenance_work_mem = 8GB               # 维护操作的工作内存
# 缓存配置
effective_cache_size = 8GB               # 操作系统和磁盘缓存的有效大小
# 3. 并行处理配置
# 并行工作进程
max_worker_processes = 10                # 最大工作进程数(更改需要重启)
max_parallel_workers = 8                 # 最大并行工作进程数
# 并行查询配置
max_parallel_workers_per_gather = 4      # 每个Gather节点的最大并行工作进程
# 4. 预写日志(WAL)配置
# WAL缓冲区设置
wal_buffers = 64MB                       # WAL缓冲区大小,最小32kB(更改需要重启)
# WAL文件大小限制
max_wal_size = 2GB                       # 最大WAL大小
min_wal_size = 160MB                     # 最小WAL大小
# 5. 检查点配置
checkpoint_completion_target = 0.9       # 检查点目标持续时间,0.0 - 1.0
# 6. 查询优化配置
# 成本估算参数
random_page_cost = 1.1                   # 随机页面访问成本(SSD建议1.0-1.5)
# 统计信息配置
default_statistics_target = 500          # 默认统计目标,范围1-10000
# 7. 自动清理配置
# 自动清理工作进程
autovacuum_max_workers = 4               # 自动清理子进程的最大数量
# 自动清理性能调整
autovacuum_vacuum_cost_delay = 10ms      # 自动清理的成本延迟,以毫秒为单位

#密码加密方式
password_encryption = scram-sha-256

wal_log_hints = on 
logging_collector = on
archive_mode = on 
docker-compose.yaml

/root/pg-cluster/postgresql/docker-compose.yaml

复制代码
# PostgreSQL 备用节点 docker-compose.yaml(部署在node01:192.168.48.81)
services:
  # PostgreSQL 备用节点配置
  pg-1:
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/bitnami/postgresql-repmgr:17.5.0-debian-12-r7
    container_name: pg-1
    restart: unless-stopped  # 改为 unless-stopped,避免异常时无限重启
    stop_grace_period: 60s   # 给 PostgreSQL 60 秒优雅停止时间
    stop_signal: SIGTERM     # 使用 SIGTERM 信号优雅停止
    network_mode: "host"  # 使用主机网络模式,便于节点间直接通信
    volumes:
      - pg_data:/bitnami/postgresql  # 备用节点数据目录持久化
      - /data/postgresql/conf.d:/opt/bitnami/postgresql/conf/conf.d:ro  # 挂载自定义配置文件目录(只读)
    environment:
      # PostgreSQL 基本配置(从 .env 文件读取)
      - POSTGRESQL_POSTGRES_PASSWORD=${POSTGRESQL_POSTGRES_PASSWORD}  # PostgreSQL 超级用户 postgres 的密码
      # 创建应用用户 flydiy
      - POSTGRESQL_USERNAME=${POSTGRESQL_USERNAME}
      # 设置应用用户密码
      - POSTGRESQL_PASSWORD=${POSTGRESQL_PASSWORD}
      # 创建应用数据库
      - POSTGRESQL_DATABASE=${POSTGRESQL_DATABASE}

      # repmgr 必要认证配置(从 .env 文件读取)
      - REPMGR_USERNAME=${REPMGR_USERNAME}  # repmgr 管理用户
      - REPMGR_PASSWORD=${REPMGR_PASSWORD}  # repmgr 用户密码
      - REPMGR_DATABASE=${REPMGR_DATABASE}  # repmgr 元数据数据库
 
      # repmgr 集群配置 - 备用节点特定配置
      - REPMGR_NODE_ID=2  # 当前节点在集群中的唯一标识符
      - REPMGR_USE_SUPERUSER=yes  # 允许 repmgr 使用超级用户权限执行管理操作
      - REPMGR_NODE_NAME=pg-1  # 节点在集群中的逻辑名称
      - REPMGR_NODE_NETWORK_NAME=192.168.48.81  # 节点对外提供服务的网络地址
      - REPMGR_PRIMARY_HOST=192.168.48.80  # 指向主节点地址,用于初始复制连接
      - REPMGR_PRIMARY_PORT=5432  # 主节点端口
      - REPMGR_PARTNER_NODES=192.168.48.80:5432,192.168.48.81:5432,192.168.48.82:5432  # 集群中所有节点的地址列表
      - REPMGR_PORT_NUMBER=5432  # 当前节点监听端口
      
      # 流复制配置
      - POSTGRESQL_WAL_LEVEL=replica
      - POSTGRESQL_MAX_WAL_SENDERS=10
      - POSTGRESQL_MAX_REPLICATION_SLOTS=10
      - POSTGRESQL_SHARED_PRELOAD_LIBRARIES=repmgr

      # 从节点配置
      - REPMGR_INIT_PRIMARY=false
      - REPMGR_CREATE_MASTER_RECORD=false
      - BITNAMI_DEBUG=true
      # 测试环境使用,生产环境建议关闭(允许所有连接无需密码验证)
      #- REPMGR_PGHBA_TRUST_ALL=yes
      
      # 优化配置
      - POSTGRESQL_MAINTENANCE_WORK_MEM=1GB  # 维护操作可用的内存大小
      
    # 添加主机名映射
    extra_hosts:
      - "pg-0:192.168.48.80"
      - "pg-1:192.168.48.81"
      - "pg-2:192.168.48.82"

    # 健康检查配置
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres || exit 1"]
      interval: 10s      # 每 10 秒检查一次
      timeout: 5s        # 超时时间 5 秒
      retries: 5         # 失败 5 次后标记为 unhealthy
      start_period: 60s  # 启动后 60 秒才开始健康检查

# 定义持久化卷
volumes:
  pg_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/postgresql  # 将主机的 /data/postgresql 目录绑定挂载为数据卷

node02

.env

绝对路径:/root/pg-cluster/postgresql/.env

复制代码
# PostgreSQL 数据库配置
# PostgreSQL 超级用户密码
POSTGRESQL_POSTGRES_PASSWORD=postgres

# 应用用户配置
POSTGRESQL_USERNAME=mydiy
POSTGRESQL_PASSWORD=mydiy
POSTGRESQL_DATABASE=mydiy

# repmgr 配置
REPMGR_USERNAME=repmgr
REPMGR_PASSWORD=repmgr
REPMGR_DATABASE=repmgr

# 备份服务配置(使用 POSTGRES_ 前缀,与图片中的变量名一致)
POSTGRES_DB=flygpt
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost            # host模式使用(如需要可取消注释)
POSTGRES_PORT=5432                 # host模式使用(如需要可取消注释)
BACKUP_DIR=/backups
RETENTION_DAYS=7

# 时区配置
TZ=Asia/Shanghai
custom.conf

postgresql默认会自己生成配置文件,这里指定自定义custom.conf文件为配置文件

绝对路径:/data/postgresql/conf.d/custom.conf

复制代码
# PostgreSQL 配置文件 - 分类整理版本
# 1. 网络与连接配置
# 网络监听设置
listen_addresses = '*'                    # 监听所有网络接口
port = 5432                              # 监听端口(更改需要重启)
# 连接限制
max_connections = 300                    # 最大连接数(更改需要重启)
# 2. 内存配置
# 共享内存设置
shared_buffers = 3GB                     # 共享缓冲区大小,最小128kB(更改需要重启)
# 工作内存设置
work_mem = 16MB                          # 每个操作的工作内存,最小64kB
maintenance_work_mem = 8GB               # 维护操作的工作内存
# 缓存配置
effective_cache_size = 8GB               # 操作系统和磁盘缓存的有效大小
# 3. 并行处理配置
# 并行工作进程
max_worker_processes = 10                # 最大工作进程数(更改需要重启)
max_parallel_workers = 8                 # 最大并行工作进程数
# 并行查询配置
max_parallel_workers_per_gather = 4      # 每个Gather节点的最大并行工作进程
# 4. 预写日志(WAL)配置
# WAL缓冲区设置
wal_buffers = 64MB                       # WAL缓冲区大小,最小32kB(更改需要重启)
# WAL文件大小限制
max_wal_size = 2GB                       # 最大WAL大小
min_wal_size = 160MB                     # 最小WAL大小
# 5. 检查点配置
checkpoint_completion_target = 0.9       # 检查点目标持续时间,0.0 - 1.0
# 6. 查询优化配置
# 成本估算参数
random_page_cost = 1.1                   # 随机页面访问成本(SSD建议1.0-1.5)
# 统计信息配置
default_statistics_target = 500          # 默认统计目标,范围1-10000
# 7. 自动清理配置
# 自动清理工作进程
autovacuum_max_workers = 4               # 自动清理子进程的最大数量
# 自动清理性能调整
autovacuum_vacuum_cost_delay = 10ms      # 自动清理的成本延迟,以毫秒为单位

#密码加密方式
password_encryption = scram-sha-256

wal_log_hints = on 
logging_collector = on
archive_mode = on 
docker-compose.yaml

/root/pg-cluster/postgresql/docker-compose.yaml

复制代码
# PostgreSQL 备用节点 docker-compose.yaml(部署在node02:192.168.48.82)
services:
  # PostgreSQL 备用节点配置
  pg-2:
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/bitnami/postgresql-repmgr:17.5.0-debian-12-r7
    container_name: pg-2
    restart: unless-stopped  # 改为 unless-stopped,避免异常时无限重启
    stop_grace_period: 60s   # 给 PostgreSQL 60 秒优雅停止时间
    stop_signal: SIGTERM     # 使用 SIGTERM 信号优雅停止
    network_mode: "host"  # 使用主机网络模式,便于节点间直接通信
    volumes:
      - pg_data:/bitnami/postgresql  # 备用节点数据目录持久化
      - /data/postgresql/conf.d:/opt/bitnami/postgresql/conf/conf.d:ro  # 挂载自定义配置文件目录(只读)
    environment:
      # PostgreSQL 基本配置(从 .env 文件读取)
      - POSTGRESQL_POSTGRES_PASSWORD=${POSTGRESQL_POSTGRES_PASSWORD}  # PostgreSQL 超级用户 postgres 的密码
      # 创建应用用户 flydiy
      - POSTGRESQL_USERNAME=${POSTGRESQL_USERNAME}
      # 设置应用用户密码
      - POSTGRESQL_PASSWORD=${POSTGRESQL_PASSWORD}
      # 创建应用数据库
      - POSTGRESQL_DATABASE=${POSTGRESQL_DATABASE}
 
      # repmgr 必要认证配置(从 .env 文件读取)
      - REPMGR_USERNAME=${REPMGR_USERNAME}  # repmgr 管理用户
      - REPMGR_PASSWORD=${REPMGR_PASSWORD}  # repmgr 用户密码
      - REPMGR_DATABASE=${REPMGR_DATABASE}  # repmgr 元数据数据库
      
      # repmgr 集群配置 - 备用节点特定配置
      - REPMGR_NODE_ID=3  # 当前节点在集群中的唯一标识符
      - REPMGR_USE_SUPERUSER=yes  # 允许 repmgr 使用超级用户权限执行管理操作
      - REPMGR_NODE_NAME=pg-2  # 节点在集群中的逻辑名称
      - REPMGR_NODE_NETWORK_NAME=192.168.48.82  # 节点对外提供服务的网络地址
      - REPMGR_PRIMARY_HOST=192.168.48.80  # 指向主节点地址,用于初始复制连接
      - REPMGR_PRIMARY_PORT=5432  # 主节点端口
      - REPMGR_PARTNER_NODES=192.168.48.80:5432,192.168.48.81:5432,192.168.48.82:5432  # 集群中所有节点的地址列表
      - REPMGR_PORT_NUMBER=5432  # 当前节点监听端口
      
      # 流复制配置
      - POSTGRESQL_WAL_LEVEL=replica
      - POSTGRESQL_MAX_WAL_SENDERS=10
      - POSTGRESQL_MAX_REPLICATION_SLOTS=10
      - POSTGRESQL_SHARED_PRELOAD_LIBRARIES=repmgr

      # 从节点配置
      - REPMGR_INIT_PRIMARY=false
      - REPMGR_CREATE_MASTER_RECORD=false
      - BITNAMI_DEBUG=true
      # 测试环境使用,生产环境建议关闭(允许所有连接无需密码验证)
      #- REPMGR_PGHBA_TRUST_ALL=yes
      
      # 优化配置
      - POSTGRESQL_MAINTENANCE_WORK_MEM=1GB  # 维护操作可用的内存大小
      
    # 添加主机名映射
    extra_hosts:
      - "pg-0:192.168.48.80"
      - "pg-1:192.168.48.81"
      - "pg-2:192.168.48.82"

    # 健康检查配置
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres || exit 1"]
      interval: 10s      # 每 10 秒检查一次
      timeout: 5s        # 超时时间 5 秒
      retries: 5         # 失败 5 次后标记为 unhealthy
      start_period: 60s  # 启动后 60 秒才开始健康检查

# 定义持久化卷
volumes:
  pg_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/postgresql  # 将主机的 /data/postgresql 目录绑定挂载为数据卷

3.Pgpool

只在master01节点

.env

绝对路径:/root/pg-cluster/pgpool/.env

复制代码
# Pgpool 环境变量配置文件
# 仅包含敏感信息(账号密码等)
# 请妥善保管,不要提交到版本控制系统

# 流复制检查用户和密码
PGPOOL_SR_CHECK_USER=repmgr
PGPOOL_SR_CHECK_PASSWORD=repmgr

# PostgreSQL 连接用户和密码
PGPOOL_POSTGRES_USERNAME=postgres
PGPOOL_POSTGRES_PASSWORD=postgres

# 管理员用户和密码
PGPOOL_ADMIN_USERNAME=postgres
PGPOOL_ADMIN_PASSWORD=postgres

# Pgpool 加密密钥(用于 pool_passwd 加密)
PGPOOL_AES_KEY=ioZQerApstxyMU0Qx0lT98jQWSM=

# 健康检查用户和密码
PGPOOL_HEALTH_CHECK_USER=repmgr
PGPOOL_HEALTH_CHECK_PASSWORD=repmgr

pgpool.conf

绝对路径:/root/pg-cluster/pgpool/pgpool.conf

复制代码
# --------------------------------
# Pgpool-II 4.6 configuration file
# --------------------------------

#------------------------------------------------------------------------------
# BACKEND CLUSTERING MODE
#------------------------------------------------------------------------------

backend_clustering_mode = 'streaming_replication'

#------------------------------------------------------------------------------
# CONNECTIONS
#------------------------------------------------------------------------------

listen_addresses = '*'
port = 9999
unix_socket_directories = '/opt/bitnami/pgpool/tmp'

pcp_listen_addresses = '*'
pcp_port = 9898
pcp_socket_dir = '/opt/bitnami/pgpool/tmp'

backend_hostname0 = '192.168.48.80'
backend_port0 = 5432
backend_weight0 = 1
backend_flag0 = 'ALLOW_TO_FAILOVER'

backend_hostname1 = '192.168.48.81' 
backend_port1 = 5432 
backend_weight1 = 1 
backend_flag1 = 'ALLOW_TO_FAILOVER'

backend_hostname2 = '192.168.48.82' 
backend_port2 = 5432 
backend_weight2 = 1 
backend_flag2 = 'ALLOW_TO_FAILOVER'

backend_application_name0 = 'pg-0'
backend_application_name1 = 'pg-1'
backend_application_name2 = 'pg-2'

enable_pool_hba = on
pool_passwd = 'pool_passwd'
authentication_timeout = 30
allow_clear_text_frontend_auth = on

#------------------------------------------------------------------------------
# POOLS
#------------------------------------------------------------------------------

num_init_children = 32
max_pool = 5
child_life_time = 300

#------------------------------------------------------------------------------
# LOGS
#------------------------------------------------------------------------------

log_destination = 'stderr'
log_connections = off
log_hostname = off
log_per_node_statement = off
logging_collector = on
log_directory = '/tmp/pgpool_logs'
log_filename = 'pgpool-%Y-%m-%d_%H%M%S.log'
log_truncate_on_rotation = on
log_rotation_age = '1d'
log_rotation_size = '10MB'

#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------

pid_file_name = '/opt/bitnami/pgpool/tmp/pgpool.pid'
logdir = '/opt/bitnami/pgpool/logs'

#------------------------------------------------------------------------------
# LOAD BALANCING MODE
#------------------------------------------------------------------------------

load_balance_mode = on
disable_load_balance_on_write = 'transaction'
statement_level_load_balance = off

#------------------------------------------------------------------------------
# STREAMING REPLICATION MODE
#------------------------------------------------------------------------------

sr_check_period = 30
sr_check_user = 'repmgr'
sr_check_password = ''
sr_check_database = 'postgres'

#------------------------------------------------------------------------------
# HEALTH CHECK GLOBAL PARAMETERS
#------------------------------------------------------------------------------

health_check_period = 10
health_check_timeout = 30
health_check_user = 'repmgr'
health_check_password = ''
health_check_max_retries = 3
health_check_retry_delay = 2
connect_timeout = 10000

#------------------------------------------------------------------------------
# FAILOVER AND FAILBACK
#------------------------------------------------------------------------------

failover_command = 'echo ">>> Failover - that will initialize new primary node search!"'
failover_on_backend_error = off
failover_on_backend_shutdown = on
search_primary_node_timeout = 0

#------------------------------------------------------------------------------
# ONLINE RECOVERY
#------------------------------------------------------------------------------

recovery_user = 'postgres'
recovery_password = ''

pool_hba.conf

绝对路径:/root/pg-cluster/pgpool/pool_hba.conf

复制代码
local    all             all                            trust
host     all             repmgr            all        scram-sha-256
host     all             postgres       all        scram-sha-256
host     all             all                all         scram-sha-256

docker-compose.yaml

绝对路径:/root/pg-cluster/pgpool/docker-compose.yaml

复制代码
services:
  pgpool-0:
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/bitnami/pgpool:4.6.2-debian-12-r1
    container_name: pgpool-0
    restart: always
    network_mode: "host"
    volumes:
      # 挂载需要持久化的子目录
      - pgpool_data:/opt/bitnami/pgpool/data
      - pgpool_logs:/opt/bitnami/pgpool/logs
      #- pgpool_conf:/opt/bitnami/pgpool/conf
      # 挂载配置文件(只读挂载)
      - ./pgpool.conf:/opt/bitnami/pgpool/conf.default/pgpool.conf:ro
      - ./pool_hba.conf:/opt/bitnami/pgpool/conf.default/pool_hba.conf:ro
      #- ./pgpool_node_id:/opt/bitnami/pgpool/conf/pgpool_node_id:ro

    env_file:
      - .env

    environment:
      # pgpool 基础配置
      - PGPOOL_PORT_NUMBER=9999
      - PGPOOL_BACKEND_NODES=0:192.168.48.80:5432,1:192.168.48.81:5432,2:192.168.48.82:5432
      - PGPOOL_BACKEND_APPLICATION_NAMES=pg-0,pg-1,pg-2
      #- PGPOOL_NODE_ID=0
      
      # 认证配置(从 .env 文件读取敏感信息)
      - PGPOOL_SR_CHECK_USER=${PGPOOL_SR_CHECK_USER}
      - PGPOOL_SR_CHECK_PASSWORD=${PGPOOL_SR_CHECK_PASSWORD}
      - PGPOOL_POSTGRES_USERNAME=${PGPOOL_POSTGRES_USERNAME}
      - PGPOOL_POSTGRES_PASSWORD=${PGPOOL_POSTGRES_PASSWORD}
      - PGPOOL_ADMIN_USERNAME=${PGPOOL_ADMIN_USERNAME}
      - PGPOOL_ADMIN_PASSWORD=${PGPOOL_ADMIN_PASSWORD}

      # 功能开关
      - PGPOOL_ENABLE_LOAD_BALANCING=yes
      - PGPOOL_ENABLE_STATEMENT_LOAD_BALANCING=no
      - PGPOOL_DISABLE_LOAD_BALANCE_ON_WRITE=transaction
      - PGPOOL_ENABLE_CONNECTION_CACHE=yes
      - PGPOOL_STREAMING_REPLICATION=yes
      - PGPOOL_REPLICATION_MODE=no
      - PGPOOL_PARALLEL_MODE=no

      # 连接池和超时配置
      - PGPOOL_NUM_INIT_CHILDREN=32
      - PGPOOL_MAX_POOL=5
      - PGPOOL_CHILD_LIFE_TIME=300
      - PGPOOL_TIMEOUT=360
      - PGPOOL_CONNECT_TIMEOUT=10000

      # 健康检查配置
      - PGPOOL_HEALTH_CHECK_USER=${PGPOOL_HEALTH_CHECK_USER}
      - PGPOOL_HEALTH_CHECK_PASSWORD=${PGPOOL_HEALTH_CHECK_PASSWORD}
      - PGPOOL_HEALTH_CHECK_PERIOD=10
      - PGPOOL_HEALTH_CHECK_TIMEOUT=30
      - PGPOOL_HEALTH_CHECK_MAX_RETRIES=3
      - PGPOOL_HEALTH_CHECK_RETRY_DELAY=2
      - PGPOOL_HEALTH_CHECK_PSQL_TIMEOUT=15
      - PGPOOL_AUTO_FAILBACK=yes
      - BITNAMI_DEBUG=true

      # 认证方式配置
      - PGPOOL_ENABLE_POOL_HBA=yes
      - PGPOOL_ENABLE_POOL_PASSWD=yes
      - PGPOOL_AUTHENTICATION_METHOD=scram-sha-256
      - PGPOOL_AES_KEY=${PGPOOL_AES_KEY}

      # 自定义配置文件
      - PGPOOL_USER_CONF_FILE=/opt/bitnami/pgpool/conf.default/pgpool.conf       # 自定义 Pgpool-II 配置文件
      - PGPOOL_USER_HBA_FILE=/opt/bitnami/pgpool/conf.default/pool_hba.conf      # 自定义基于主机的身份验证配置
      #- PGPOOL_PASSWD_FILE=pool_passwd               # Pgpool-II 池密码文件
      
      # TLS/SSL 安全配置
      #- PGPOOL_ENABLE_TLS=no                             # 是否为流量启用 TLS
      #- PGPOOL_TLS_CERT_FILE                             # 包含 TLS 证书的文件
      #- PGPOOL_TLS_KEY_FILE                              # 包含证书密钥的文件
      #- PGPOOL_TLS_CA_FILE                               # 包含证书 CA 的文件
      #- PGPOOL_TLS_PREFER_SERVER_CIPHERS=yes             # 使用服务器的 TLS 密码偏好
    
    # 健康检查(修正缩进)
    healthcheck:
      test: ["CMD", "/opt/bitnami/scripts/pgpool/healthcheck.sh"]
      interval: 10s
      timeout: 5s
      retries: 5      

    extra_hosts:
      - "pg-0:192.168.48.80"
      - "pg-1:192.168.48.81"
      - "pg-2:192.168.48.82"

# 定义持久卷,只挂载数据和日志目录
volumes:
  pgpool_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/pgpool/data/
  # pgpool_conf:
  #   driver: local
  #   driver_opts:
  #     type: none
  #     o: bind
  #     device: /data/pgpool/conf/
  pgpool_logs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/pgpool/logs/

4.启动

进入docker-compose.yaml所在目录执行启动命令,先启动主库再启动从库,最后启动pgpool。

复制代码
docker-compose up -d

检查是否启动成功

复制代码
docker-compose ps

检查postgresql高可用集群状态

复制代码
docker exec -it pgpool-0 psql -h 192.168.48.80 -p 9999 -U postgres -c "SHOW pool_nodes;"

输出:

复制代码
Password for user postgres: 
 node_id |   hostname    | port | status | pg_status | lb_weight |  role   | pg_role | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change  
---------+---------------+------+--------+-----------+-----------+---------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
 0       | 192.168.48.80 | 5432 | up     | up        | 0.333333  | primary | primary | 2          | false             | 0                 |                   |                        | 2026-06-18 12:19:53
 1       | 192.168.48.81 | 5432 | up     | up        | 0.333333  | standby | standby | 0          | false             | 0                 | streaming         | async                  | 2026-06-18 12:19:53
 2       | 192.168.48.82 | 5432 | up     | up        | 0.333333  | standby | standby | 0          | true              | 0                 | streaming         | async                  | 2026-06-18 12:19:53
(3 rows)

各字段详解

|------------------------|---------------------|------------------------------------------------------------|
| 字段 | 值(以 node_id=0 为例) | 含义 |
| node_id | 0, 1, 2 | 后端节点的唯一标识(pgpool 内部编号)。 |
| hostname | 192.168.48.80/81/82 | PostgreSQL 实例的 IP 地址。 |
| port | 5432 | PostgreSQL 的监听端口。 |
| status | up | pgpool 对节点的健康检查结果(up 表示可连接,down 表示不可用)。 |
| pg_status | up | PostgreSQL 实例自身的运行状态(up 表示数据库进程正常)。 |
| lb_weight | 0.333333 | 负载均衡权重,三个节点平均分配(各 1/3),意味着读查询会按此比例分发到三个节点。 |
| role | primary / standby | pgpool 识别的节点角色(主库或从库),用于路由写操作(主)和读操作(从)。 |
| pg_role | primary / standby | PostgreSQL 自身的角色,与 role 一致,确保一致性。 |
| select_cnt | 2 / 0 / 0 | 该节点自 pgpool 启动以来处理的 SELECT 查询次数(由于刚重启不久,主库处理了 2 次,从库还未处理)。 |
| load_balance_node | true(在 node_id=2 上) | 表示本次查询被 pgpool 的负载均衡器路由到了哪个节点(这里是 82)。true 只会出现在其中一个节点上。 |
| replication_delay | 0 | 从库与主库的复制延迟(单位为字节或时间,此处为 0 表示无延迟)。 |
| replication_state | streaming(从库) | 从库正在使用 流复制 同步数据(正常状态)。主库此列为空。 |
| replication_sync_state | async(从库) | 复制模式为 异步复制(PostgreSQL 默认),主库此列为空。 |
| last_status_change | 时间戳 | 该节点最后一次状态变化的时间(从 down 变为 up 或反过来)。 |

关键信息总结

  1. 主从架构确认

    1. 主库:192.168.48.80(负责写入)

    2. 从库:192.168.48.81192.168.48.82(负责读取)

  2. 复制链路正常

    1. 两个从库都通过 流复制 从主库同步数据,延迟为 0,说明数据实时性很好。

    2. 复制模式是 async(异步),这是 PostgreSQL 的默认配置,适合大多数场景。

  3. 负载均衡生效

    1. 三个节点的 lb_weight 都是 0.333,表示读查询会均匀分发。

    2. 你的本次查询被路由到了 192.168.48.82load_balance_node=true),说明 pgpool 的负载均衡算法(如轮询或最少连接)正在工作。

5.主从复制验证

这里pgpool是逻辑上的一个数据库,它会连接主库,所以在pgpool上验证主从复制。

连接pgpool的9999端口后,postgres库中插入user表,三个postgresql同时复制user表。

复制代码
CREATE TABLE "user" (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    is_active BOOLEAN DEFAULT TRUE
);

查看是否都同步复制了user表

复制代码
psql -h 192.168.48.80 -p 5432 -U postgres -c "\dt"
psql -h 192.168.48.81 -p 5432 -U postgres -c "\dt"
psql -h 192.168.48.82 -p 5432 -U postgres -c "\dt"

均显示

复制代码
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | user | table | postgres
(1 row)

示例:

复制代码
[root@master01 pg-cluster]# docker exec -it pgpool-0 /bin/bash
I have no name!@master01:/$ psql -h 192.168.48.80 -p 5432 -U postgres -c "\dt"
Password for user postgres: 
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | user | table | postgres
(1 row)

I have no name!@master01:/$ psql -h 192.168.48.81 -p 5432 -U postgres -c "\dt"
Password for user postgres: 
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | user | table | postgres
(1 row)

I have no name!@master01:/$ psql -h 192.168.48.82 -p 5432 -U postgres -c "\dt"
Password for user postgres: 
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | user | table | postgres
(1 row)