MySQL主备高可用架构搭建实战

自开始写后端以来好几年了,什么高可用,高并发常常都在聊,但实际大多数都还停留在嘴上,终于有时间来完成过去没有完成的工作了,直接实战。注意:1、一定要在测试环境跑通流程才能在生产上实操;2、数据库一定要备份以防万一;

一、架构总览

核心设计原则

整套架构严格遵循脚本极简、告警标准化、运维轻量化核心原则,最大程度降低故障概率与日常维护成本:

  • 脚本极简:仅保留唯一核心切换脚本,仅用于VIP漂移时自动切换数据库读写权限

  • 告警标准化:全量故障告警、集群状态通知,完全依托Prometheus+Grafana原生能力实现

当前落地现状

整体采用一主一从单向同步+Keepalived VIP漂移高可用架构,业务通过统一VIP入口访问数据库,主节点故障时可快速自动切换入口,保障业务连续性;已完成服务器基础监控部署,数据库精细化监控可按需扩展。

  • 数据库层:节点A为主库、节点B为从库,单向同步(A→B),从库默认开启只读模式,禁止业务写入

  • 高可用层:基于VRRP协议的Keepalived实现虚拟VIP漂移,采用非抢占模式,有效规避集群脑裂、频繁切换问题

  • 切换逻辑:VIP漂移联动唯一核心脚本,自动控制节点只读开关,无VIP的节点强制只读,从底层兜底杜绝双写数据异常

  • 告警监控层:node-exporter采集服务器基础指标,数据库指标依托mysqld-exporter扩展,所有告警、状态监控统一收敛至Prometheus+Grafana体系

核心约束(单向架构必知)

本架构为单向主从复制,仅从库同步主库数据,主库不会反向同步从库数据,存在严格运维约束:

禁止人工随意触发VIP切换写入!非主库彻底故障场景下的切换,会导致主从两端binlog分叉,造成永久数据不一致,且无法自动恢复。仅允许主库宕机、进程崩溃等彻底故障时执行VIP切换。

二、环境信息

角色 内网IP 已部署组件
主节点A 192.168.99.61 MySQL 8.0(主库)、Keepalived、node-exporter
备节点B 192.168.99.62 MySQL 8.0(从库)、Keepalived、node-exporter
虚拟VIP(统一业务入口) 192.168.99.100 无独立组件,由Keepalived统一管理漂移

前置部署说明

  1. 两台服务器已完成时间同步,操作系统为Linux,系统环境一致

  2. MySQL 8.0默认使用InnoDB存储引擎,支持无锁全量数据导出,不阻塞业务

  3. 复用现有数据库复制账号repl,无需新建同步账号,减少权限配置成本

  4. node-exporter基于Docker容器部署,采用network_mode: host主机网络模式,完整采集宿主机硬件与网络指标

三、MySQL单向主从同步搭建(已落地)

1. 数据库配置文件修改

主节点A配置(/etc/my.cnf)

1
2
3
4
5
[mysqld]
server-id = 1 # 主从节点ID必须唯一
log_bin = mysql-bin # 开启binlog日志,用于主从同步
binlog_format = ROW # 行级日志格式,数据同步精准、避免数据错乱
expire_logs_days = 7 # binlog日志7天自动清理,释放磁盘空间

备节点B配置(/etc/my.cnf)

1
2
3
4
5
6
7
[mysqld]
server-id = 2 # 与主库ID区分,全局唯一
log_bin = mysql-bin # 开启binlog,为后续架构扩容预留能力
binlog_format = ROW
expire_logs_days = 7
read_only = 1 # 普通用户只读
super_read_only = 1 # 超级管理员只读,彻底杜绝手动写入

配置修改完成后,两台节点重启MySQL服务使配置生效:

1
systemctl restart mysqld

2. 复制账号权限校验

复用系统现有repl同步账号,校验账号是否具备主从同步所需的REPLICATION SLAVE权限:

1
SHOW GRANTS FOR 'repl'@'%';

若权限缺失,执行授权并刷新权限:

1
2
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

3. 主库无锁全量数据导出

基于InnoDB引擎事务特性,使用--single-transaction实现无锁热备份,全程不阻塞线上业务读写,适配生产环境:

1
mysqldump -uroot -p --all-databases --master-data=2 --single-transaction > all.sql

导出完成后,登录主库查询主节点binlog位点,记录File日志文件名称Position偏移量,用于从库同步初始化:

1
SHOW MASTER STATUS;

4. 从库全量数据导入

将主库导出的all.sql文件传输至备节点B,执行数据导入,保证主从初始数据完全一致:

1
mysql -uroot -p < all.sql

5. 从库配置主从同步链路

登录备节点B的MySQL,配置主库连接信息、同步账号及初始化位点,建立单向同步链路:

1
2
3
4
5
6
7
8
9
CHANGE MASTER TO
MASTER_HOST='192.168.99.61',
MASTER_USER='repl',
MASTER_PASSWORD='复制账号密码',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=156;

-- 启动主从同步
START SLAVE;

6. 主从同步状态校验

执行命令查看完整同步状态,重点校验核心指标:

1
SHOW SLAVE STATUS\G

正常标准(全部满足即为同步正常)

  • Slave_IO_Running = Yes:IO线程正常运行,可成功拉取主库binlog日志

  • Slave_SQL_Running = Yes:SQL线程正常运行,可正常回放日志、同步数据

  • Seconds_Behind_Master = 0:主从数据无延迟,同步状态健康

四、Keepalived VIP高可用部署(已落地)

1. Keepalived安装(双节点)

主备两台节点统一执行安装命令,部署Keepalived服务:

1
yum install -y keepalived

2. 核心配置文件说明

全局采用非抢占模式,主节点故障恢复后不会自动抢占VIP,避免集群二次切换、脑裂及业务抖动;仅绑定唯一读写切换脚本,无冗余配置与自定义告警脚本。

主节点A完整配置(/etc/keepalived/keepalived.conf)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
global_defs {
router_id mysql-master-A # 主节点唯一标识
}

vrrp_instance VI_1 {
state BACKUP # 统一配置为BACKUP,配合优先级区分主备
interface ens33 # 替换为服务器实际网卡名(ip a 查询)
virtual_router_id 51 # 主备节点必须完全一致
priority 100 # 主节点优先级高于备节点
nopreempt # 开启非抢占模式,仅主节点配置
advert_int 1 # 心跳报文发送间隔1秒

authentication {
auth_type PASS
auth_pass 123456 # 主备认证密码必须一致
}

virtual_ipaddress {
192.168.99.100/24 dev ens33 # 业务VIP及绑定网卡
}

# 状态切换联动读写权限控制脚本
notify_master "/etc/keepalived/scripts/mysql_switch.sh MASTER"
notify_backup "/etc/keepalived/scripts/mysql_switch.sh BACKUP"
notify_fault "/etc/keepalived/scripts/mysql_switch.sh FAULT"
}

备节点B差异化配置

整体配置与主节点一致,仅修改三处关键内容:

  • router_id 改为 mysql-master-B

  • priority 改为 90(低于主节点)

  • 删除nopreempt配置,仅主节点开启非抢占

3. 唯一核心:读写权限切换脚本

双节点脚本路径统一,为架构唯一自定义脚本,逻辑极简、无多余依赖,仅负责VIP状态变更时自动调整数据库读写权限,兜底防双写:

脚本路径:/etc/keepalived/scripts/mysql_switch.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
MYSQL_USER="root"
MYSQL_PASS="MySQL密码"
MYSQL_SOCK="/var/lib/mysql/mysql.sock"

case $1 in
MASTER)
# 节点接管VIP,切换为主库,放开读写权限
mysql -u$MYSQL_USER -p$MYSQL_PASS -S $MYSQL_SOCK -e "SET GLOBAL read_only=0;SET GLOBAL super_read_only=0;"
;;
BACKUP|FAULT)
# 节点失去VIP/故障,强制只读,杜绝写入
mysql -u$MYSQL_USER -p$MYSQL_PASS -S $MYSQL_SOCK -e "SET GLOBAL read_only=1;SET GLOBAL super_read_only=1;"
;;
esac

创建脚本目录并赋予执行权限(双节点均执行):

1
2
mkdir -p /etc/keepalived/scripts
chmod +x /etc/keepalived/scripts/mysql_switch.sh

4. 防火墙放行VRRP协议

VRRP协议为Keepalived心跳通信核心,需双向放行,否则主备心跳中断、VIP无法正常漂移:

1
2
firewall-cmd --add-protocol=vrrp --permanent
firewall-cmd --reload

5. 服务启动与状态验证

双节点启动Keepalived并设置开机自启:

1
2
systemctl start keepalived
systemctl enable keepalived

正常运行状态说明

  • 主节点A:执行ip a可查询到VIP绑定,日志显示Entering MASTER STATE

  • 备节点B:执行ip a无VIP为正常现象,日志显示Entering BACKUP STATE,静默待命等待主节点故障接管

6. 日志警告修复(可选)

若系统日志出现keepalived_script 用户不存在警告,创建专属执行用户即可消除:

1
useradd -M keepalived_script

五、监控与告警体系

本集群监控告警遵循零自定义告警脚本、开源标准架构设计,整体由「指标采集器 + Prometheus + Alertmanager + Grafana」组成,分工明确、运维简单,统一收敛所有服务器、MySQL、集群高可用状态指标与告警。

1. 指标采集组件

集群部署两类采集器,全覆盖软硬件监控指标,无自定义脚本:

  • node-exporter(已部署):主机网络、CPU、内存、磁盘、VIP绑定状态等服务器基础指标采集

  • mysqld-exporter(待部署):MySQL实例状态、主从同步、线程、连接数等数据库核心指标采集

  • 部署方式:Docker Compose独立部署

  • 网络模式:network_mode: host主机网络,完整采集网卡、磁盘、进程、VIP绑定状态等宿主机指标

  • 暴露端口:9100

  • 监控范围:服务器CPU、内存、磁盘使用率、网卡流量、进程存活状态、VIP绑定状态

2. 标准告警流程(核心)

严格遵循开源监控标准分工,Prometheus负责规则判断触发告警,Alertmanager负责告警调度推送,Grafana仅负责可视化展示与记录回溯,不承担告警触发能力。

完整告警链路

Exporter指标采集 → Prometheus规则校验、触发告警 → Alertmanager去重/分组/静默/抑制 → 推送企业微信/钉钉/邮件 → Grafana大盘展示监控数据与告警历史

核心运维告警规则

覆盖集群核心故障场景,全部在Prometheus中配置:MySQL实例宕机、主从IO/SQL线程中断、主从同步延迟过高、集群双VIP脑裂、节点双写风险、服务器资源使用率超标。

六、现有架构风险与优化方向

1. 当前架构核心风险

  • 单向复制局限性风险:VIP切换至备节点写入后,原主库无反向同步链路,两端binlog分叉,数据不可逆不一致,无法直接切回原主节点,仅支持单次故障切换

  • 数据库故障无自动感知:当前Keepalived仅检测服务器网络与节点存活,若MySQL进程崩溃、数据库异常但服务器正常,无法自动触发VIP漂移,存在业务中断风险

2. 优化方向:双主双向同步架构改造(核心架构升级)

彻底解决单向架构数据分叉、无法回切的问题,适配生产长期稳定运行,原有切换脚本、监控告警体系完全复用,无需新增冗余脚本。

  1. 自增主键冲突规避:两台节点配置自增偏移量,杜绝双向写入主键冲突

    • 主节点A:auto_increment_increment=2auto_increment_offset=1

    • 备节点B:auto_increment_increment=2auto_increment_offset=2

  2. 新增反向同步链路:在原主库A配置同步原备库B数据,实现双向互为主从,数据双向同步

  3. 保留原有兜底机制:沿用非抢占模式+只读权限自动切换逻辑,保证同一时间仅单节点可写入,彻底杜绝脑裂双写

4. 全局优化原则

  • 核心读写切换脚本永久保留,作为双写风险底层兜底,单向/双向架构通用

  • 所有告警、状态监控统一收敛至Prometheus+Grafana,严禁新增独立自定义告警脚本

  • 所有扩展脚本、自定义配置仅在业务刚需场景下新增,默认保持架构极简、脚本最少化

七、常见问题与排错手册

1. 备节点查询不到VIP是否正常?

完全正常。VIP为单点独占资源,同一时间仅允许一台节点绑定持有。备节点默认处于BACKUP备用状态,不绑定VIP;仅主节点故障、备节点接管后,才会生成VIP地址。

2. 主节点故障后VIP无法漂移排查步骤

按优先级逐层排查,快速定位问题:

  1. 检查双节点防火墙是否已永久放行VRRP协议,临时放行不生效

  2. 核对主备virtual_router_id、VRRP认证密码是否完全一致

  3. 校验配置文件中网卡名称与服务器实际网卡(ip a查询)是否匹配

  4. 确认双节点Keepalived优先级存在差值,主节点优先级高于备节点

  5. 查看Keepalived日志,排查进程异常、配置报错

3. mysqld-exporter连接MySQL失败排查

  1. 网络模式为bridge网桥时,禁止使用127.0.0.1连接,需使用容器服务名或宿主机内网IP

  2. 核对MySQL监控账号授权范围,bridge模式必须授权@'%',主机网络模式适配localhost授权

  3. 检查端口连通性、服务器防火墙是否拦截9104、3306端口

  4. 确认exporter密码与数据库授权密码完全一致,无字符误差

4. 单向架构是否支持测试VIP切换?

  • 低风险测试(推荐):单独执行读写切换脚本,验证只读权限切换逻辑,不触发真实VIP漂移,无数据风险

  • 全量切换测试(谨慎):单向架构不建议随意切换。确需测试,必须在业务低峰期执行,且切换完成后禁止强行切回原主,需长期保留新主架构,避免binlog分叉导致数据永久不一致

(注:内容由 AI 辅助编写)

[越努力,越幸运!]