Lazy loaded image
配置 PostgreSQL 高可用集群
Words 4884Read Time 13 min
2025-10-1
2025-11-10
date
related_level
slug
type
relate_date
summary
status
tags
category
last_updated
Nov 10, 2025 10:03 PM
是否已更新
orginal_page
是否推荐

PostgreSQL 使用 repmgr 进行主备克隆和故障转移

参考资料
  • 虽然配置相对简单, 但相对繁琐, 建议使用 etcd+Patroni
  • 本文中,postgresql 主版本为 15, 主库操作系统为 OS X,其余均为 debian
repmgr 常用指令汇总
注册节点 <primary|standby|witness> register
  • repmgr -f ~/repmgr/repmgr.conf primary register
    • node1
  • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf standby register --upstream-node-id <primary_node_id>
    • node2
  • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf witness register -h <primary_ip>
    • witness
备库从主库克隆
  • node2
    • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf -U repmgr -d repmgr -h <primary_ip> standby clone
  • 取消注册节点 <primary|standby|witness> unregister
  • 验证集群状态 cluster show
    • node1
      • repmgr -f ~/repmgr/repmgr.conf cluster show
    • node2
      • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf cluster show
  • 检查集群节点间是否 ssh 互信 cluster crosscheck
    • node1
      • repmgr -f ~/repmgr/repmgr.conf cluster crosscheck
    • node2
      • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf cluster crosscheck
debian 添加 postgresql 库安装 repmgr
  • 添加 postgresql 官方库
    • 添加 repmgr
      • apt install postgresql-15-repmgr
    mac 编译安装 repmgr
    • 如果需要集群间复制配置文件则还需要安装 rsync
    os x
    • brew install make gcc json-c ki18n
    • 下载最新版本源码并解压
      • export REPMGR_VER=5.5.0
      • curl -o repmgr.tar.gz -L https://github.com/EnterpriseDB/repmgr/releases/download/v$REPMGR_VER/repmgr-$REPMGR_VER.tar.gz
      • tar -xzf repmgr.tar.gz
    编译并安装最新版本 repmgr
    • cd repmgr-$REPMGR_VER
    • 配置编译环境(假设为 postgresql 15)
      • export PATH="/opt/homebrew/opt/postgresql@15/bin:/opt/homebrew/bin:/opt/local/bin:$PATH"
        • 确保目标 PostgreSQL 版本的 pg_config 位于 $PATH
      • export LIBRARY_PATH=$LIBRARHPATH:/opt/homebrew/lib/
    • ./configure
    • make && make install
    • where repmgr
    添加 launchd 启动脚本
    • vim ~/Library/LaunchAgents/com.repmgr.plist
      • 自行更改相应路径
    (可选) ubuntu/debian 编译安装 repmgr
    • apt 安装,跟不上最新版本
      • apt-get install postgresql-15-repmgr
    • 下载最新版本源码并解压
      • export REPMGR_VER=5.5.0
      • curl -o repmgr.tar.gz -L https://github.com/EnterpriseDB/repmgr/releases/download/v$REPMGR_VER/repmgr-$REPMGR_VER.tar.gz
      • tar -xzf repmgr.tar.gz
    • 编译并安装最新版本 repmgr
      • cd repmgr-$REPMGR_VER
      • 配置编译环境(假设为 postgresql 15)
        • apt install make gcc flex bison postgresql-server-dev-15 libcurl4-openssl-dev libjson-c-dev libselinux-dev libzstd-dev liblz4-dev libxslt1-dev libpam0g-dev libkrb5-dev zlib1g-dev libreadline-dev
        • export PATH="/usr/lib/postgresql/15/bin:$PATH"
          • 确保目标 PostgreSQL 版本的 pg_config 位于 $PATH
      • ./configure
      • make && make install
      • where repmgr && sudo -u postgres repmgr --version
    主库 postgres 配置
    配置 postgresql.conf
    • listen_addresses = '*'
    • repmgr 相关
      • shared_preload_libraries = 'repmgr'
    • wal 设置,详细参考 PostgreSQL 设置日志传送后备服务器
      • 参考
    • 日志设置
      • 参考
    • 从库特有设置
      配置 pg_hba.conf
      • 配置 repmgr 用户和数据库
        • psql postgres
          • CREATE USER repmgr WITH SUPERUSER LOGIN PASSWORD '<passwd>';
          • CREATE DATABASE repmgr OWNER repmgr;
      配置 repmgr 管理 postgresql 集群
      • 根据当前系统管理 postgresql 的方式来修改默认指令
      • 查看当前的服务指令
        • OS X
          • repmgr -f ~/repmgr/repmgr.conf node service --list-actions
          • 改由 pg_ctl 管理,禁用 brew services 自动重启(keepalive)以免影响主备切换
            • brew services stop postgresql@15
            • brew services info postgresql@15
            • brew services list | grep postgresql
            • 修改 KeepAlive 的值为 false
              • vim /opt/homebrew/opt/postgresql@15/homebrew.mxcl.postgresql@15.plist
          • 保持 postgresql 开机自动启动
            • vim ~/Library/LaunchAgents/com.repmgr.postgresql.plist
              • launchctl load ~/Library/LaunchAgents/com.repmgr.postgresql.plist
              • pg_ctl status -D /opt/homebrew/var/postgresql@15
            ubuntu/debian
            • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf node service --list-actions
          • centos
          部分指令需要 sudo 提升权限,需要修改 /etc/sudoers
          • OS X
            • 无需 visudo
          • ubuntu/debian
            • sudo visudo
          • centos
            • sudo visudo
          主库和备库 repmgr 配置
          • 部分 repmgr 配置解释
            • promote_command 是提升时执行的指令
            • follow_command 是另外的备库附加到新的上游节点时执行的指令
            • service_xxx_command 是配置 repmgr 如何管理 postgresql 集群
          不同系统中的二进制文件路径不一样会导致 SSH 时 No such file or directory
          • 配置文件里设置 pg_bindir 保持路径一致来规避
          • ubuntu/debian
            • mkdir -p /usr/local/postgresql/15
            • ln -s /usr/lib/postgresql/15/bin /usr/local/postgresql/15/bin
            • ls -al /usr/local/postgresql/15/bin
          • os x
            • sudo mkdir -p /usr/local/postgresql/15
            • sudo ln -s /opt/homebrew/opt/postgresql@15/bin /usr/local/postgresql/15/bin
          配置主库 repmgr 并注册节点 node1 作为 primary 到集群
          • mkdir -p ~/repmgr
          • vim ~/repmgr/repmgr.conf
            • 注册主库节点到集群
              • repmgr -f ~/repmgr/repmgr.conf primary register
            配置备库 repmgr
            • mkdir -p /var/log/repmgr
              • sudo chown -R postgres:postgres /var/log/repmgr
            • sudo -p postgres mkdir -p /var/lib/postgresql/repmgr
            • sudo -p postgres touch /var/lib/postgresql/repmgr/repmgr.conf
            • vim /var/lib/postgresql/repmgr/repmgr.conf
              • ubuntu/debian 以外的使用 systemctl 而非 pg_ctlcluster 来管理 postgresql 集群
            备库克隆并启动
            • su - postgres
            • /usr/bin/repmgr -h <primary_ip> -U repmgr -d repmgr -f /var/lib/postgresql/repmgr/repmgr.conf standby clone
            • 此前的复制槽已经存在时需要先在主库上进行删除
              • psql -c "select * from pg_replication_slots;" postgres postgres
              • psql -c "SELECT pg_drop_replication_slot('repmgr_slot_standby1');" postgres postgres
            • 对于 ubuntu/debian 系统,配置文件位于数据目录之外,默认不会被复制
              • 配置 config_directory=/etc/postgresql/15/main-copy-external-config-files 可以复制这部分文件,默认复制到与上游相同的路径
              • -copy-external-config-files=pgdata 复制到数据目录
            • /usr/lib/postgresql/15/bin/pg_ctl -D /var/lib/postgresql/15/main start
              • 启动备库
            • pg_createcluster 15 main --start -d /var/lib/postgresql/15/main
            • sudo systemctl enable postgresql@15-main
            • 注册备库节点 node2 到集群(需要备库已启动)
              • /usr/bin/repmgr -f /var/lib/postgresql/repmgr/repmgr.conf standby register --upstream-node-id 1
            • 如果需要取消注册
              • /usr/bin/repmgr -f /var/lib/postgresql/repmgr/repmgr.conf primary unregister
              • /usr/bin/repmgr -f /var/lib/postgresql/repmgr/repmgr.conf standby unregister
            启动 repmgrd 守护进程
            ubuntu/debian 配置 repmgrd 服务
            repmgr 使用 init.d 脚本而非 systemd unit 文件, 配置 /etc/default/repmgrd 即可
            vim /etc/init.d/repmgrd
            vim /etc/default/repmgrd
            • sudo systemctl daemon-reload
            • sudo systemctl enable repmgrd
            • sudo systemctl is-enabled repmgrd
            • sudo systemctl start repmgrd
              • 根据 init.d 脚本文件生成 unit 服务文件
            • sudo systemctl status repmgrd
            OS X 创建 launchd 脚本配置 repmgrd 服务
            • launchctl list | grep postgres
              • 查看 postgresql 服务名
            vim ~/Library/LaunchAgents/com.repmgr.plist
            • 自行更改相应路径
            • launchctl load ~/Library/LaunchAgents/com.repmgr.plist
              • 修改后需要先 unload 后重新 load
            • launchctl print gui/$UID/com.repmgr
            • pgrep -fl repmgrd
            手动启动
            • /usr/bin/repmgrd -f /var/lib/postgresql/repmgr/repmgr.conf --pid-file /var/run/repmgrd.pid --daemonize
              • ubuntu/debian
            配置见证节点实现自动故障转移
            • 双节点集群必须有见证节点才能实现自动故障转移
            • 见证节点不存储数据,仅运行 repmgrd 守护进程
              • 当主节点和备节点因网络分区断开时,双方可能都认为自己是主节点,导致数据不一致(脑裂问题)
              • 此时,见证节点可以通过投票机制决定哪个节点应晋升为新主节点
            见证节点 postgresql 配置
            配置 postgresql.conf
            • listen_addresses = '*'
            • repmgr 相关
              • shared_preload_libraries = 'repmgr'
            • 日志设置
              • 参考
            配置 pg_hba.conf
            • sudo -u postgres pg_createcluster 15 main --start -d /var/lib/postgresql/15/main
            • sudo systemctl enable postgresql@15-main
            • 配置 repmgr 用户和数据库
              • sudo -u postgres psql postgres
                • CREATE USER repmgr WITH SUPERUSER LOGIN PASSWORD '<passwd>';
                • CREATE DATABASE repmgr OWNER repmgr;
            见证节点 repmgr 配置
            • mkdir -p /var/log/repmgr
            • sudo chown postgres:postgres /var/log/repmgr
            • su - postgres
            • mkdir -p ~/repmgr
            vim ~/repmgr/repmgr.conf
            • 注册节点 witness1 作为 witness 到集群
              • sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf witness register -h <primary_ip>
            配置 repmgrd 守护进程
            • 手动启动
              • /usr/bin/repmgrd -f /var/lib/postgresql/repmgr/repmgr.conf --pid-file /var/run/repmgrd.pid --daemonize
            ubuntu/debian 创建 init.d 脚本配置 repmgrd 服务
            sudo vim /etc/init.d/repmgrd
            sudo vim /etc/default/repmgrd
            • chmod 755 /etc/init.d/repmgrd
            • sudo systemctl daemon-reload
            • sudo systemctl enable repmgrd
            • sudo systemctl is-enabled repmgrd
            • sudo systemctl start repmgrd
              • 根据 init.d 脚本文件生成 unit 服务文件
            • sudo systemctl status repmgrd
            备库使用 repmgr 手动执行切换(故障转移)
            • 故障转移需要节点间通过无密码 ssh 连接
            创建节点间的无密码 ssh 连接(假设已有对应密钥对 repmgr, repmgr.pub
            • repmgr 默认以各节点配置文件中的 conn_info 对应的地址为 Hostname
              • 还需要配置 pg_hba.conf 以允许 repmgr 账户访问
            • 可以修改 repmgr 配置文件中的 ssh_options 进行 ssh 调试
              • ssh_options='-v -o ConnectTimeout=10'
            • su - postgres
            • mkdir -p ~/.ssh && touch ~/.ssh/{authorized_keys,config}
              • 把密钥对也放入其中,同时需要 chmod 600 以及 chown postgres
            • 添加公钥信息
              • cat ~/.ssh/repmgr.pub >> ~/.ssh/authorized_keys
            • 添加各节点的连接信息
              • vim ~/.ssh/config
                • 格式如下
                • 各个节点的连接信息都要加上,包括节点自身
            • 提前添加各个节点的公钥信息
              • ssh-keyscan -p <port> -H <primary_ip> <standby_ip> <witness_ip> >> ~/.ssh/known_hosts
            检查集群节点间是否 ssh 互信
            • /opt/homebrew/opt/postgresql@15/bin/repmgr -f ~/repmgr/repmgr.conf cluster show
              • node1
            • node1
              • /opt/homebrew/opt/postgresql@15/bin/repmgr -f ~/repmgr/repmgr.conf cluster crosscheck
            • node2
              • sudo -u postgres /usr/bin/repmgr -f /var/lib/postgresql/repmgr/repmgr.conf cluster crosscheck
            测试是否满足切换的前置条件 -dry-run
            • node2
              • sudo -u postgres /usr/bin/repmgr standby switchover -f /var/lib/postgresql/repmgr/repmgr.conf --siblings-follow --dry-run
            • node1
              • /opt/homebrew/opt/postgresql@15/bin/repmgr standby switchover -f ~/repmgr/repmgr.conf --siblings-follow --dry-run
            • 测试满足条件后去掉 -dry-run 即可
             

            PostgreSQL 使用 etcd, Patroni 和 HAProxy 提供高可用集群

            参考资料
            • etcd 安装参考别的文章, 这里不再累述
            debian 添加 postgresql 库安装 Patroni
            • 添加 postgresql 官方库
              • 添加 Patroni
                • apt-get install patroni
                • apt install python3-systemd
                  • systemd-notify
              (可选) debian 使用 python uv pip 安装 Patroni
              • 安装必须的编译工具
                • apt install -y build-essential pkg-config libsystemd-dev python3-dev
              • 获取最新版本
                • git clone --depth 1 --branch master https://github.com/patroni/patroni.git /var/lib/patroni
              安装 patroni
              • cd /var/lib/patroni
              • uv init venv && cd venv
              • uv add patroni
              • uv pip install patroni[psycopg3,etcd3,systemd,jsonlogger]
                • 使用 etcd 作为 DCS (Distributed Configuration Store, 分布式配置存储)
                • systemd 模块提供与 systemd 相关的 sd_notify 集成
                • jsonlogger 模块提供 json 格式日志输出
                • 如果需要使用 psycopg2 模块
                  • apt-get install python3-psycopg2
              • ln -sf /var/lib/patroni/venv/.venv/bin/patroni /usr/bin/patroni
              • which patroni && patroni --version
                • 测试
              配置 patroni unit 服务文件
              • cp /var/lib/patroni/extras/startup-scripts/patroni.service /etc/systemd/system/patroni.service
              • vim /etc/systemd/system/patroni.service
                • 修改文件位置, 其他根据情况修改
              • systemctl daemon-reload
              配置 Patroni
              • mkdir -p /etc/patroni
              • (可选) 可以从现有运行的 postgres 实例生成配置文件以复用
                • patroni --generate-config --dsn postgresql://postgres@127.0.0.1:5432/postgres /etc/patroni/patroni.current.yaml
                  • 会提示输入密码
                  • 未指定 DSN 则会从当前环境中读取相关 postgres 变量
              • cp /var/lib/patroni/postgres0.yml /etc/patroni/patroni.yaml
              vim /etc/patroni/patroni.yaml
              • 每个节点分别配置, 部分配置需要根据节点修改
                • name, restapi.connect_address, postgresql.connect_address
              • 动态配置文件均生成在 postgresql.data_dir 文件夹下
              • 配置 postgresql.custom_conf 复用现有配置, 忽略 postgresql.base.conf
                • 没有则默认从 postgresql.base.conf 获取
              • 如果配置了 postgresql.pg_hba, 且 postgresql.custom_conf 对应文件里没有配置 hba_file 选项, 则由 patroni 根据 负责在集群启动时生成 pg_hba.conf
                • postgresql.pg_ident 类似
              • 这里的 etcd3 使用了 ssl
              • 验证配置文件
                • patroni --validate-config /etc/patroni/patroni.yaml --ignore-listen-port
              启动 Patroni
              • systemctl disable --now postgresql@15-main
                • 改由 patroni 负责
              • systemctl enable --now patroni
              • systemctl status patroni
              curl 测试 Patroni 配置 basic auth
              • echo -n "username:password" | base64
              • curl -v -H "Authorization: Basic <auth_base64>" http://<node_ip>:8008/master
              • curl -v -H "Authorization: Basic <auth_base64>" http://<node_ip>:8008/replica
              用 patronictl 管理 PostgreSQL 集群
              指定配置文件路径
              • export PATRONICTL_CONFIG_FILE=/etc/patroni/patroni.yaml
                • UNIX 下默认路径为 ~/.patroni~/.config/patroni
              • 手动指定使用的配置文件
                • patronictl -c /etc/patroni/patroni.yaml
              备库重新初始化并从当前主库克隆
              • patronictl reinit <cluster_name> [<replica_node1_name> <replica_node2_name> ...]
              检查集群运行状态
              • patronictl topology [<cluster_name>] [-w | --watch]
                • 显示拓扑结构
                • w 每 2 秒刷新
              • patronictl list [<cluster_name>] [ { -e | --extended } ]
                • 显示集群信息
              重新加载配置文件
              • patronictl reload <cluster_name> [<node_name>]
                • 未指定成员则对全员生效
              • patronictl show-config <cluster_name>
                • 显示集群配置
              重新启动特定节点
              • patronictl restart <cluster_name> [<node_name>] [--role <role_type>] [ --scheduled TIMESTAMP ]
                • 未指定成员则对全员生效
                  • -role <role_type> 可以指定特定类型的成员组执行操作
                    • leader
                    • primary
                    • standby-leader
                    • replica
                    • 默认为 any
                • -scheduled <TIMESTAMP> 在指定时间戳执行重启, now 为立即
              手动故障转移
              • patronictl history <cluster_name>
                • 显示故障转移历史
              • patronictl failover <cluster_name> --candidate <cur_replica_node_name>
                • 在没有 leader 角色时使用
              • patronictl switchover <cluster_name> --leader <cur_leader_node_name> --candidate <cur_replica_node_name> --scheduled now
                • 在具有一位 leader 角色时使用
                • -scheduled <TIMESTAMP> 在指定时间戳执行转移, now 为立即
              执行 SQL 指令
              • 用户未提供则为当前系统操作用户
              配合 HAProxy 和 keepalived 提供高可用访问
              • 搭建 HAProxy 和 keepalived 基础部分参考
                • alpine 使用 haproxy 和 keepalived 提供高可用网络
              • keepalived 提供虚拟 IP, haproxy 负责将流量导向当前可用主库
              haproxy Patroni 部分的前端和后端
              status 迟迟未能变为 running 使得 systemd 重启服务, 导致主备频繁切换
              • 最简单的解决办法
                • 修改 type=notifytype=simple, 然后 systemctl daemon-reload 即可
              • 可能缺失 systemd-python 模块
                • apt install python3-systemd
              测试当前系统的 systemd-notify 机制是否可以生效
              • 测试 python3 是否可以使用 systemd.daemon.notify
                • daemon.notify
              vim /usr/local/share/scripts/notify-test.py
              • chmod +x /usr/local/share/scripts/notify-test.py
              vim /etc/systemd/system/notify-test.service
              • systemctl daemon-reload
              • systemctl start notify-test
                • 可以生效的话, 会在 3s 成功启动
              • systemctl status notify-test.service
                • 此时立刻查看应该为 active
                • 10s 经过后查看便恢复为 inactive, 同时输出日志
              • systemctl stop notify-test
              • 通知实际是由子进程发来的, 需要添加 NotifyAccess=all
                • all 表示接受该服务 cgroup 内所有进程的消息
               
              上一篇
              通过 k3s 部署轻量级 Kubernetes 集群
              下一篇
              Proxmox VE 虚拟机使用

              Comments
              Loading...