PostgreSQL 高可用架构:repmgr 3 节点集群搭建与切换实战(保姆级)!!!
·
📋 本系列第 4 篇 | 上一篇:PostgreSQL 备份恢复:pg_dump、pg_basebackup、增量备份实战
📋 文章信息
• 适用版本:PostgreSQL 15.4 / repmgr 5.4.1
• 部署架构:1 主 2 备(3 节点)
• 部署方式:源码编译安装(生产环境)
• 操作系统:CentOS 7.9 / Rocky Linux 8+
• 统一安装目录:/home/postgres/opt/
🖥️ 第一步:环境规划
1.1 节点规划
| 角色 | 主机名 | IP 地址 | 端口 | 说明 |
|---|---|---|---|---|
| 主节点 | pg-node1 | 192.168.118.10 | 5432 | 初始主库 |
| 备节点 1 | pg-node2 | 192.168.118.11 | 5432 | 热备库 |
| 备节点 2 | pg-node3 | 192.168.118.12 | 5432 | 热备库 |
1.2 目录结构(所有节点统一)
/home/postgres/opt/
├── pgsql/ ← PostgreSQL 安装目录
│ ├── bin/
│ ├── lib/
│ └── include/
├── data/ ← PostgreSQL 数据目录
│ ├── base/
│ ├── pg_wal/
│ └── postgresql.conf
├── repmgr/ ← repmgr 安装目录
│ ├── bin/
│ └── lib/
├── log/ ← 统一日志目录
│ ├── postgresql/
│ └── repmgr/
└── wal_archive/ ← WAL 归档目录
1.3 软件版本
| 软件 | 版本 | 下载地址 |
|---|---|---|
| PostgreSQL | 15.4 | 官方下载 |
| repmgr | 5.4.1 | 官方下载 |
| 操作系统 | CentOS 7.9 | 最小化安装 |
1.4 系统准备(所有节点)
# 1. 创建 postgres 用户和组
sudo groupadd -g 1001 postgres
sudo useradd -u 1001 -g postgres -s /bin/bash -m postgres
# 2. 安装编译依赖
sudo yum install -y gcc gcc-c++ make readline-devel zlib-devel openssl-devel \
libxml2-devel libxslt-devel wget git vim net-tools
# 3. 创建统一目录
sudo mkdir -p /home/postgres/opt/{pgsql,data,repmgr,log/wal_archive}
sudo chown -R postgres:postgres /home/postgres/opt
sudo chmod -R 700 /home/postgres/opt
# 4. 设置环境变量
sudo su - postgres
cat >> ~/.bash_profile << 'EOF'
# PostgreSQL 环境变量
export PGHOME=/home/postgres/opt/pgsql
export PGDATA=/home/postgres/opt/data
export PATH=$PGHOME/bin:$PATH
export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH
# repmgr 环境变量
export REPMGRHOME=/home/postgres/opt/repmgr
export PATH=$REPMGRHOME/bin:$PATH
# 日志目录
export PGLOG=/home/postgres/opt/log/postgresql
EOF
source ~/.bash_profile
✅ 验证环境变量:
echo $PGHOME
# /home/postgres/opt/pgsql
echo $PGDATA
# /home/postgres/opt/data
which postgres
# /home/postgres/opt/pgsql/bin/postgres
📦 第二步:编译安装 PostgreSQL 15.4
2.1 下载源码(所有节点)
cd /tmp
wget https://ftp.postgresql.org/pub/source/v15.4/postgresql-15.4.tar.gz
tar -xzf postgresql-15.4.tar.gz
cd postgresql-15.4
✅ 预期输出:
ls -lh postgresql-15.4.tar.gz
-rw-r--r-- 1 root root 31M Apr 2 10:00 postgresql-15.4.tar.gz
2.2 编译安装
# 配置编译选项(生产环境)
./configure --prefix=/home/postgres/opt/pgsql \
--with-openssl \
--with-libxml \
--with-libxslt \
--enable-thread-safety \
--with-pgport=5432
# 编译(使用所有 CPU 核心)
make -j$(nproc)
# 安装
sudo make install
✅ 预期输出:
configure: creating ./config.status
config.status: creating GNUmakefile
...
make[1]: Entering directory `/tmp/postgresql-15.4/src/backend'
...
/usr/bin/mkdir -p '/home/postgres/opt/pgsql/bin'
/usr/bin/install -c postgres '/home/postgres/opt/pgsql/bin'
2.3 初始化数据库
# 切换到 postgres 用户
sudo su - postgres
# 初始化数据库(指定 UTF-8 编码)
initdb -D /home/postgres/opt/data -E UTF8 --locale=zh_CN.UTF-8
# 创建日志目录
mkdir -p /home/postgres/opt/log/postgresql
✅ 预期输出:
The files belonging to this database system will be owned by user "postgres".
...
Success. You can now start the database server using:
/home/postgres/opt/pgsql/bin/pg_ctl -D /home/postgres/opt/data -l logfile start
🔐 第三步:配置 PostgreSQL
3.1 修改 postgresql.conf(所有节点)
# ==================== 连接设置 ====================
listen_addresses = '*'
port = 5432
max_connections = 200
superuser_reserved_connections = 3
# ==================== 复制配置 ====================
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
hot_standby_feedback = on
wal_keep_size = 2GB
synchronous_commit = on
# ==================== 归档配置 ====================
archive_mode = on
archive_command = 'cp %p /home/postgres/opt/wal_archive/%f'
archive_timeout = 300
# ==================== 日志配置 ====================
logging_collector = on
log_directory = '/home/postgres/opt/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0
log_min_duration_statement = 1000
# ==================== 内存配置(根据实际内存调整) ====================
shared_buffers = 2GB
effective_cache_size = 6GB
work_mem = 64MB
maintenance_work_mem = 512MB
3.2 修改 pg_hba.conf(所有节点)
# ==================== 本地连接 ====================
local all all scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
# ==================== 局域网连接 ====================
host all all 192.168.118.0/24 scram-sha-256
# ==================== repmgr 复制权限(使用 scram-sha-256 加密) ====================
local replication repmgr scram-sha-256
host replication repmgr 192.168.118.10/32 scram-sha-256
host replication repmgr 192.168.118.11/32 scram-sha-256
host replication repmgr 192.168.118.12/32 scram-sha-256
⚠️ 重要:生产环境必须使用 scram-sha-256 加密,不要使用 trust!
3.3 启动 PostgreSQL
# 启动数据库
pg_ctl -D /home/postgres/opt/data -l /home/postgres/opt/log/postgresql/postgresql.log start
# 设置开机启动(systemd)
sudo vim /etc/systemd/system/postgresql-15.service
[Unit]
Description=PostgreSQL 15.4 Database Server
After=network.target
[Service]
Type=forking
User=postgres
Group=postgres
Environment="PGHOME=/home/postgres/opt/pgsql"
Environment="PGDATA=/home/postgres/opt/data"
Environment="PATH=/home/postgres/opt/pgsql/bin:/usr/bin:/sbin:/bin"
ExecStart=/home/postgres/opt/pgsql/bin/pg_ctl -D $PGDATA -l /home/postgres/opt/log/postgresql/postgresql.log start
ExecStop=/home/postgres/opt/pgsql/bin/pg_ctl -D $PGDATA stop
ExecReload=/home/postgres/opt/pgsql/bin/pg_ctl -D $PGDATA reload
PIDFile=/home/postgres/opt/data/postmaster.pid
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable postgresql-15
sudo systemctl start postgresql-15
# 验证服务状态
systemctl status postgresql-15
✅ 预期输出:
● postgresql-15.service - PostgreSQL 15.4 Database Server
Loaded: loaded (/etc/systemd/system/postgresql-15.service; enabled)
Active: active (running) since Wed 2026-04-02 17:00:00 CST
🔗 第四步:配置 SSH 免密登录
4.1 在主节点生成 SSH 密钥
sudo su - postgres
ssh-keygen -t ed25519 -b 512 -C "repmgr_cluster"
✅ 预期输出:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/var/lib/pgsql/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/lib/pgsql/.ssh/id_ed25519.
Your public key has been saved in /var/lib/pgsql/.ssh/id_ed25519.pub.
4.2 复制公钥到所有节点
# 复制到自己的 authorized_keys
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# 复制到其他节点(输入 postgres 用户密码)
ssh-copy-id -i ~/.ssh/id_ed25519.pub postgres@192.168.118.10
ssh-copy-id -i ~/.ssh/id_ed25519.pub postgres@192.168.118.11
ssh-copy-id -i ~/.ssh/id_ed25519.pub postgres@192.168.118.12
✅ 预期输出:
Number of key(s) added: 1
4.3 验证 SSH 免密
ssh postgres@192.168.118.11 "hostname && whoami"
ssh postgres@192.168.118.12 "hostname && whoami"
✅ 预期输出:
pg-node2
postgres
pg-node3
postgres
📦 第五步:编译安装 repmgr 5.4.1
5.1 下载源码(所有节点)
cd /tmp
wget https://repmgr.org/download/repmgr-5.4.1.tar.gz
tar -xzf repmgr-5.4.1.tar.gz
cd repmgr-5.4.1
✅ 预期输出:
ls -lh repmgr-5.4.1.tar.gz
-rw-r--r-- 1 root root 1.2M Apr 2 10:00 repmgr-5.4.1.tar.gz
5.2 编译安装
# 配置编译选项(指定 PostgreSQL 路径)
./configure --prefix=/home/postgres/opt/repmgr \
--pg-bindir=/home/postgres/opt/pgsql/bin \
--pg-libdir=/home/postgres/opt/pgsql/lib \
--pg-includedir=/home/postgres/opt/pgsql/include
# 编译
make -j$(nproc)
# 安装
sudo make install
✅ 预期输出:
configure: creating ./config.status
config.status: creating GNUmakefile
...
/usr/bin/install -c -m 755 repmgr '/home/postgres/opt/repmgr/bin'
/usr/bin/install -c -m 755 repmgrd '/home/postgres/opt/repmgr/bin'
5.3 验证安装
repmgr --version
✅ 预期输出:
repmgr 5.4.1
🔐 第六步:创建 repmgr 用户和数据库
6.1 在主节点(192.168.118.10)执行
sudo su - postgres
# 创建 repmgr 用户(使用强密码)
psql -c "CREATE USER repmgr WITH REPLICATION LOGIN PASSWORD 'R3pMgr@2026!Secure#Prod';"
# 创建 repmgr 数据库
createdb -O repmgr repmgr
# 授予权限
psql -d repmgr -c "GRANT ALL ON DATABASE repmgr TO repmgr;"
# 验证用户创建
psql -c "\du repmgr"
✅ 预期输出:
CREATE ROLE
CREATE DATABASE
GRANT
List of roles
Role name | Attributes
-----------+------------------------------------------------------------
repmgr | Replication
⚙️ 第七步:配置 repmgr
7.1 创建 repmgr 配置文件(所有节点)
sudo su - postgres
vim /home/postgres/opt/repmgr/repmgr.conf
主节点(192.168.118.10)配置:
# ==================== 集群配置 ====================
cluster = pg_ha_cluster
node = 1
node_name = 'pg-node1'
node_type = 'primary'
# ==================== 连接配置 ====================
conninfo = 'host=192.168.118.10 user=repmgr password=R3pMgr@2026!Secure#Prod dbname=repmgr connect_timeout=5'
# ==================== PostgreSQL 路径配置 ====================
pg_bindir = '/home/postgres/opt/pgsql/bin'
pg_data = '/home/postgres/opt/data'
# ==================== 复制配置 ====================
repl_user = 'repmgr'
repl_password = 'R3pMgr@2026!Secure#Prod'
use_replication_slots = 1
# ==================== 日志配置 ====================
log_level = INFO
log_file = '/home/postgres/opt/log/repmgr/repmgr.log'
log_connections = on
# ==================== 监控配置 ====================
monitor_interval_secs = 10
reconnect_interval_secs = 10
ping_interval_secs = 5
ping_timeout_secs = 5
# ==================== 故障切换配置 ====================
failover = 'automatic'
failover_validation_command = '/home/postgres/opt/repmgr/scripts/validate_failover.sh'
# ==================== 备份配置 ====================
backup_method = 'pg_basebackup'
备节点 1(192.168.118.11)配置:
cluster = pg_ha_cluster
node = 2
node_name = 'pg-node2'
node_type = 'standby'
conninfo = 'host=192.168.118.11 user=repmgr password=R3pMgr@2026!Secure#Prod dbname=repmgr connect_timeout=5'
# 其他配置与主节点相同
备节点 2(192.168.118.12)配置:
cluster = pg_ha_cluster
node = 3
node_name = 'pg-node3'
node_type = 'standby'
conninfo = 'host=192.168.118.12 user=repmgr password=R3pMgr@2026!Secure#Prod dbname=repmgr connect_timeout=5'
# 其他配置与主节点相同
7.2 创建日志目录和验证脚本
# 创建日志目录
mkdir -p /home/postgres/opt/log/repmgr
mkdir -p /home/postgres/opt/repmgr/scripts
# 创建故障切换验证脚本
vim /home/postgres/opt/repmgr/scripts/validate_failover.sh
#!/bin/bash
# repmgr 故障切换验证脚本
# 参数:$1 = 新主节点 IP
NEW_PRIMARY=$1
# 检查新主节点是否可连接
/home/postgres/opt/pgsql/bin/psql -h $NEW_PRIMARY -U repmgr -d repmgr -c "SELECT 1;" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$(date): Failover validation successful for $NEW_PRIMARY" >> /home/postgres/opt/log/repmgr/failover_validation.log
exit 0
else
echo "$(date): Failover validation FAILED for $NEW_PRIMARY" >> /home/postgres/opt/log/repmgr/failover_validation.log
exit 1
fi
# 设置权限
chmod +x /home/postgres/opt/repmgr/scripts/validate_failover.sh
chown -R postgres:postgres /home/postgres/opt/repmgr
🚀 第八步:初始化 repmgr 集群
8.1 在主节点注册第一个节点
repmgr primary register --force
✅ 预期输出:
NOTICE: using provided configuration file "/home/postgres/opt/repmgr/repmgr.conf"
NOTICE: connecting to source node "pg-node1" (host=192.168.118.10 port=5432 user=repmgr database=repmgr)
NOTICE: successfully registered primary node "pg-node1" (ID: 1)
INFO: node registered successfully
8.2 在备节点克隆并注册
在节点 2(192.168.118.11)执行:
sudo su - postgres
# 停止 PostgreSQL
pg_ctl -D /home/postgres/opt/data stop
# 克隆主节点数据
repmgr standby clone -h 192.168.118.10 -U repmgr -d repmgr --fast-checkpoint --force
# 注册备节点
repmgr standby register
# 启动 PostgreSQL
pg_ctl -D /home/postgres/opt/data start
✅ 预期输出:
NOTICE: destination directory "/home/postgres/opt/data" provided
INFO: connecting to source node "pg-node1" (host=192.168.118.10 port=5432 user=repmgr database=repmgr)
INFO: executing pg_basebackup
NOTICE: cloning completed
NOTICE: standby node "pg-node2" (ID: 2) successfully registered
INFO: node registered successfully
在节点 3(192.168.118.12)执行相同操作:
sudo su - postgres
pg_ctl -D /home/postgres/opt/data stop
repmgr standby clone -h 192.168.118.10 -U repmgr -d repmgr --fast-checkpoint --force
repmgr standby register
pg_ctl -D /home/postgres/opt/data start
8.3 验证集群状态
repmgr cluster show
✅ 预期输出:
ID | Name | Role | Status | Upstream | Location
----+-------------+---------+---------------+-------------+----------
1 | pg-node1 | primary | * running | | default
2 | pg-node2 | standby | streaming | pg-node1 | default
3 | pg-node3 | standby | streaming | pg-node1 | default
8.4 验证复制状态
psql -c "SELECT client_addr, state, sync_state, replay_lsn FROM pg_stat_replication;"
✅ 预期输出:
client_addr | state | sync_state | replay_lsn
----------------+-----------+------------+------------
192.168.118.11 | streaming | async | 0/3000000
192.168.118.12 | streaming | async | 0/3000000
🔄 第九步:手动切换主备节点(Switchover)
9.1 查看当前集群状态
repmgr cluster show
✅ 预期输出:
ID | Name | Role | Status | Upstream | Location
----+-------------+---------+---------------+-------------+----------
1 | pg-node1 | primary | * running | | default
2 | pg-node2 | standby | streaming | pg-node1 | default
3 | pg-node3 | standby | streaming | pg-node1 | default
9.2 执行手动切换
将主节点从 node1 切换到 node2:
sudo su - postgres
# 执行切换(--siblings-follow 让其他备节点跟随新主)
repmgr standby switchover --siblings-follow
✅ 预期输出:
NOTICE: executing switchover on node "pg-node2" (node 2)
NOTICE: checking switchover prerequisites
NOTICE: checking replication state
NOTICE: promoting standby to primary
NOTICE: demoting primary to standby
NOTICE: stopping primary
NOTICE: waiting for standby to catch up
NOTICE: starting former primary as new standby
NOTICE: switchover successful
INFO: new primary is "pg-node2" (node 2)
9.3 验证切换结果
repmgr cluster show
✅ 预期输出:
ID | Name | Role | Status | Upstream | Location
----+-------------+---------+---------------+-------------+----------
1 | pg-node1 | standby | streaming | pg-node2 | default
2 | pg-node2 | primary | * running | | default
3 | pg-node3 | standby | streaming | pg-node2 | default
验证新主节点可写:
psql -h 192.168.118.11 -U postgres -c "CREATE TABLE switchover_test (id int, created_at timestamp default now());"
psql -h 192.168.118.11 -U postgres -c "INSERT INTO switchover_test (id) VALUES (1);"
psql -h 192.168.118.11 -U postgres -c "SELECT * FROM switchover_test;"
✅ 预期输出:
CREATE TABLE
INSERT 0 1
id | created_at
----+----------------------------
1 | 2026-04-02 17:10:00.123456
验证备节点同步:
psql -h 192.168.118.10 -U postgres -c "SELECT * FROM switchover_test;"
✅ 预期输出:
id | created_at
----+----------------------------
1 | 2026-04-02 17:10:00.123456
⚡ 第十步:配置自动故障切换(Failover)
10.1 启动 repmgrd 守护进程(所有节点)
repmgrd -f /home/postgres/opt/repmgr/repmgr.conf --daemonize
# 验证进程
ps aux | grep repmgrd
✅ 预期输出:
postgres 12345 0.5 0.2 123456 7890 ? Ss 17:00 0:00 repmgrd -f /home/postgres/opt/repmgr/repmgr.conf --daemonize
10.2 查看 repmgrd 日志
tail -f /home/postgres/opt/log/repmgr/repmgr.log
✅ 预期输出:
[2026-04-02 17:00:00] [INFO] repmgrd started
[2026-04-02 17:00:00] [INFO] monitoring cluster "pg_ha_cluster"
[2026-04-02 17:00:00] [INFO] node "pg-node1" (ID: 1) is primary
10.3 测试自动故障切换
模拟主节点故障:
# 在主节点(192.168.118.10)上停止 PostgreSQL
sudo su - postgres
pg_ctl -D /home/postgres/opt/data stop -m fast
在备节点查看日志:
tail -f /home/postgres/opt/log/repmgr/repmgr.log
✅ 预期输出:
[2026-04-02 17:15:00] [WARNING] unable to connect to primary node "pg-node1" (ID: 1)
[2026-04-02 17:15:10] [NOTICE] primary node "pg-node1" (ID: 1) is down
[2026-04-02 17:15:10] [NOTICE] initiating failover
[2026-04-02 17:15:11] [NOTICE] promoting node "pg-node2" (ID: 2) to primary
[2026-04-02 17:15:15] [NOTICE] failover successful
验证新的集群状态:
repmgr cluster show
✅ 预期输出:
ID | Name | Role | Status | Upstream | Location
----+-------------+---------+---------------+-------------+----------
1 | pg-node1 | - | x failed | | default
2 | pg-node2 | primary | * running | | default
3 | pg-node3 | standby | streaming | pg-node2 | default
📊 第十一步:监控和维护
11.1 查看复制延迟
psql -c "SELECT
client_addr,
pg_current_wal_lsn() AS current_lsn,
replay_lsn,
pg_size_pretty(pg_current_wal_lsn() - replay_lsn) AS lag,
state,
sync_state
FROM pg_stat_replication;"
✅ 预期输出:
client_addr | current_lsn | replay_lsn | lag
----------------+-------------+--------------+--------
192.168.118.11 | 0/5000000 | 0/4FFFFC0 | 64 bytes
192.168.118.12 | 0/5000000 | 0/4FFFFC0 | 64 bytes
11.2 添加监控脚本
vim /home/postgres/opt/repmgr/scripts/check_cluster.sh
#!/bin/bash
# repmgr 集群状态检查脚本
REPMGR_BIN=/home/postgres/opt/repmgr/bin/repmgr
REPMGR_CONF=/home/postgres/opt/repmgr/repmgr.conf
LOG_FILE=/home/postgres/opt/log/repmgr/cluster_status.log
# 检查集群状态
CLUSTER_STATUS=$($REPMGR_BIN -f $REPMGR_CONF cluster show 2>&1)
if [ $? -ne 0 ]; then
echo "$(date): ERROR - Cluster check failed" >> $LOG_FILE
echo "$CLUSTER_STATUS" >> $LOG_FILE
exit 1
fi
# 检查是否有 failed 节点
FAILED_COUNT=$(echo "$CLUSTER_STATUS" | grep -c "x failed")
if [ $FAILED_COUNT -gt 0 ]; then
echo "$(date): WARNING - $FAILED_COUNT node(s) failed" >> $LOG_FILE
fi
# 记录正常状态
echo "$(date): OK - Cluster status normal" >> $LOG_FILE
echo "$CLUSTER_STATUS" >> $LOG_FILE
设置定时任务:
crontab -e
# 每 5 分钟检查一次
*/5 * * * * /home/postgres/opt/repmgr/scripts/check_cluster.sh
🔧 第十二步:常见问题排查
12.1 备节点无法连接主节点
问题: could not connect to server: Connection refused
# 1. 检查防火墙
sudo firewall-cmd --add-port=5432/tcp --permanent
sudo firewall-cmd --reload
# 2. 检查 PostgreSQL 是否监听
netstat -tlnp | grep 5432
# 3. 检查 pg_hba.conf
cat /home/postgres/opt/data/pg_hba.conf | grep replication
# 4. 测试连接
psql -h 192.168.118.10 -U repmgr -d repmgr -c "SELECT 1;"
12.2 复制延迟过大
问题: 备节点落后主节点太多
# 1. 增加 WAL 保留
vim /home/postgres/opt/data/postgresql.conf
wal_keep_size = 10GB
# 2. 重启 PostgreSQL
pg_ctl -D /home/postgres/opt/data reload
# 3. 如果落后太多,重新克隆
pg_ctl -D /home/postgres/opt/data stop
repmgr standby clone --force
pg_ctl -D /home/postgres/opt/data start
12.3 脑裂问题
问题: 网络分区导致双主
# 1. 配置见证节点(第四台服务器)
repmgr witness create -h 192.168.118.100 -U repmgr -d repmgr
# 2. 使用 fencing 机制
# 在 repmgr.conf 中添加
fencing_command = '/home/postgres/opt/repmgr/scripts/fence_primary.sh'
12.4 Fencing 脚本示例
sudo vim /home/postgres/opt/repmgr/scripts/fence_primary.sh
#!/bin/bash
# =====================================================
# repmgr Fencing 脚本
# 用途:当检测到脑裂时,强制停止旧主节点,防止双写
# =====================================================
LOG_FILE="/home/postgres/opt/log/repmgr/fencing.log"
PG_CTL="/home/postgres/opt/pgsql/bin/pg_ctl"
PG_DATA="/home/postgres/opt/data"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}
# 检查当前节点是否还是主节点
IS_PRIMARY=$($PG_CTL status -D $PG_DATA | grep -c "server is running")
if [ $IS_PRIMARY -eq 1 ]; then
# 检查是否有复制连接(如果有备节点连接,说明不是脑裂)
REPLICATION_COUNT=$(psql -t -c "SELECT count(*) FROM pg_stat_replication;" 2>/dev/null | tr -d ' ')
if [ -z "$REPLICATION_COUNT" ] || [ "$REPLICATION_COUNT" -eq 0 ]; then
# 没有备节点连接,可能是脑裂,立即停止服务
log_message "WARNING: No replication connections detected, possible split-brain. Stopping PostgreSQL..."
# 立即停止 PostgreSQL(不等待事务完成)
$PG_CTL stop -D $PG_DATA -m immediate
if [ $? -eq 0 ]; then
log_message "SUCCESS: PostgreSQL stopped to prevent split-brain"
exit 0
else
log_message "ERROR: Failed to stop PostgreSQL"
exit 1
fi
else
log_message "INFO: $REPLICATION_COUNT replication connection(s) active, no action needed"
exit 0
fi
else
log_message "INFO: This node is not primary, no fencing required"
exit 0
fi
设置权限:
chmod +x /home/postgres/opt/repmgr/scripts/fence_primary.sh
chown postgres:postgres /home/postgres/opt/repmgr/scripts/fence_primary.sh
测试脚本:
# 手动执行测试
sudo -u postgres /home/postgres/opt/repmgr/scripts/fence_primary.sh
# 查看日志
tail -f /home/postgres/opt/log/repmgr/fencing.log
✅ 预期输出:
2026-04-02 17:45:00 - INFO: This node is not primary, no fencing required
⚠️ 重要说明:
- fencing 是最后手段 - 只在检测到脑裂时触发
- 谨慎使用 - 误触发会导致服务中断
- 配合见证节点 - 单独使用 fencing 风险较高
- 定期测试 - 确保脚本在关键时刻能正常工作
📝 总结
手动切换 vs 自动切换
| 特性 | 手动切换 | 自动切换 |
|---|---|---|
| 安全性 | 高(人工确认) | 中(可能误切换) |
| 响应时间 | 分钟级 | 秒级 |
| 适用场景 | 计划内维护 | 故障应急 |
| 风险 | 低 | 中(脑裂风险) |
| 命令 | repmgr standby switchover |
自动触发 |
生产环境建议
- 使用见证节点 - 防止脑裂(至少 3 节点 +1 见证)
- 配置监控告警 - 复制延迟超过 100MB 自动通知
- 定期演练 - 每季度至少一次切换演练
- 备份策略 - 结合 pg_basebackup + WAL 归档
- fencing 机制 - 防止旧主节点恢复后造成冲突
- 日志轮转 - 配置 log_rotation_age 和 log_rotation_size
📚 系列文章
- PostgreSQL 复制配置参数详解
- PostgreSQL 流复制主从切换
- PostgreSQL 备份恢复实战
- PostgreSQL 高可用:repmgr 搭建与切换(本文)
- PostgreSQL 监控告警:复制延迟超过 100MB 自动通知
- PostgreSQL 性能调优:内存、连接数、WAL 参数配置
更多推荐
所有评论(0)