文章目录
一、节点说明
1、相关软件
| IP | 主机名 | 部署软件 |
|---|---|---|
| 192.168.10.102 | node02 | postgresql,keepalived,repmgr |
| 192.168.10.103 | node03 | postgresql,keepalived,repmgr |
| 192.168.10.110 | vip |
二、软件下载
PostgreSQL:PostgreSQL: File Browser
Keepalived:Keepalived for Linux
repmgr:repmgr - Replication Manager for PostgreSQL clusters
本文使用:
postgresql-16.10.tar.gz
keepalived-2.2.4.tar.gz
repmgr-5.5.0.tar.gz
三、安装PostgreSQL
参考本人此篇文章:Linux软件安装 ------ PostgreSQL集群安装(主从复制集群)
上文是采用postgreSQL原生的流式复制搭建的主从集群,
本文是在原生流式复制的基础上做高可用搭建。
四、安装repmgr
1、前置准备
(1)安装依赖(两台节点)
shell
# 安装依赖包
yum install -y libcurl-devel json-c-devel openssl-devel \
postgresql16-devel libevent-devel ncurses-devel libedit-devel \
libselinux-devel libxslt-devel perl-devel systemd-devel libxml2-devel \
krb5-devel flex bison popt-devel
2、编译安装(两台节点)
shell
# 使用postgres用户
su - postgres
# 解压
tar -zxvf repmgr-5.5.0.tar.gz
cd /opt/module/pgsql16/repmgr-5.5.0
# 编译安装
./configure PG_CONFIG=/opt/module/pgsql16/pgsql/bin/pg_config # 这里是pg数据库bin目录下的执行文件
make && make install
# 检查版本号,验证是否安装成功
repmgr --version
3、配置repmgr
(1)配pgsql.conf(配置主节点即可,从节点需要用repmgr重新同步)
shell
# 配置postgresql.conf
vim $PGDATA/postgresql.conf
# 修改
shared_preload_libraries = 'repmgr'
# 添加IP段
vi $PGDATA/pg_hba.conf
# 这允许repmgr用户进行流复制连接,并采用 scram-sha-256 加密认证。
host replication repmgr 192.168.10.102/32 scram-sha-256
host replication repmgr 192.168.10.103/32 scram-sha-256
# 这允许repmgr用户连接repmgr数据库进行元数据管理,并采用 scram-sha-256 加密认证。
host repmgr repmgr 192.168.10.102/32 scram-sha-256
host repmgr repmgr 192.168.10.103/32 scram-sha-256
# 重启主库
pg_ctl -D $PGDATA -l $PGHOME/logfile restart
(2)配置repmgr免密登录(两台节点)
shell
# 需要创建
vim /home/postgres/.pgpass
# hostname:port:database:username:password
192.168.10.102:5432:replication:repmgr:repmgr
192.168.10.103:5432:replication:repmgr:repmgr
192.168.10.102:5432:repmgr:repmgr:repmgr
192.168.10.103:5432:repmgr:repmgr:repmgr
192.168.10.102:5432:*:postgres:postgres
192.168.10.103:5432:*:postgres:postgres
# 权限必须600
chmod 600 /home/postgres/.pgpass
(3)创建用于同步的用户及数据库(主库)
sql
# 进入pgsql客户端
psql
# 创建repmgr用户,需要超级用户权限
CREATE USER repmgr WITH SUPERUSER LOGIN ENCRYPTED PASSWORD 'repmgr';
# 创建repmgr数据库,所属用户为repmgr用户
CREATE DATABASE repmgr WITH OWNER repmgr;
GRANT ALL PRIVILEGES ON DATABASE repmgr TO repmgr;
(4)repmgr.conf
主库配置
bash
# 这个配置文件是没有的,需要新建,不要放在pgsql数据目录就行
mkdir -p /opt/module/pgsql16/repmgr/
cd /opt/module/pgsql16/repmgr/
vim repmgr.conf
node_id=2 # 节点唯一ID
node_name='node02' # 节点名称
conninfo='host=192.168.10.102 port=5432 user=repmgr dbname=repmgr connect_timeout=2' # 连接信息
data_directory='/opt/module/pgsql16/pgdata' # 数据目录
pg_bindir='/opt/module/pgsql16/pgsql/bin'
repmgr_bindir='/opt/module/pgsql16/pgsql/bin'
use_replication_slots=yes # 使用复制槽,避免WAL日志被过早删除
# repmgrd
repmgrd_service_start_command='repmgrd -f /opt/module/pgsql16/repmgr/repmgr.conf -p /opt/module/pgsql16/repmgr/repmgrd.pid -d' # 开启
repmgrd_service_stop_command='kill `cat /opt/module/pgsql16/repmgr/repmgrd.pid`' # 关闭
promote_command='repmgr standby promote -f /opt/module/pgsql16/repmgr/repmgr.conf --log-to-file' # 提升命令
follow_command='repmgr standby follow -f /opt/module/pgsql16/repmgr/repmgr.conf --log-to-file -W --upstream-node-id=%n' # 跟随命令
# 复制配置
failover=automatic # 故障转移模式
monitor_interval_secs=5 # 监控间隔
connection_check_type=ping # 连接检查类型
reconnect_attempts=3 # 重连尝试次数
reconnect_interval=5 # 重连间隔(秒)
# 日志配置
log_level=INFO # 日志级别
log_file='/opt/module/pgsql16/repmgr/repmgr.log' # 日志文件
log_status_interval=300 # 状态日志间隔
从库配置
bash
# 这个配置文件是没有的,需要新建,不要放在pgsql数据目录就行
mkdir -p /opt/module/pgsql16/repmgr/
cd /opt/module/pgsql16/repmgr/
vim repmgr.conf
node_id=3 # 节点唯一ID
node_name='node03' # 节点名称
conninfo='host=192.168.10.103 port=5432 user=repmgr dbname=repmgr connect_timeout=2' # 连接信息
data_directory='/opt/module/pgsql16/pgdata' # 数据目录
pg_bindir='/opt/module/pgsql16/pgsql/bin'
repmgr_bindir='/opt/module/pgsql16/pgsql/bin'
use_replication_slots=yes # 使用复制槽,避免WAL日志被过早删除
# repmgrd
repmgrd_service_start_command='repmgrd -f /opt/module/pgsql16/repmgr/repmgr.conf -p /opt/module/pgsql16/repmgr/repmgrd.pid -d' # 开启
repmgrd_service_stop_command='kill `cat /opt/module/pgsql16/repmgr/repmgrd.pid`' # 关闭
promote_command='repmgr standby promote -f /opt/module/pgsql16/repmgr/repmgr.conf --log-to-file' # 提升命令
follow_command='repmgr standby follow -f /opt/module/pgsql16/repmgr/repmgr.conf --log-to-file --upstream-node-id=%n' # 跟随命令
# 复制配置
failover=automatic # 故障转移模式
monitor_interval_secs=5 # 监控间隔
connection_check_type=ping # 连接检查类型
reconnect_attempts=3 # 重连尝试次数
reconnect_interval=5 # 重连间隔(秒)
# 日志配置
log_level=INFO # 日志级别
log_file='/opt/module/pgsql16/repmgr/repmgr.log' # 日志文件
log_status_interval=300 # 状态日志间隔
4、添加主从到repmgr集群
(1)添加主库到repmgr(操作主库)
shell
# 添加主库
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf primary register -F
# 启动repmgr
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf daemon start
# 查看repmgr信息
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status

(2)从库同步主库数据(操作从库)
bash
# 停止从库
pg_ctl -D $PGDATA -l $PGHOME/logfile stop
# 先清空从库数据目录
rm -rf /opt/module/pgsql16/pgdata/*
# 检查从库是否具备同步条件
repmgr -h 192.168.10.102 -U repmgr -d repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf standby clone --dry-run
# 同步从库
repmgr -h 192.168.10.102 -U repmgr -d repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf standby clone
# 此时postgresql.auto.conf中显示的是repmgr账号的信息
# primary_conninfo = 'host=192.168.10.102 user=repmgr application_name=''pg-node2'' password=repmgr port=5432'
# 启动从库
pg_ctl -D $PGDATA -l $PGHOME/logfile start
主库从库分别查看同步状态
sql
psql -U repmgr
repmgr=# \x
# 主库查看
repmgr=# select * from pg_stat_replication;
# 从库查看
repmgr=# SELECT * FROM pg_stat_wal_receiver;


同步没问题就可以将从库添加到repmgr
(3)添加从库到repmgr(操作从库)
shell
# 添加从库
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf standby register -F
# 启动repmgr
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf daemon start
# 查看repmgr信息
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status

五、安装keepalived(root用户)
1、编译并安装(两台节点)
shell
# 解压
tar -zxvf keepalived-2.2.4.tar.gz
cd keepalived-2.2.4
# 编译安装
mkdir -p /opt/module/keepalived/
./configure --prefix=/opt/module/keepalived/
make && make install
# 配置环境变量
vim /etc/profile.d/my_env.sh
# KEEPALIVED_HOME
export KEEPALIVED_HOME=/opt/module/keepalived
export PATH=$PATH:$KEEPALIVED_HOME/bin:$KEEPALIVED_HOME/sbin
source /etc/profile.d/my_env.sh
# 检查版本号,验证是否安装成功
keepalived --version
# 创建软链接方便系统调用
ln -s /opt/module/keepalived/sbin/keepalived /usr/sbin/
2、配置keepalived
shell
# 备份原文件
cd /opt/module/keepalived/etc/keepalived
cp keepalived.conf keepalived.conf.bak
vim keepalived.conf
(1)主节点配置
bash
! Configuration File for keepalived
global_defs {
router_id node02
}
vrrp_script check_pg_alived {
script "/opt/module/keepalived/etc/keepalived/check_postgres.sh"
interval 5 # 检查间隔5秒
weight 20 # 优先级降低加减20
fall 2 # 连续2次失败才认为KO
rise 1 # 1次成功就认为恢复
timeout 5 # 脚本执行超时时间
}
vrrp_instance VI_PG {
state BACKUP
# nopreempt # 非抢占模式
interface ens33 # 网络接口(根据实际修改)
virtual_router_id 110 # 虚拟路由ID,各节点配置必须一致
priority 100 # 节点优先级,
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 加入集群密码,需保持一致
}
track_script {
check_pg_alived
}
virtual_ipaddress { # VIP网卡信息
192.168.10.110/24 dev ens33 label ens33:pgvip # VIP地址
}
}
(2)从节点配置
bash
! Configuration File for keepalived
global_defs {
router_id node03
}
vrrp_script check_pg_alived {
script "/opt/module/keepalived/etc/keepalived/check_postgres.sh"
interval 5 # 检查间隔5秒
weight 20 # 优先级降低加减20
fall 2 # 连续2次失败才认为KO
rise 1 # 1次成功就认为恢复
timeout 5 # 脚本执行超时时间
}
vrrp_instance VI_PG {
state BACKUP
# nopreempt # 非抢占模式
interface ens33 # 网卡名
virtual_router_id 110 # 虚拟路由ID,各节点配置必须一致
priority 90 # 节点优先级,抢占模式与权重weight组合使用
advert_int 1 # VRRP通告间隔1秒
authentication {
auth_type PASS
auth_pass 1111 # 加入集群密码,需保持一致
}
track_script {
check_pg_alived
}
virtual_ipaddress { # VIP网卡信息
192.168.10.110/24 dev ens33 label ens33:pgvip # VIP地址
}
}
(3)check_postgres.sh配置(主从一样配置)
bash
# 在两台服务器的 /opt/keepalived/conf 目录下创建脚本
vim /opt/module/keepalived/etc/keepalived/check_postgres.sh
#!/bin/bash
# 1. 检查PostgreSQL服务是否运行
count=`ps -ef | grep postgres | grep -v grep | wc -l`
if [ $count -eq 0 ];then
exit 1 # 服务停止
fi
# 2. 检查数据库连接
if ! su - postgres -c "psql -tAc 'SELECT 1;'" >/dev/null 2>&1; then
exit 1 # 无法连接
fi
# 3. 检查是否是主节点
ROLE=$(su - postgres -c "psql -tAc 'SELECT pg_is_in_recovery();'" 2>/dev/null)
if [ "$ROLE" = "f" ]; then
exit 0 # 主节点
else
exit 1 # 从节点
fi
chmod +x /opt/module/keepalived/etc/keepalived/check_postgres.sh
3、启动
shell
# 启动
keepalived -f /opt/module/keepalived/etc/keepalived/keepalived.conf -D
# 查看进程
ps aux | grep keepalived
# 停止
pkill -TERM keepalived
六、测试验证
1、初始状态验证
shell
# 1. 在node02,node03分别执行,检查VIP位置(应在Node02)
ip addr show ens33 | grep 192.168.10.110
# 或者执行ssh远程命令,应跳转到node02
ssh 192.168.10.110
# 2. 检查repmgr集群状态
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
# 3. 检查流复制状态(在主节点执行)
psql -c "SELECT client_addr, state, sync_state FROM pg_stat_replication;"
# 4. 测试通过VIP连接
psql -h 192.168.10.110 -U postgres -c "SELECT inet_server_addr(), pg_is_in_recovery();"

2、主从复制测试
sql
# 当前主节点node02,到主节点node02操作
psql -h 192.168.10.102 -U postgres -c "CREATE TABLE test_rep2 (id int, name text);"
psql -h 192.168.10.102 -U postgres -c "INSERT INTO test_rep2 VALUES (1, 'Hello from Master');"
# VIP写入
psql -h 192.168.10.110 -U postgres -c "INSERT INTO test_rep2 VALUES (2, 'Hello from VIP');"
# 从库查询
psql -h 192.168.10.103 -U postgres -c "SELECT * FROM test_rep2;"
# 此外,从库是只读状态,进行增删改会报错
psql -h 192.168.10.103 -U postgres -c "INSERT INTO test_rep2 VALUES (2, 'Hello from Slave');"

3、手动主从切换触发VIP漂移
shell
# 当前主节点node02,到从节点node03操作
# 查看当前状态
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
# 从库执行,升级为主节点
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf standby switchover --siblings-follow
# 查看当前状态
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
# 查看 VIP 是否漂移到node03
ip addr show ens33 | grep 192.168.10.110
# 或者执行ssh远程命令,应跳转到node03
ssh 192.168.10.110
# 验证主从复制
# 主库操作
psql -h 192.168.10.103 -U postgres -c "INSERT INTO test_rep2 VALUES (3, 'Repmgr from Master');"
# VIP写入
psql -h 192.168.10.110 -U postgres -c "INSERT INTO test_rep2 VALUES (4, 'Repmgr from VIP');"
# 从库查询
psql -h 192.168.10.102 -U postgres -c "SELECT * FROM test_rep2;"
# 此外,从库是只读状态,进行增删改会报错
psql -h 192.168.10.102 -U postgres -c "INSERT INTO test_rep2 VALUES (5, 'Hello from Slave');"


4、主节点挂掉后VIP漂移与恢复
shell
# 当前主节点为node03
# 停止主节点
pg_ctl -D $PGDATA -l $PGHOME/logfile stop
# 到node02查看repmgr状态,node02已经成为主节点
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
# 查看 VIP 是否漂移到node02
ip addr show ens33 | grep 192.168.10.110
# 或者执行ssh远程命令,应跳转到node02
ssh 192.168.10.110
# 在node03执行,此命令功能重启pgsql并成为node02从节点
repmgr -h 192.168.10.102 -U repmgr -p 5432 -d repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf node rejoin --force-rewind
# 查看当前状态
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
# 验证主从复制
# 主库操作
psql -h 192.168.10.102 -U postgres -c "INSERT INTO test_rep2 VALUES (5, 'Repmgr02 from Master');"
# VIP写入
psql -h 192.168.10.110 -U postgres -c "INSERT INTO test_rep2 VALUES (6, 'Repmgr02 from VIP');"
# 从库查询
psql -h 192.168.10.103 -U postgres -c "SELECT * FROM test_rep2;"
# 此外,从库是只读状态,进行增删改会报错
psql -h 192.168.10.103 -U postgres -c "INSERT INTO test_rep2 VALUES (6, 'Hello from Slave');"




5、小结
shell
# 手动主从切换在从节点执行
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf standby switchover --siblings-follow
# 主节点挂掉发生主从切换在挂掉的节点执行,重启pgsql并成为从节点,-h 指向新的主节点
repmgr -h 192.168.10.103 -U repmgr -p 5432 -d repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf node rejoin --force-rewind
# 查看repmgr状态
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf cluster show
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service status
七、可能发生的问题
1、主节点宕机后主从切换失败


上图可以看见Paused?表示repmgr集群被逻辑暂停了,此时主节点宕机,repmgr集群无法检测psql状态,导致主从切换不过去,生产环境确保Paused? 值为 no
shell
# 从启主节点
pg_ctl -D $PGDATA -l $PGHOME/logfile start
# 立即解除暂停
repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service unpause
# 手动暂停
# repmgr -f /opt/module/pgsql16/repmgr/repmgr.conf service pause
2、手动主从失败

这个问题是系统找不到/opt/module/pgsql16/pgsql/lib 这个目录
shell
# 配置系统环境变量
sudo vim /etc/profile.d/my_env.sh
export PGHOME=/opt/module/pgsql16/pgsql
export PGDATA=/opt/module/pgsql16/pgdata
export PATH=$PATH:$PGHOME/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PGHOME/lib
# 重新加载环境变量
sudo source /etc/profile.d/my_env.sh