一、什么是MySQL高可用
1.1 核心定义
MySQL高可用,本质是通过架构设计和技术手段,最大限度减少数据库服务不可用时间,保障业务连续性和数据可靠性,核心目标是解决"单点故障"问题------即单个MySQL节点宕机、故障时,能快速切换到备用节点,避免业务中断、数据丢失,同时支撑业务高并发访问需求。
简单来说,高可用的核心是"不中断、不丢数",让数据库服务在故障场景下仍能正常对外提供服务,是生产环境中数据库部署的核心要求。
1.2 核心衡量指标
-
RTO(恢复时间目标):故障发生后,数据库服务恢复正常的最长可接受时间,生产核心场景要求RTO<30s,非核心场景RTO<5min。
-
RPO(恢复点目标):故障发生后,可接受的最大数据丢失量,核心交易场景要求RPO=0(无数据丢失),非核心场景RPO<30s。
1.3 高可用与普通部署的区别
普通单节点部署:结构简单,但存在单点故障,一旦节点宕机,整个数据库服务完全不可用,数据易丢失,仅适用于测试、开发等非生产场景。
高可用集群部署:多节点协同工作,存在主备/主主节点,故障时自动/手动切换,保障服务连续性,数据同步可靠,适用于生产、线上等高并发、高可靠需求场景。
二、MySQL高可用集群搭建
本次搭建以"主主复制 + Keepalived(虚拟IP漂移) + HAProxy(负载均衡)"为核心架构,适配生产级中小规模业务,兼顾高可用和高并发,步骤清晰、可直接落地,环境基于CentOS 7 + MySQL 8.0。
2.1 搭建前准备
2.1.1 服务器环境(4台服务器,最小配置)
-
MySQL主节点1(Master1):IP 192.168.1.10,CPU≥2核,内存≥4G,硬盘≥50G
-
MySQL主节点2(Master2):IP 192.168.1.11,配置与Master1一致(主主复制要求节点配置对等)
-
HAProxy节点1:IP 192.168.1.12,CPU≥2核,内存≥2G(负载均衡节点,可部署2台实现HA)
-
HAProxy节点2(可选,高可用负载):IP 192.168.1.13,配置与HAProxy节点1一致
2.1.2 环境初始化(所有节点执行)
1. 关闭防火墙和SELinux(生产可按需开放端口,临时关闭便于搭建)
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
2. 时间同步(避免数据同步因时间差异常)
yum install ntpdate -y
ntpdate ntp.aliyun.com
3. 安装依赖包
yum install -y wget gcc gcc-c++ make openssl-devel pcre-devel
2.1.3 安装MySQL 8.0(Master1、Master2节点)
1. 下载MySQL repo源(注:原下载链接可能存在不支持该文件类型的报错,可更换为国内镜像源或直接通过yum仓库安装)
wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
rpm -ivh mysql80-community-release-el7-3.noarch.rpm
2. 安装MySQL
yum install -y mysql-community-server
3. 启动MySQL并设置开机自启
systemctl start mysqld
systemctl enable mysqld
4. 查看初始密码(用于首次登录)
grep 'temporary password' /var/log/mysqld.log
5. 登录MySQL并修改密码(密码需符合复杂度:字母+数字+特殊符号)
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MySQL@123456';
grant all privileges on *.* to 'root'@'%' identified by 'MySQL@123456';
flush privileges;
exit;
2.2 搭建主主复制
主主复制是指两个MySQL节点互为主从,彼此同步数据,即Master1的修改同步到Master2,Master2的修改同步到Master1,解决单主复制中主节点故障后需手动切换的痛点,为后续高可用切换奠定基础。
2.2.1 配置Master1(192.168.1.10)
1. 编辑MySQL配置文件
vim /etc/my.cnf
2. 添加以下配置(核心参数,其余保持默认)
mysqld
server-id = 10 # 唯一标识,每个节点必须不同,建议用IP最后一段
log_bin = mysql-bin # 开启binlog日志(数据同步的核心)
binlog_format = ROW # 行级格式,避免主从不一致,生产必用
gtid_mode = ON # 开启GTID,自动定位同步位点,无需手动配置
enforce_gtid_consistency = ON # 强制GTID一致性
log_slave_updates = ON # 允许从库将同步的事务写入自身binlog(主主复制核心)
sync_binlog = 1 # 每提交1个事务,就将binlog刷到磁盘,保障数据不丢失
innodb_flush_log_at_trx_commit = 1 # 事务提交时,将redo log刷到磁盘
3. 重启MySQL生效
systemctl restart mysqld
2.2.2 配置Master2(192.168.1.11)
1. 编辑MySQL配置文件
vim /etc/my.cnf
2. 添加以下配置(server-id与Master1不同,其余参数一致)
mysqld
server-id = 11
log_bin = mysql-bin
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
3. 重启MySQL生效
systemctl restart mysqld
2.2.3 建立主主同步关系
步骤1:在Master1上授权Master2同步
mysql -u root -pMySQL@123456
授权同步用户(repl为同步用户名,123456为密码,%表示允许所有IP连接)
grant replication slave on *.* to 'repl'@'%' identified by 'Repl@123456';
flush privileges;
查看Master1状态(记录binlog文件和位置,后续配置Master2用)
show master status;
输出示例(无需复制,实际以自己的为准):
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 156 | | | |
+------------------+----------+--------------+------------------+-------------------+
步骤2:在Master2上配置同步Master1
mysql -u root -pMySQL@123456
停止从库同步(首次配置可忽略)
stop slave;
配置同步Master1(替换Master1的IP、同步用户和密码,无需手动填binlog位置,GTID自动同步)
change master to
master_host='192.168.1.10',
master_user='repl',
master_password='Repl@123456',
master_auto_position=1; # 开启GTID自动定位
启动从库同步
start slave;
查看同步状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)
show slave status\G;
步骤3:在Master2上授权Master1同步(反向同步)
继续在Master2的MySQL终端执行
grant replication slave on *.* to 'repl'@'%' identified by 'Repl@123456';
flush privileges;
查看Master2状态(记录binlog信息,用于配置Master1同步)
show master status;
步骤4:在Master1上配置同步Master2(反向同步)
mysql -u root -pMySQL@123456
stop slave;
change master to
master_host='192.168.1.11',
master_user='repl',
master_password='Repl@123456',
master_auto_position=1;
start slave;
查看同步状态,确保Slave_IO_Running和Slave_SQL_Running均为Yes
show slave status\G;
验证主主复制
- 在Master1上创建数据库和表,插入数据:
create database test_ha;
use test_ha;
create table user(id int primary key auto_increment, name varchar(50));
insert into user(name) values('test1');
commit;
- 在Master2上查询,确认数据同步成功:
use test_ha;
select * from user; # 能查询到Master1插入的数据,说明同步正常
- 同理,在Master2上插入数据,在Master1上查询,验证反向同步正常,主主复制搭建完成。
2.3 安装配置HAProxy(负载均衡)
HAProxy是一款高性能的TCP/HTTP负载均衡工具,用于将客户端的数据库请求分发到两个MySQL主节点,实现负载分担,同时检测节点状态,故障节点自动剔除,保障请求正常转发。
2.3.1 安装HAProxy(192.168.1.12、192.168.1.13节点)
1. 下载HAProxy(以2.4.24版本为例,注:原下载链接可能存在网页解析失败报错,可更换版本或国内镜像源)
wget https://www.haproxy.org/download/2.4/src/haproxy-2.4.24.tar.gz
2. 解压并编译安装
tar -zxvf haproxy-2.4.24.tar.gz
cd haproxy-2.4.24
make TARGET=linux-glibc
make install
3. 查看版本,确认安装成功
haproxy -v
2.3.2 配置HAProxy(核心配置)
1. 创建配置文件目录和日志目录
mkdir -p /etc/haproxy
mkdir -p /var/log/haproxy
2. 编辑HAProxy配置文件
vim /etc/haproxy/haproxy.cfg
3. 写入以下配置(核心部分,其余可默认)
global
log 127.0.0.1 local0 info # 日志配置
maxconn 10000 # 最大连接数
daemon # 后台运行
defaults
log global
mode tcp # 模式为TCP(MySQL是TCP协议)
option tcplog # 开启TCP日志
option dontlognull
retries 3 # 连接失败重试次数
timeout connect 5000ms # 连接超时时间
timeout client 50000ms # 客户端超时时间
timeout server 50000ms # 服务器超时时间
MySQL负载均衡配置(frontend接收请求,backend分发请求)
frontend mysql_front
bind *:3306 # 监听3306端口(与MySQL端口一致,方便客户端访问)
default_backend mysql_back # 请求转发到mysql_back后端集群
backend mysql_back
balance roundrobin # 负载均衡算法:轮询(均匀分发请求)
option tcp-check # 开启TCP检测(检测MySQL节点是否存活)
tcp-check connect port 3306 # 检测3306端口
tcp-check send "SELECT 1\r\n" # 发送检测指令(MySQL心跳检测)
tcp-check expect string "1" # 期望返回结果,确认节点正常
配置两个MySQL主节点(weight是权重,默认1,可根据节点性能调整)
server mysql1 192.168.1.10:3306 check weight 1
server mysql2 192.168.1.11:3306 check weight 1
HAProxy监控页面(可选,便于查看集群状态)
listen stats
bind *:8888 # 监控页面端口
mode http
stats enable
stats uri /haproxy_stats # 监控页面路径
stats auth admin:admin # 监控页面用户名密码(可自定义)
2.3.3 启动HAProxy并设置开机自启
1. 启动HAProxy
haproxy -f /etc/haproxy/haproxy.cfg
2. 设置开机自启(创建系统服务)
vim /usr/lib/systemd/system/haproxy.service
写入以下内容:
Unit
Description=HAProxy Load Balancer
After=network.target
Service
ExecStart=/usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg
ExecReload=/usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg -s reload
ExecStop=/usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg -s stop
Restart=on-failure
Install
WantedBy=multi-user.target
3. 启用并重启服务
systemctl daemon-reload
systemctl enable haproxy
systemctl restart haproxy
4. 验证HAProxy状态(确保启动成功)
systemctl status haproxy
2.4 安装配置Keepalived(虚拟IP漂移)
Keepalived的核心作用是实现虚拟IP(VIP)的漂移,为HAProxy节点提供高可用------当主HAProxy节点故障时,虚拟IP自动漂移到备用HAProxy节点,客户端无需修改连接地址,即可继续访问数据库服务,避免HAProxy成为单点故障。
2.4.1 安装Keepalived(所有HAProxy节点执行)
yum install -y keepalived
2.4.2 配置主HAProxy节点(192.168.1.12,MASTER角色)
1. 编辑Keepalived配置文件
vim /etc/keepalived/keepalived.conf
2. 写入以下配置(核心参数,替换对应IP)
! Configuration File for keepalived
global_defs {
router_id LVS_MASTER # 路由标识,主备节点需不同
}
检测HAProxy状态(核心:如果HAProxy停止,自动切换VIP)
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh" # 检测脚本路径
interval 2 # 检测间隔(2秒)
weight -20 # 检测失败,权重降低20,触发切换
}
vrrp_instance VI_1 {
state MASTER # 角色:MASTER(主节点)
interface ens33 # 网卡名称(用ip addr查看自己的网卡,如eth0)
virtual_router_id 51 # 虚拟路由ID,主备节点必须一致(0-255)
priority 100 # 优先级,MASTER优先级高于BACKUP(如100>90)
advert_int 1 # 心跳发送间隔(1秒)
authentication {
auth_type PASS # 认证方式
auth_pass 1111 # 认证密码,主备节点必须一致
}
虚拟IP(VIP),客户端通过这个IP访问数据库,可设置多个
virtual_ipaddress {
192.168.1.200/24 # VIP地址,与服务器在同一网段
}
调用HAProxy检测脚本
track_script {
chk_haproxy
}
}
2.4.3 配置备HAProxy节点(192.168.1.13,BACKUP角色)
vim /etc/keepalived/keepalived.conf
配置与主节点基本一致,修改以下3处即可
! Configuration File for keepalived
global_defs {
router_id LVS_BACKUP # 路由标识,与主节点不同
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state BACKUP # 角色:BACKUP(备节点)
interface ens33 # 与主节点一致的网卡名称
virtual_router_id 51 # 与主节点一致
priority 90 # 优先级,低于主节点(90<100)
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 与主节点一致
}
virtual_ipaddress {
192.168.1.200/24 # 与主节点一致的VIP
}
track_script {
chk_haproxy
}
}
2.4.4 创建HAProxy检测脚本(所有HAProxy节点执行)
脚本作用:定期检测HAProxy是否正常运行,若异常则停止Keepalived,触发VIP漂移。
1. 创建脚本文件
vim /etc/keepalived/check_haproxy.sh
2. 写入以下内容(检测HAProxy进程)
#!/bin/bash
检测HAProxy进程是否存在
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
若HAProxy未运行,停止Keepalived
systemctl stop keepalived
fi
3. 给脚本添加执行权限
chmod +x /etc/keepalived/check_haproxy.sh
2.4.5 启动Keepalived并设置开机自启
systemctl start keepalived
systemctl enable keepalived
查看Keepalived状态,确保启动成功
systemctl status keepalived
查看VIP是否生效(主节点会显示VIP,备节点不显示)
ip addr
2.5 集群整体测试(验证高可用)
测试1:负载均衡测试
客户端通过VIP(192.168.1.200)连接MySQL,多次插入数据,查看两个MySQL节点的日志,确认请求被HAProxy均匀分发(轮询模式)。
客户端连接MySQL(需安装MySQL客户端)
mysql -u root -pMySQL@123456 -h 192.168.1.200 -P 3306
插入多条数据,分别在Master1和Master2上查看binlog,确认均有请求
show binary logs;
mysqlbinlog 文件名 | grep 'insert into user' # 查看插入记录
测试2:MySQL节点故障测试
停止Master1的MySQL服务,客户端继续通过VIP连接,插入数据,确认数据能正常写入Master2,HAProxy自动剔除故障节点,无服务中断。
停止Master1的MySQL
systemctl stop mysqld
客户端继续插入数据,确认正常
mysql -u root -pMySQL@123456 -h 192.168.1.200 -P 3306
use test_ha;
insert into user(name) values('test_fault');
commit;
启动Master1的MySQL,确认数据自动同步(主主复制生效)
systemctl start mysqld
select * from user; # 能查询到故障期间插入的数据
测试3:HAProxy节点故障测试
停止主HAProxy节点(192.168.1.12)的HAProxy服务,查看VIP是否漂移到备HAProxy节点(192.168.1.13),客户端继续连接VIP,确认服务正常。
停止主HAProxy
systemctl stop haproxy
查看备节点的IP,确认VIP(192.168.1.200)已漂移
ip addr
客户端连接VIP,确认正常访问
mysql -u root -pMySQL@123456 -h 192.168.1.200 -P 3306
三、核心协同机制(必掌握)
3.1 主主复制的协同逻辑
主主复制是整个高可用集群的基础,核心协同逻辑是"双向同步、互为备份":
-
两个MySQL节点(Master1、Master2)均开启binlog和GTID,彼此作为对方的从库,同步对方的事务。
-
当客户端通过HAProxy向其中一个节点写入数据时,该节点将事务写入自身binlog,另一节点通过IO线程读取该binlog,SQL线程重放事务,实现数据同步。
-
核心优势:无需手动切换主从,任何一个节点故障,另一个节点可直接接管服务,数据无丢失(RPO=0),为后续负载均衡和故障切换提供数据基础。
-
注意点:需确保两个节点的配置一致(如server-id、binlog格式),避免主键冲突(建议使用自增主键,设置不同的自增步长,如Master1步长2、起始1;Master2步长2、起始2)。
3.2 Keepalived虚拟IP漂移机制
Keepalived基于VRRP(虚拟路由冗余协议)实现VIP漂移,核心协同逻辑是"心跳检测、优先级切换":
-
主备HAProxy节点运行Keepalived,主节点(MASTER)优先级高于备节点(BACKUP),主节点定期向备节点发送心跳(advert_int=1秒)。
-
正常情况下,主节点持有VIP,客户端通过VIP访问HAProxy,再由HAProxy分发请求到MySQL节点。
-
当主HAProxy节点故障(如HAProxy停止、服务器宕机),备节点无法收到主节点的心跳,触发VRRP选举:备节点检测到主节点故障后,提升自身优先级,接管VIP,实现VIP漂移(漂移时间≤3秒)。
-
当主节点恢复正常后,由于其优先级高于备节点,会重新接管VIP,备节点释放VIP,恢复备用状态。
-
核心作用:屏蔽HAProxy的单点故障,客户端无需修改连接地址,即可实现无缝切换,保障访问连续性。
3.3 HAProxy负载均衡协同机制
HAProxy作为请求入口,核心协同逻辑是"请求分发、故障检测、负载分担",衔接客户端与MySQL节点:
-
客户端通过VIP连接HAProxy的3306端口(与MySQL端口一致),HAProxy接收请求后,根据负载均衡算法(本次用轮询),将请求分发到两个MySQL主节点。
-
HAProxy通过TCP检测机制(tcp-check),定期向MySQL节点发送"SELECT 1"心跳请求,检测节点是否存活:若节点无响应(如MySQL停止),HAProxy自动将该节点从后端集群中剔除,不再分发请求;若节点恢复,自动重新加入集群。
-
协同Keepalived:HAProxy的状态由Keepalived检测(通过check_haproxy.sh脚本),若HAProxy故障,Keepalived触发VIP漂移,确保客户端请求始终能到达正常的HAProxy节点。
-
核心作用:实现请求的负载分担,避免单个MySQL节点压力过大;同时实现MySQL节点的故障自动剔除,提升集群的并发处理能力和可用性。
3.4 三者整体协同流程(完整链路)
客户端 → VIP(Keepalived管理) → HAProxy(负载均衡) → MySQL主主节点(数据同步),完整协同流程如下:
-
正常状态:Keepalived主节点持有VIP,HAProxy正常运行,客户端通过VIP连接HAProxy,HAProxy将请求轮询分发到Master1和Master2,两个节点双向同步数据,负载均衡且数据一致。
-
MySQL节点故障:若Master1故障,HAProxy检测到节点异常,自动停止向Master1分发请求,所有请求转发到Master2;Master1恢复后,HAProxy重新将其加入集群,主主复制同步缺失数据,恢复负载均衡。
-
HAProxy节点故障:若主HAProxy故障,Keepalived检测到HAProxy停止,触发VIP漂移到备HAProxy;客户端继续通过VIP连接,备HAProxy接管请求分发,服务无中断;主HAProxy恢复后,VIP漂移回主节点,恢复正常架构。
四、实战注意事项
-
MySQL配置:必须开启GTID和log_slave_updates,binlog格式设为ROW,避免主从不一致;主主复制需设置不同的server-id,防止冲突。
-
HAProxy配置:模式设为TCP(MySQL是TCP协议),开启TCP检测,确保能准确识别MySQL节点状态;负载均衡算法可根据业务调整(如leastconn:最少连接优先)。
-
Keepalived配置:主备节点的virtual_router_id和auth_pass必须一致,主节点优先级高于备节点;检测脚本需添加执行权限,确保能正常检测HAProxy状态。
-
下载异常处理:MySQL repo源和HAProxy安装包的原下载链接可能出现"不支持该文件类型""网页解析失败"等报错,可更换对应软件的其他版本,或使用国内镜像源(如阿里云、华为云镜像)下载,避免影响搭建流程。
-
生产优化:MySQL节点建议关闭查询缓存,开启并行复制;HAProxy和Keepalived节点可部署在不同机房,提升集群抗灾能力;定期备份数据,避免极端故障导致数据丢失。
-
故障排查:若集群异常,优先查看HAProxy日志(/var/log/haproxy)、Keepalived日志(/var/log/messages)、MySQL日志(/var/log/mysqld.log),定位故障节点和原因。