数据库教程FGMT61-PostgreSQL高可用集群项目实战之Repmgr
## 前言与大纲介绍
数据库高可用是企业核心业务架构中不可缺少的一环,业务系统持续运行的底层依赖就是数据库能够在硬件故障、操作系统异常、数据库进程崩溃等场景下快速完成故障转移,减少业务中断时长。传统手工搭建主从流复制架构,只能实现数据同步,一旦主节点宕机,需要运维人员手动登录备库执行提升操作,修改业务连接地址,整个过程耗时较长,人为操作失误风险高,无法满足生产环境自动化故障切换的需求。
Repmgr作为PostgreSQL生态内成熟的开源复制管理工具,基于原生流复制能力进行封装扩展,提供集群节点管理、主备状态监控、手动主备切换、自动故障转移、节点重新加入集群等完整能力,广泛应用于中小型业务PostgreSQL高可用架构落地。风哥教程本文围绕Repmgr高可用集群项目完整落地过程展开,从底层原理拆解,到操作系统环境初始化、数据库部署、集群初始化、主备切换演练、故障模拟、日常运维命令,完整覆盖生产落地全流程。
风哥教程本文内容大纲如下:第一部分为理论知识,讲解PostgreSQL流复制底层原理、Repmgr核心组件、集群节点角色、选举机制、故障切换逻辑,对比Repmgr与其他高可用方案的适用场景;第二部分为项目实战,包含操作系统环境准备、系统内核与资源参数调优、数据库软件部署、主节点数据库参数配置、备节点基础配置、使用repmgr进行备库克隆、集群注册、见证节点部署、手动主备切换、模拟主库故障触发自动故障转移、故障节点修复后重新加入集群、集群日常运维管理、HAProxy读写分离接入;最后一部分为项目总结,梳理生产环境上线检查清单、风险点与运维注意事项。本套风哥教程面向数据库运维工程师、DBA、数据库架构人员,所有实战操作基于两台核心主机fgedu-net-cn1、fgedu-net-cn2,配套见证节点,服务器规格统一为64G内存、8CPU,数据库实例名fgedudb,数据库用户fgedu,数据存放路径统一为/fgedudb。
## 理论部分
### 1. PostgreSQL流复制基础原理
PostgreSQL原生流复制是Repmgr高可用架构的底层基石,流复制的核心是WAL(预写日志)机制。数据库所有数据修改操作不会直接写入数据文件,优先写入WAL日志段文件,WAL日志记录了事务的所有变更细节,事务提交成功的判定标准是WAL日志持久化落盘。主节点产生WAL日志之后,通过网络实时发送给备节点,备节点持续接收WAL日志,在本地回放,保证备节点数据与主节点保持一致。
流复制分为物理流复制与逻辑流复制,Repmgr高可用集群基于**物理流复制**搭建。物理流复制复制的是数据库底层数据块,备库是主库的完整物理副本,备库处于持续恢复状态,只能提供只读查询,不支持写入。物理流复制支持同步复制与异步复制两种模式。异步复制模式下,主库提交事务不需要等待备库WAL接收确认,主库性能更好,但极端场景主库宕机,存在少量WAL日志未同步,出现数据丢失风险;同步复制模式,主库事务提交必须等待至少一台备库接收并持久化WAL日志,数据一致性更强,但是会带来主库写入性能损耗,适合金融类对数据零丢失要求严格的业务。
流复制工作流程:主节点启动WAL sender进程,监听网络连接;备节点启动WAL receiver进程,主动连接主节点,建立流复制通道;备节点持续接收WAL日志写入本地WAL文件,启动startup进程持续回放日志;备库持续追赶主库的WAL日志位置,LSN(日志序列号)用来标记WAL日志位置,集群判断主备数据同步状态、判断节点优先级,全部依赖LSN数值。风哥 itpux-com
### 2. Repmgr核心组件介绍
Repmgr分为两大核心模块:repmgr命令行工具与repmgrd守护进程。
repmgr是交互式命令行工具,运维人员通过该命令完成集群节点注册、备库克隆、手动切换、查看集群状态、节点重新加入集群等运维操作,所有集群管理操作都依靠repmgr命令执行。
repmgrd是后台常驻守护进程,是实现自动故障转移的核心。该进程持续监控集群所有节点状态,定时探测节点连通性、数据库进程状态、WAL同步状态。当主节点故障,repmgrd会按照预设选举规则,从存活备节点中选举出新主,自动执行备库提升操作,更新集群元数据,完成故障转移。如果不启动repmgrd,集群仅支持手动切换,无法自动故障转移。
Repmgr集群支持三类节点角色:
1. 主节点(primary):集群写入唯一入口,生成WAL日志,向备节点推送流复制日志,集群内仅存在一个主节点。
2. 备节点(standby):接收主节点WAL日志回放,对外只读。主节点故障时,备节点参与选举,有机会提升为新主。集群支持一主多备架构。
3. 见证节点(witness):见证节点不存储业务数据,不参与业务读写,不参与WAL日志复制。作用仅为参与集群投票,解决脑裂问题。当集群网络分裂,主备之间网络中断,两边各自认为对方宕机,容易出现双主(脑裂)。增加见证节点,集群投票采用多数派机制,只有获得超过半数投票的节点才能成为主节点,避免脑裂。见证节点资源消耗极低,可以部署在独立主机。
### 3. Repmgr选举机制与故障切换逻辑
Repmgr节点选举存在优先级判定顺序,优先级从高到低依次为LSN、node priority、node ID。
第一优先级:LSN。WAL日志位置越接近原主库的备节点,优先被选举为新主。优先选择数据最完整的节点,最大限度减少数据丢失。
第二优先级:node priority。在配置文件中手动设置节点优先级数值,数值越大优先级越高。当多个备节点LSN差距很小,优先选择优先级数值高的节点。运维人员可以根据服务器硬件位置、机房位置设置优先级,优先选择机房A的服务器升主。
第三优先级:node ID。当LSN、priority全部一致,node ID更小的节点优先当选。
切换分为两种类型:手动切换switchover与自动故障转移failover。
switchover:计划内停机维护场景,业务低峰期执行,原主节点正常运行,数据完整同步。执行切换命令后,Repmgr会先阻塞主库写入,等待WAL全部同步至备库,再将备库提升为主,原主库自动降级为备库,整个切换过程数据零丢失,属于可控操作。
failover:非计划故障,主节点崩溃、主机断电、数据库进程异常崩溃。repmgrd探测主节点不可达,触发自动故障转移,选举新主。原主节点此时状态未知,故障修复之后,原主不能直接加入集群,需要使用repmgr rejoin命令,将原主重新转换为备节点加入集群。
集群脑裂防护依靠多数派投票机制。集群总节点数N,存活节点投票数大于N/2,才允许选举新主。例如集群1主1备,总节点数2。主备网络中断,两个节点各自投票,投票数都是1,不满足大于半数,不会触发切换。此时增加见证节点,总节点3个。主节点宕机,备节点+见证节点,合计2票,超过半数,可以正常选举新主。
### 4. Repmgr高可用方案对比
PostgreSQL高可用方案有多个选择,Patroni、Repmgr、PGpool-II,不同方案底层实现不同。
Patroni依靠etcd分布式存储保存集群元数据,架构组件多,部署复杂度高,适合大规模多节点集群;Repmgr架构轻量化,无额外分布式存储依赖,集群元数据保存在数据库内部表,部署简单,运维门槛低,适合中小型业务。
PGpool-II侧重连接池、读写分离,故障转移能力偏弱,一般不会单独作为高可用方案。
Repmgr优势:原生流复制深度适配,架构简单,上手门槛低;劣势:大规模集群的元数据管理能力弱于Patroni,自动故障转移依赖repmgrd进程稳定运行。风哥教程 113257174
### 5. 集群规划与资源参数设计
本套风哥教程项目规划:
主机1:fgedu-net-cn1,初始角色primary,64G内存,8CPU
主机2:fgedu-net-cn2,初始角色standby,64G内存,8CPU
额外部署见证节点,用于投票防脑裂。
数据库实例:fgedudb,数据库用户:fgedu,数据目录:/fgedudb/data
数据库参数基于64G内存8CPU规格规划:
shared_buffers = 16GB
effective_cache_size = 48GB
maintenance_work_mem = 2GB
work_mem = 64MB
wal_buffers = 1GB
max_wal_size = 4GB
min_wal_size = 1GB
max_connections = 1000
wal_level = replica
max_wal_senders = 10
wal_keep_size = 16GB
hot_standby = on
hot_standby_feedback = on
参数说明:shared_buffers分配服务器物理内存的25%左右,effective_cache_size设置为物理内存75%,用于查询优化器评估索引代价;wal_level设置replica开启流复制所需WAL日志信息;max_wal_senders限制最大WAL发送进程数量,预留足够进程给备节点;wal_keep_size保留一定WAL段文件,防止备库断连一段时间后WAL被清理,备库无法继续追赶。
操作系统层面,64G内存主机需要调整内核参数,包含内存overcommit、文件句柄数、进程最大数量,关闭SELinux,关闭防火墙或者放行PostgreSQL、Repmgr通信端口。
## 实战操作部分
### 1. 操作系统环境准备(fgedu-net-cn1、fgedu-net-cn2)
#### 1.1 主机名与hosts解析配置
集群所有节点必须能够互相解析主机名,所有节点执行hosts配置,修改/etc/hosts文件。
```
cat >> /etc/hosts <<EOF
192.168.1.101 fgedu-net-cn1
192.168.1.102 fgedu-net-cn2
192.168.1.103 fgedu-net-cn3
EOF
```
执行hostname确认主机名:
```
hostname
```
输出结果:fgedu-net-cn1,另一台主机输出fgedu-net-cn2。
所有节点之间配置免密ssh,repmgr克隆备库、节点通信依赖ssh免密。
```
# fgedu用户生成密钥
su - fgedu
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
# 分发公钥到所有节点
ssh-copy-id fgedu@fgedu-net-cn1
ssh-copy-id fgedu@fgedu-net-cn2
ssh-copy-id fgedu@fgedu-net-cn3
```
测试免密登录,在fgedu-net-cn1执行ssh fgedu@fgedu-net-cn2,不需要输入密码即可登录。
#### 1.2 系统内核参数优化
编辑/etc/sysctl.conf,写入针对64G内存服务器参数:
```
kernel.shmmax = 68719476736
kernel.shmall = 16777216
kernel.shmmni = 4096
kernel.sem = 50100 64128000 5010 1280
fs.file-max = 1048576
net.ipv4.ip_local_port_range = 1024 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
vm.swappiness = 10
vm.overcommit_memory = 0
```
生效内核参数:
```
sysctl -p
```
修改资源限制文件/etc/security/limits.conf,设置fgedu用户资源:
```
fgedu soft nofile 1048576
fgedu hard nofile 1048576
fgedu soft nproc 65536
fgedu hard nproc 65536
```
关闭SELinux:
```
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
```
防火墙放行端口,数据库默认5432端口,repmgr通信依赖数据库端口:
```
# firewalld系统
firewall-cmd --add-port=5432/tcp --permanent
firewall-cmd --reload
```
#### 1.3 创建目录与用户
创建操作系统用户fgedu,创建/fgedudb目录,修改权限:
```
useradd fgedu
echo "fgedu@123" | passwd --stdin fgedu
mkdir -p /fgedudb /fgedudb/data /fgedudb/archive /fgedudb/soft
chown -R fgedu:fgedu /fgedudb
chmod -R 700 /fgedudb
```
切换fgedu用户操作,后续所有数据库操作,全部使用fgedu用户执行。风哥数据库教程 itpux-com
### 2. 数据库软件部署(fgedu-net-cn1、fgedu-net-cn2)
数据库源码包上传至/fgedudb/soft目录,所有节点编译安装数据库软件。
```
su - fgedu
cd /fgedudb/soft
# 解压源码包
tar zxvf postgresql-src.tar.gz
cd postgresql-src
# 编译配置
./configure --prefix=/fgedudb/pgsql --with-ossp-uuid --with-readline --with-zlib
# 编译安装
make -j8
make install
```
配置环境变量,编辑fgedu用户家目录.bash_profile
```
cat >> ~/.bash_profile <<EOF
export PGHOME=/fgedudb/pgsql
export PGDATA=/fgedudb/data
export PATH=\$PGHOME/bin:\$PATH
export PGUSER=fgedu
export PGPORT=5432
EOF
source ~/.bash_profile
# 验证版本
psql --version
```
编译安装repmgr软件,同样源码编译,安装到数据库相同目录。
```
cd /fgedudb/soft
tar zxvf repmgr-src.tar.gz
cd repmgr-src
./configure --with-pgconfig=/fgedudb/pgsql/bin/pg_config
make -j8
make install
```
验证repmgr命令是否可用:
```
repmgr --version
```
### 3. fgedu-net-cn1主节点数据库初始化与参数配置
#### 3.1 数据库初始化
```
su - fgedu
initdb -D /fgedudb/data -U fgedu -W -E UTF8 --lc-collate=C --lc-ctype=C
```
输入数据库超级用户密码,完成实例初始化。
#### 3.2 修改postgresql.conf参数
编辑/fgedudb/data/postgresql.conf,修改核心参数:
```
listen_addresses = '*'
port = 5432
max_connections = 1000
shared_buffers = 16GB
effective_cache_size = 48GB
maintenance_work_mem = 2GB
work_mem = 64MB
wal_buffers = 1GB
max_wal_size = 4GB
min_wal_size = 1GB
wal_level = replica
max_wal_senders = 10
wal_keep_size = 16GB
hot_standby = on
hot_standby_feedback = on
archive_mode = on
archive_command = 'cp %p /fgedudb/archive/%f'
log_timezone = 'Asia/Shanghai'
timezone = 'Asia/Shanghai'
```
修改pg_hba.conf,增加流复制与repmgr访问权限,允许集群所有节点fgedu用户连接:
```
host all fgedu 192.168.1.0/24 scram-sha-256
host replication fgedu 192.168.1.0/24 scram-sha-256
```
启动主节点数据库:
```
pg_ctl -D /fgedudb/data start
```
登录数据库,创建repmgr所需元数据数据库与repmgr用户:
```
psql -U fgedu -d postgres
CREATE USER repmgr WITH SUPERUSER PASSWORD 'repmgr@123';
CREATE DATABASE repmgrdb OWNER repmgr;
\q
```
#### 3.3 主节点repmgr.conf配置
创建repmgr配置文件目录,编写/fgedudb/repmgr.conf
```
node_id=1
node_name='fgedu-net-cn1'
conninfo='host=fgedu-net-cn1 user=repmgr dbname=repmgrdb password=repmgr@123 port=5432'
data_directory='/fgedudb/data'
repmgrd_pid_file='/fgedudb/repmgrd.pid'
repmgrd_log_file='/fgedudb/repmgrd.log'
failover='automatic'
promote_command='repmgr standby promote -f /fgedudb/repmgr.conf'
follow_command='repmgr standby follow -f /fgedudb/repmgr.conf --dbname=repmgr'
node_priority=100
```
注册主节点到Repmgr集群:
```
repmgr -f /fgedudb/repmgr.conf primary register
```
查看集群节点状态:
```
repmgr -f /fgedudb/repmgr.conf cluster show
```
输出中可以看到node_id=1节点角色primary。网上搜索风哥教程可以学习全套数据库教程
### 4. fgedu-net-cn2备节点克隆与集群注册
备节点fgedu-net-cn2,数据库软件已经完成编译安装,不需要执行initdb初始化,使用repmgr standby clone直接从主库克隆全量数据。
```
su - fgedu
# 清理空数据目录
rm -rf /fgedudb/data/*
# 执行克隆,从fgedu-net-cn1主库克隆
repmgr -h fgedu-net-cn1 -U repmgr -d repmgrdb -f /fgedudb/repmgr.conf standby clone
```
克隆完成之后,修改备节点repmgr.conf配置文件
```
node_id=2
node_name='fgedu-net-cn2'
conninfo='host=fgedu-net-cn2 user=repmgr dbname=repmgrdb password=repmgr@123 port=5432'
data_directory='/fgedudb/data'
repmgrd_pid_file='/fgedudb/repmgrd.pid'
repmgrd_log_file='/fgedudb/repmgrd.log'
failover='automatic'
promote_command='repmgr standby promote -f /fgedudb/repmgr.conf'
follow_command='repmgr standby follow -f /fgedudb/repmgr.conf --dbname=repmgr'
node_priority=90
```
启动备库数据库:
```
pg_ctl -D /fgedudb/data start
```
将备节点注册进入集群:
```
repmgr -f /fgedudb/repmgr.conf standby register
```
再次查看集群状态:
```
repmgr -f /fgedudb/repmgr.conf cluster show
```
此时集群包含两个节点,node1为主库,node2备库,状态正常。
查看流复制同步状态,在主库执行:
```
psql -U fgedu -d postgres
SELECT pid,usename,application_name,state,write_lsn,replay_lsn FROM pg_stat_replication;
\q
```
### 5. 见证节点部署(fgedu-net-cn3)
见证节点不需要业务数据目录,只需要数据库软件、repmgr软件,创建repmgr数据库,用于集群投票。见证节点repmgr.conf配置:
```
node_id=3
node_name='fgedu-net-cn3'
conninfo='host=fgedu-net-cn3 user=repmgr dbname=repmgrdb password=repmgr@123 port=5432'
data_directory='/fgedudb/data'
repmgrd_pid_file='/fgedudb/repmgrd.pid'
repmgrd_log_file='/fgedudb/repmgrd.log'
failover='automatic'
node_priority=0
```
见证节点注册命令:
```
repmgr -f /fgedudb/repmgr.conf witness register -h fgedu-net-cn1
```
注册完成,集群总节点3个,满足多数派投票机制。启动所有节点repmgrd守护进程:
```
# 所有节点执行后台启动repmgrd
repmgrd -f /fgedudb/repmgr.conf &
```
查看repmgrd日志文件,确认守护进程正常运行:
```
tail -f /fgedudb/repmgrd.log
```
### 6. 计划内手动主备切换 switchover
计划内切换,当前主库fgedu-net-cn1,备库fgedu-net-cn2。业务低峰执行switchover。在原主节点执行切换命令:
```
repmgr -f /fgedudb/repmgr.conf standby switchover
```
执行过程:Repmgr首先确认集群所有节点健康状态,阻塞主库写入,等待所有WAL日志同步到备库,完成之后,提升fgedu-net-cn2为新主,原主fgedu-net-cn1自动转为备节点。
切换完成,查看集群状态验证角色变更:
```
repmgr -f /fgedudb/repmgr.conf cluster show
```
登录新主库,验证数据库写入,创建测试表:
```
psql -U fgedu -d postgres
CREATE TABLE test_tbl(id int);
INSERT INTO test_tbl VALUES(1);
SELECT * FROM test_tbl;
\q
```
登录原主(现在备库),查询数据,备库只读,不能写入。
```
psql -U fgedu -d postgres
SELECT * FROM test_tbl;
```
尝试insert写入会报错,符合备库只读特性。风哥 itpux-com
### 7. 模拟主库故障,自动故障转移failover演练
当前集群主节点为fgedu-net-cn2,模拟主节点宕机。在fgedu-net-cn2强制停止数据库进程,模拟主机断电场景:
```
pg_ctl -D /fgedudb/data stop -m immediate
```
观察repmgrd日志,等待故障检测超时,repmgrd识别主节点不可访问,集群启动投票机制,fgedu-net-cn1备节点与见证节点投票超过半数,触发failover,fgedu-net-cn1提升为新主节点。
等待30秒后,在fgedu-net-cn1执行查看集群状态:
```
repmgr -f /fgedudb/repmgr.conf cluster show
```
可以看到fgedu-net-cn1角色变为primary,fgedu-net-cn2标记为failed。
此时fgedu-net-cn2主机数据库已经停止,需要修复故障,重新加入集群。启动fgedu-net-cn2数据库:
```
pg_ctl -D /fgedudb/data start
```
此时原主节点数据库启动后,不能直接加入集群,需要执行rejoin操作,将其转为备节点跟随新主:
```
repmgr -f /fgedudb/repmgr.conf standby rejoin
```
执行完成,再次查看集群状态,fgedu-net-cn2恢复为备节点,集群恢复完整一主一备+见证架构。上51CTO搜索风哥可以学习全套数据库教程
### 8. Repmgr集群常用运维管理命令
查看集群整体状态:
```
repmgr -f /fgedudb/repmgr.conf cluster show
```
查看集群节点事件记录,所有切换、故障事件会记录:
```
repmgr -f /fgedudb/repmgr.conf event list
```
查看节点WAL复制状态:
```
repmgr -f /fgedudb/repmgr.conf node status
```
手动提升备库(紧急手动操作,非计划场景慎用):
```
repmgr -f /fgedudb/repmgr.conf standby promote
```
备库跟随新主:
```
repmgr -f /fgedudb/repmgr.conf standby follow
```
取消节点注册,从集群移除节点:
```
repmgr -f /fgedudb/repmgr.conf node unregister
```
停止repmgrd进程:
```
pkill repmgrd
```
### 9. HAProxy接入实现读写分离
业务层不能直接感知数据库主节点IP变化,因此搭配HAProxy代理数据库流量,实现读写分离,自动路由写入流量到主节点,查询流量分发到备节点。HAProxy部署在独立代理主机。
HAProxy配置文件haproxy.cfg核心片段:
```
listen pg_write
bind 0.0.0.0:5432
mode tcp
option tcp-check
server pg_master fgedu-net-cn1:5432 check port 5432
listen pg_read
bind 0.0.0.0:5433
mode tcp
option tcp-check
server pg_master fgedu-net-cn1:5432 check port 5432
server pg_slave fgedu-net-cn2:5432 check port 5432 backup
```
HAProxy会检测后端节点连通性,当主节点发生故障转移,HAProxy自动识别节点状态,将写端口流量切换到新主节点。业务程序连接HAProxy 5432端口执行写操作,5433端口执行读查询。
测试代理连通性:
```
psql -h 代理IP -p 5432 -U fgedu -d postgres
psql -h 代理IP -p 5433 -U fgedu -d postgres
```
执行主备切换,再次测试连接,验证写端口自动指向新主节点。风哥教程 113257174
### 10. 集群启停规范操作
集群停止操作顺序:
1. 停止业务应用,停止HAProxy
2. 所有节点停止repmgrd守护进程
3. 先停止备节点数据库,最后停止主节点数据库
```
# 备库执行
pg_ctl -D /fgedudb/data stop
# 主库执行
pg_ctl -D /fgedudb/data stop
```
集群启动顺序:
1. 启动主节点数据库
2. 启动备节点数据库
3. 所有节点启动repmgrd守护进程
4. 启动HAProxy,启动业务应用
启动完成执行cluster show检查集群全部节点状态。
## 风哥针对本文总结
风哥教程本文完整落地Repmgr高可用集群项目,从底层流复制原理、Repmgr组件、选举机制,到操作系统调优、数据库部署、集群初始化、手动切换、故障模拟自动转移、故障节点修复、HAProxy读写分离全部进行实操演练。在生产环境上线这套架构,有多个关键点需要重点把控。
第一,生产环境必须部署见证节点,依靠多数派投票机制,防止网络分区场景发生脑裂,脑裂会出现双主节点,造成数据错乱,是高可用架构最高风险点。第二,repmgrd守护进程是自动故障转移核心,必须配置开机自启,同时增加进程监控告警,一旦repmgrd进程异常退出,集群失去自动故障转移能力,只能人工处理故障。第三,上线前必须完整演练故障场景,模拟主库崩溃、网络中断、服务器重启,验证故障转移耗时、业务中断时长,不能只做计划内switchover演练。第四,WAL日志归档策略需要配套搭建,WAL归档可以用于时间点恢复,即使集群高可用,仍然需要定期全量备份+WAL归档,集群高可用不等于数据备份。第五,监控体系需要覆盖数据库进程、WAL延迟、repmgr集群状态、repmgrd进程状态,一旦WAL延迟持续走高,及时告警处理,避免备库WAL日志被清理,导致备库需要重新全量克隆。
Repmgr架构轻量化,运维成本低,适合中小型业务PostgreSQL高可用落地。运维人员日常要熟悉repmgr全套运维命令,定期查看集群事件日志,掌握故障节点修复rejoin操作。集群变更、版本升级,全部要在业务低峰执行switchover计划切换,保证业务平稳无感知。上51CTO搜索风哥可以学习全套数据库教程
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9664900/viewspace-3186255/ ,如需转载,请注明出处,否则将追究法律责任。