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
mac 编译安装 repmgr
- 如果需要集群间复制配置文件则还需要安装 rsync
os x
brew install make gcc json-c ki18n
- 下载最新版本源码并解压
export REPMGR_VER=5.5.0curl -o repmgr.tar.gz -L https://github.com/EnterpriseDB/repmgr/releases/download/v$REPMGR_VER/repmgr-$REPMGR_VER.tar.gztar -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
- 修改 Makefile.global.in
- https://github.com/EnterpriseDB/repmgr/issues/891
- 修改
PG_LDFLAGS行 PG_LDFLAGS=-lcurl -ljson-c -lintl- 在
PG_LDFLAGS行前添加 PG_CPPFLAGS=-I/opt/homebrew/include/ -I/opt/homebrew/opt/postgresql@15/include/
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.0curl -o repmgr.tar.gz -L https://github.com/EnterpriseDB/repmgr/releases/download/v$REPMGR_VER/repmgr-$REPMGR_VER.tar.gztar -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-devexport PATH="/usr/lib/postgresql/15/bin:$PATH"- 确保目标 PostgreSQL 版本的
pg_config位于$PATH ./configuremake && make installwhere repmgr && sudo -u postgres repmgr --version
主库 postgres 配置
配置 postgresql.conf
listen_addresses = '*'
- repmgr 相关
shared_preload_libraries = 'repmgr'
- wal 设置,详细参考 PostgreSQL 设置日志传送后备服务器
- 参考
- 日志设置
- 参考
- 从库特有设置
配置 pg_hba.conf
- 配置 repmgr 用户和数据库
psql postgresCREATE USER repmgr WITH SUPERUSER LOGIN PASSWORD '<passwd>';CREATE DATABASE repmgr OWNER repmgr;
配置 repmgr 管理 postgresql 集群
- 根据当前系统管理 postgresql 的方式来修改默认指令
- 查看当前的服务指令
repmgr -f ~/repmgr/repmgr.conf node service --list-actions- 改由
pg_ctl管理,禁用 brew services 自动重启(keepalive)以免影响主备切换 brew services stop postgresql@15brew services info postgresql@15brew services list | grep postgresql- 修改 KeepAlive 的值为 false
vim /opt/homebrew/opt/postgresql@15/homebrew.mxcl.postgresql@15.plist- 保持
postgresql开机自动启动 vim ~/Library/LaunchAgents/com.repmgr.postgresql.plistlaunchctl load ~/Library/LaunchAgents/com.repmgr.postgresql.plistpg_ctl status -D /opt/homebrew/var/postgresql@15sudo -u postgres repmgr -f /var/lib/postgresql/repmgr/repmgr.conf node service --list-actions- centos
OS X
ubuntu/debian
部分指令需要 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/15ln -s /usr/lib/postgresql/15/bin /usr/local/postgresql/15/binls -al /usr/local/postgresql/15/bin
- os x
sudo mkdir -p /usr/local/postgresql/15sudo 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/repmgrsudo 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 postgrespsql -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 postgresCREATE 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 patroniapt install python3-systemdsystemd-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 变量
- 如果是在容器内运行, 需要从环境变量中读取配置则在
patroni_env.conf进行配置 - https://patroni.readthedocs.io/en/latest/ENVIRONMENT.html
vim /etc/patroni/patroni_env.conf
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>可以指定特定类型的成员组执行操作leaderprimarystandby-leaderreplica- 默认为
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=notify为type=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 内所有进程的消息
- Author:白鸟3
- URL:https://blog.kun2peng.top/datasci/postgresql_ha_cluster
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
