Skip to content

PostgreSQL 基于 repmgr 的高可用方案

repmgr 是一个功能强大的 PostgreSQL 复制管理和高可用解决方案,它专注于简化主从复制的部署、管理和故障转移过程。repmgr 提供了主从复制的自动监控、故障检测和手动/自动故障转移功能,同时还提供了详细的节点状态报告和复制拓扑可视化。本文将详细介绍如何使用 repmgr 实现 PostgreSQL 的高可用架构,兼顾不同 PostgreSQL 版本和 repmgr 版本的特性差异。

repmgr 架构概述

repmgr 核心组件

repmgr 架构主要由以下组件组成:

  1. repmgrd:repmgr 守护进程,运行在每个 PostgreSQL 节点上,负责监控节点状态和处理故障转移
  2. repmgr CLI:命令行工具,用于管理复制集群、执行故障转移和生成状态报告
  3. PostgreSQL 实例:集群中的主库和从库实例
  4. repmgr 元数据:存储在专用数据库中的集群配置和状态信息

repmgr 工作原理

  1. 集群初始化:在主库上初始化 repmgr 元数据库,注册主库信息
  2. 从库注册:在从库上执行 repmgr 注册命令,连接到主库并创建复制关系
  3. 健康监控:repmgrd 守护进程定期检查本地 PostgreSQL 实例的健康状态,并将状态信息更新到元数据库
  4. 故障检测:repmgrd 通过监控元数据库中的状态信息,检测主库故障
  5. 故障转移:当主库故障时,repmgr 可以手动或自动将一个从库提升为主库
  6. 集群重配置:其他从库会自动重新配置,连接到新的主库

repmgr 与 Patroni 的比较

特性repmgrPatroni
架构复杂度简单较复杂
依赖仅 PostgreSQL分布式一致性存储(etcd/Consul/ZooKeeper)
自动故障转移支持支持
配置管理有限强大
复制拓扑支持级联复制支持
社区活跃度活跃非常活跃
学习曲线平缓较陡峭
适用场景中小型集群大型集群

环境准备

硬件要求

组件最低配置推荐配置
CPU2 核4 核或以上
内存4 GB8 GB 或以上
存储100 GB SSD200 GB NVMe SSD
网络千兆以太网万兆以太网

软件要求

软件版本要求说明
PostgreSQL10 或以上PostgreSQL 13+ 对 repmgr 的支持更好
repmgr5.3 或以上repmgr 5.x 支持 PostgreSQL 10+,repmgr 6.x 支持 PostgreSQL 11+

节点规划

本示例将部署一个包含 3 个节点的 repmgr 集群:

节点角色主机名IP 地址初始角色
PostgreSQL 节点 1pg1192.168.1.20主库
PostgreSQL 节点 2pg2192.168.1.21从库
PostgreSQL 节点 3pg3192.168.1.22从库

安装与配置

安装 PostgreSQL

在所有节点上安装 PostgreSQL

bash
# 在所有节点上执行
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install -y postgresql13 postgresql13-server postgresql13-contrib

初始化 PostgreSQL 数据目录

bash
# 在所有节点上执行
/usr/pgsql-13/bin/postgresql-13-setup initdb

配置 PostgreSQL

修改 postgresql.conf 文件

在所有节点上修改 /var/lib/pgsql/13/data/postgresql.conf 文件,根据 PostgreSQL 版本调整配置:

ini
# 基本配置
listen_addresses = '*'
port = 5432

# 复制配置
# PostgreSQL 10+ 使用 replica,PostgreSQL 13+ 建议使用 logical 以支持更多功能
wal_level = replica
hot_standby = on
max_wal_senders = 10
max_replication_slots = 10
# PostgreSQL 13+ 使用 wal_keep_size 替代 wal_keep_segments
wal_keep_size = 8192

# 连接配置
max_connections = 100

# 性能配置
shared_buffers = 256MB
work_mem = 4MB
maintenance_work_mem = 64MB

修改 pg_hba.conf 文件

在所有节点上修改 /var/lib/pgsql/13/data/pg_hba.conf 文件,添加以下配置:

# 允许 repmgr 用户本地连接
local   repmgr          repmgr                              trust
# 允许 repmgr 用户远程连接
host    repmgr          repmgr          0.0.0.0/0            md5
# 允许复制用户远程连接
host    replication     replicator      0.0.0.0/0            md5
# 生产环境应限制 IP 地址,不建议使用 0.0.0.0/0
# host    all             all             192.168.1.0/24       md5

启动 PostgreSQL 服务

bash
# 在所有节点上执行
systemctl start postgresql-13
systemctl enable postgresql-13

安装 repmgr

在所有节点上安装 repmgr

bash
# 在所有节点上执行
yum install -y repmgr13

配置 repmgr

创建 repmgr 配置文件

在所有节点上创建 /etc/repmgr/13/repmgr.conf 文件,根据 repmgr 版本调整配置:

ini
# 在 pg1 节点上
node_id=1
node_name='pg1'
conninfo='host=pg1 user=repmgr dbname=repmgr port=5432 connect_timeout=2'
data_directory='/var/lib/pgsql/13/data'

# 复制配置
repl_user='replicator'
repl_password='rep-pass'
pg_bindir='/usr/pgsql-13/bin'

# 故障转移配置
# 可以设置为 automatic(自动故障转移)或 manual(手动故障转移)
failover='automatic'
promote_command='/usr/pgsql-13/bin/repmgr standby promote -f /etc/repmgr/13/repmgr.conf --log-to-file'
follow_command='/usr/pgsql-13/bin/repmgr standby follow -f /etc/repmgr/13/repmgr.conf --log-to-file --upstream-node-id=%n'

# 监控配置
monitoring_history='yes'
monitor_interval_secs=2

# 日志配置
log_level='INFO'
log_file='/var/log/repmgr/repmgrd.log'

注意

  • 每个节点的 node_idnode_name 必须唯一
  • conninfo 中的 host 应设置为节点自身的主机名或 IP 地址
  • 生产环境中建议使用手动故障转移,避免误判导致的数据不一致

创建 repmgr 日志目录

bash
# 在所有节点上执行
mkdir -p /var/log/repmgr
chown postgres:postgres /var/log/repmgr

初始化 repmgr 集群

在主库上创建 repmgr 用户和数据库

bash
# 在 pg1 节点上执行
sudo -u postgres psql -c "CREATE ROLE repmgr WITH SUPERUSER LOGIN PASSWORD 'repmgr-pass';"
sudo -u postgres psql -c "CREATE DATABASE repmgr WITH OWNER repmgr;"
sudo -u postgres psql -c "CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'rep-pass';"

初始化 repmgr 元数据库

bash
# 在 pg1 节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf primary register

验证主库注册

bash
# 在 pg1 节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf cluster show

预期输出:

 ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string 
----+------+------+--------+----------+----------+----------+----------+----------------------------------------
 1  | pg1  | primary | * running |          | default  | 100      | 1        | host=pg1 user=repmgr dbname=repmgr port=5432 connect_timeout=2

添加从库到集群

在 pg2 节点上执行基础备份

bash
# 在 pg2 节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf standby clone -h pg1 -U repmgr -d repmgr --copy-external-config-files

启动 pg2 节点的 PostgreSQL 服务

bash
# 在 pg2 节点上执行
systemctl start postgresql-13

在 pg2 节点上注册从库

bash
# 在 pg2 节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf standby register

重复上述步骤添加 pg3 节点

启动 repmgrd 守护进程

创建 repmgrd 系统服务文件

在所有节点上创建 /etc/systemd/system/repmgrd-13.service 文件:

ini
[Unit]
Description=repmgrd - Replication Manager Daemon for PostgreSQL 13
After=syslog.target network.target postgresql-13.service

[Service]
Type=forking
User=postgres
Group=postgres
PIDFile=/var/run/repmgrd-13.pid
ExecStart=/usr/pgsql-13/bin/repmgrd -f /etc/repmgr/13/repmgr.conf --pid-file /var/run/repmgrd-13.pid
KillMode=process
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

启动 repmgrd 服务

bash
# 在所有节点上执行
systemctl daemon-reload
systemctl start repmgrd-13
systemctl enable repmgrd-13

验证 repmgr 集群状态

查看集群状态

bash
# 在任意节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf cluster show

预期输出:

 ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string 
----+------+------+--------+----------+----------+----------+----------+----------------------------------------
 1  | pg1  | primary | * running |          | default  | 100      | 1        | host=pg1 user=repmgr dbname=repmgr port=5432 connect_timeout=2
 2  | pg2  | standby | running | pg1      | default  | 100      | 1        | host=pg2 user=repmgr dbname=repmgr port=5432 connect_timeout=2
 3  | pg3  | standby | running | pg1      | default  | 100      | 1        | host=pg3 user=repmgr dbname=repmgr port=5432 connect_timeout=2

查看节点详情

bash
# 在任意节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf node show

查看复制状态

bash
# 在任意节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf replication status

测试故障转移

模拟主库故障

bash
# 在 pg1 节点上执行
systemctl stop postgresql-13

查看故障转移过程

bash
# 在 pg2 节点上执行
tail -f /var/log/repmgr/repmgrd.log

repmgrd 应该会检测到 pg1 节点故障,并将 pg2 或 pg3 提升为主库。

查看故障转移后的集群状态

bash
# 在任意节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf cluster show

预期输出显示其中一个从库已经被提升为主库,例如:

 ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string 
----+------+------+--------+----------+----------+----------+----------+----------------------------------------
 1  | pg1  | primary | - failed |          | default  | 100      | 1        | host=pg1 user=repmgr dbname=repmgr port=5432 connect_timeout=2
 2  | pg2  | primary | * running |          | default  | 100      | 2        | host=pg2 user=repmgr dbname=repmgr port=5432 connect_timeout=2
 3  | pg3  | standby | running | pg2      | default  | 100      | 2        | host=pg3 user=repmgr dbname=repmgr port=5432 connect_timeout=2

恢复故障节点

修复 pg1 节点的 PostgreSQL 服务

bash
# 在 pg1 节点上执行
systemctl start postgresql-13

重新注册 pg1 节点为从库

bash
# 在 pg1 节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf standby follow -W

查看恢复后的集群状态

bash
# 在任意节点上执行
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf cluster show

pg1 节点应该已经作为从库重新加入集群。

repmgr 高级配置

配置级联复制

repmgr 支持级联复制,可以将从库配置为从另一个从库复制数据,减轻主库的复制压力:

bash
# 在 pg3 节点上执行,从 pg2 复制数据
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf standby clone -h pg2 -U repmgr -d repmgr --copy-external-config-files

配置节点优先级

可以为节点设置不同的优先级,影响故障转移时的主库选举,数值越大优先级越高:

ini
# 在 repmgr.conf 中配置
priority=100  # 主库建议设置较高优先级,从库设置较低优先级

配置自动故障转移延迟

可以配置故障转移延迟,避免因短暂网络波动导致误判:

ini
# 在 repmgr.conf 中配置
connection_check_type='ping'  # 连接检查类型
connection_check_timeout=5  # 连接检查超时时间(秒)
reconnect_attempts=3  # 重连尝试次数
reconnect_interval=5  # 重连间隔时间(秒)
failover_timeout=60  # 故障转移超时时间(秒)

配置监控

repmgr 提供了多种监控方式,便于运维人员实时了解集群状态:

使用 repmgr CLI 生成状态报告

bash
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf cluster show --verbose
sudo -u postgres repmgr -f /etc/repmgr/13/repmgr.conf node status

监控 repmgrd 日志

bash
# 实时查看日志
tail -f /var/log/repmgr/repmgrd.log

# 搜索错误日志
grep -i error /var/log/repmgr/repmgrd.log

集成 Prometheus

repmgr 可以通过 repmgr_exporter 提供 Prometheus 指标,便于集成到监控系统:

bash
git clone https://github.com/ClusterLabs/repmgr_exporter.git
cd repmgr_exporter
go build
sudo ./repmgr_exporter --web.listen-address=:9625 --repmgr.config-file=/etc/repmgr/13/repmgr.conf

repmgr 最佳实践

部署建议

  • 节点数量:建议部署奇数个节点(3、5 等),避免脑裂
  • 硬件配置:主从节点硬件配置尽量一致,避免性能瓶颈
  • 网络配置:使用高速、低延迟的网络连接,尤其是主从节点之间
  • 存储配置:使用可靠的存储设备,如 RAID 10 或分布式存储
  • 操作系统:所有节点使用相同的操作系统版本和配置

监控与告警

  • 监控关键指标:复制延迟、节点状态、连接数、资源使用率等
  • 设置合理的告警阈值:根据业务需求设置合适的告警阈值
  • 监控 repmgrd 日志:及时发现和处理问题
  • 定期生成状态报告:分析集群状态,提前发现潜在问题
  • 集成监控系统:将 repmgr 监控指标集成到现有的监控系统中

备份策略

  • 定期全量备份:使用 pg_basebackup 或第三方工具进行定期全量备份
  • 连续 WAL 归档:配置 WAL 归档到可靠的存储设备,确保可以进行 PITR 恢复
  • 测试恢复流程:定期测试从备份恢复的流程,确保备份可用
  • 备份多个节点:考虑在多个节点上进行备份,提高备份的可靠性

故障转移测试

  • 定期演练:定期进行故障转移演练,验证故障转移流程的正确性
  • 测试场景:主库崩溃、网络故障、存储故障等
  • 记录演练结果:分析演练中发现的问题,持续改进
  • 制定回滚计划:故障转移后如果出现问题,要有明确的回滚计划

安全配置

  • 使用强密码:为 repmgr 和复制用户设置强密码,定期更换
  • 配置适当的 pg_hba.conf:限制访问 IP 地址和用户,不建议使用 0.0.0.0/0
  • 启用 SSL/TLS:加密数据库连接,保护数据传输安全
  • 保护 repmgr 配置文件:修改配置文件权限,避免泄露敏感信息
  • 定期更新系统和软件:及时安装安全补丁,避免已知漏洞

版本升级

  • 测试升级:在测试环境中验证升级过程,确保升级不会导致问题
  • 备份数据:升级前进行全量备份,以便在升级失败时恢复
  • 顺序升级:先升级 repmgr,再升级 PostgreSQL
  • 监控升级过程:密切监控升级过程,及时处理出现的问题

常见问题与解决方案

从库无法连接到主库

问题:从库无法连接到主库进行复制

解决方案

  • 检查网络连接,确保节点之间可以相互通信
  • 检查 pg_hba.conf 配置,确保允许复制用户从从库 IP 地址连接
  • 检查复制用户的密码是否正确
  • 检查主库的 max_wal_senders 和 max_replication_slots 参数是否足够
  • 检查主库的 wal_level 是否设置正确

故障转移失败

问题:主库故障后,repmgr 无法进行故障转移

解决方案

  • 检查 repmgrd 服务是否正在运行
  • 检查故障转移配置是否正确,特别是 promote_command 和 follow_command
  • 查看 repmgrd 日志,分析具体错误原因
  • 确保有足够的从库处于正常状态
  • 检查节点优先级配置,确保有合适的节点可以被提升为主库

复制延迟过高

问题:从库复制延迟过高,影响业务使用

解决方案

  • 检查主库的写入负载,是否过于集中,考虑优化查询或分库分表
  • 检查网络连接,是否存在网络瓶颈,考虑使用更高带宽的网络
  • 调整 wal_keep_size 参数,确保有足够的 WAL 日志供从库复制
  • 考虑使用更快的存储设备,如 NVMe SSD,提高 I/O 性能
  • 检查从库的资源使用率,是否存在 CPU 或内存瓶颈
  • 对于级联复制,考虑调整复制拓扑,减少级联层级

节点状态显示为 "failed"

问题:节点状态显示为 "failed",无法正常参与集群

解决方案

  • 检查该节点的 PostgreSQL 服务是否正在运行
  • 检查网络连接,确保可以连接到该节点
  • 查看 repmgrd 日志,分析具体错误原因
  • 使用 repmgr node rejoin 命令将节点重新加入集群
  • 如果无法重新加入,考虑重新克隆节点

版本差异说明

PostgreSQL 版本差异

PostgreSQL 版本差异说明
10支持基本的流式复制,repmgr 5.x 支持
11增强了复制功能,支持并行查询,repmgr 5.x/6.x 支持
12改进了分区表功能,支持默认分区,repmgr 5.x/6.x 支持
13引入并行 WAL 写入,优化了复制性能,repmgr 5.x/6.x 支持
14改进了从库的 I/O 性能,repmgr 6.x 支持
15增强了逻辑复制功能,repmgr 6.x 支持

repmgr 版本差异

repmgr 版本差异说明
5.x支持 PostgreSQL 10+,提供基本的复制管理和故障转移功能
6.x支持 PostgreSQL 11+,增强了监控功能,改进了故障转移算法

总结

基于 repmgr 的 PostgreSQL 高可用方案是一个简单易用、功能强大的解决方案,它提供了自动故障检测、手动/自动故障转移、复制管理和集群监控等功能。repmgr 架构简单,依赖少,学习曲线平缓,适合中小型 PostgreSQL 集群。

在实际部署中,需要注意以下几点:

  1. 确保所有节点的 PostgreSQL 配置正确,特别是复制相关的参数
  2. 合理配置 repmgr 的故障转移参数,根据业务需求选择自动或手动故障转移
  3. 配置适当的监控和告警,及时发现和处理问题
  4. 定期进行故障转移演练,验证故障转移流程的正确性
  5. 制定合理的备份策略,确保数据安全
  6. 关注 PostgreSQL 和 repmgr 的版本差异,选择适合的版本组合

通过遵循这些最佳实践,可以构建一个稳定、可靠的 PostgreSQL 高可用集群,满足业务的高可用性需求。