一、前言
在数字化时代,数据是企业的核心资产,而数据库的可靠性直接决定了业务的连续性。传统单节点 MySQL 架构存在严重的单点故障风险:一旦主库宕机、硬件损坏或网络中断,将直接导致业务系统瘫痪,造成不可估量的经济损失与用户信任危机。因此,搭建一套高可用、高可靠、可扩展的 MySQL 高可用集群,是企业级生产环境的核心刚需。
本文将基于MySQL 主主复制 + HAProxy 负载均衡 + Keepalived 高可用的经典架构,从零到一完整实现一套企业级 MySQL 高可用集群,涵盖环境准备、主主复制配置、HAProxy 负载均衡部署、Keepalived 虚拟 IP 搭建、故障自动转移全流程,所有步骤均经过实战验证,可直接用于生产环境落地。
二、技术栈与核心原理
2.1 核心组件介绍
2.1.1 MySQL 主主复制
MySQL 主主复制(Master-Master Replication)是基于 MySQL 二进制日志(Binlog)实现的双向同步架构,两台 MySQL 节点互为主从,任意节点写入的数据都会同步到另一台节点,实现数据的实时一致性。
- 核心原理:主库将数据变更记录到 Binlog 日志,从库通过 I/O 线程拉取主库 Binlog 并写入本地 Relay Log,再通过 SQL 线程重放 Relay Log 中的 SQL 语句,完成数据同步。主主架构下,两台节点同时开启 Binlog 与复制功能,实现双向同步。
- 核心优势 :
- 双向同步,双主互备,任意节点宕机不影响数据完整性;
- 支持双写,可灵活分配读写负载,提升系统并发能力;
- 为上层负载均衡提供多活节点,保障服务连续性。
2.1.2 HAProxy 负载均衡
HAProxy 是一款开源、高性能的 TCP/HTTP 负载均衡器,专为高并发、高可用场景设计,在 MySQL 高可用架构中承担流量入口与负载分发的核心角色。
- 核心作用 :
- 统一入口:对外提供唯一的数据库访问地址,屏蔽后端多节点细节;
- 负载分发:将客户端请求按策略分发到后端 MySQL 节点,实现负载均衡;
- 健康检查:实时监控后端 MySQL 节点状态,自动剔除故障节点,保障流量仅分发到健康节点;
- 高并发支持:单节点可承载数万并发连接,满足企业级业务流量需求。
2.1.3 Keepalived 高可用
Keepalived 是基于 VRRP(虚拟路由冗余协议)实现的高可用工具,核心作用是为 HAProxy 节点提供虚拟 IP(VIP),实现 HAProxy 的主备切换,解决 HAProxy 自身的单点故障问题。
- 核心原理:通过 VRRP 协议,多台 Keepalived 节点选举出主节点,由主节点绑定虚拟 IP 对外提供服务;当主节点宕机时,备节点自动抢占虚拟 IP,接管服务,实现秒级故障转移,对业务完全透明。
- 核心优势 :
- 解决 HAProxy 单点故障,实现负载均衡层高可用;
- 故障自动转移,无需人工干预,保障服务连续性;
- 配置简单,轻量高效,资源占用极低。
2.2 整体架构设计
本次实战采用四层高可用架构,架构拓扑如下:
客户端
↓
虚拟IP(VIP:192.168.10.100,Keepalived主备节点提供)
↓
HAProxy负载均衡层(主备双节点:192.168.10.101/192.168.10.102)
↓
MySQL主主复制层(双主节点:192.168.10.103/192.168.10.104)
- 架构分层说明 :
- 应用层:客户端通过虚拟 IP 访问数据库,无需感知后端节点细节;
- 负载均衡层:HAProxy 主备节点通过 Keepalived 实现高可用,主节点承载流量,备节点待命;
- 数据层:MySQL 双主节点实现数据双向同步,保障数据一致性与多活能力;
- 高可用层:Keepalived 保障负载均衡层高可用,HAProxy 保障数据层高可用,双重保障实现全链路无单点。
三、案例环境与需求
3.1 环境规划
本次实战采用 4 台 CentOS 7 服务器,具体规划如下表:
表格
| 主机名 | 操作系统 | IP 地址 | 应用服务 | 角色 |
|---|---|---|---|---|
| Master1 | openEuler 24.03 | 192.168.10.101 | MySQL 8.0.36、HAProxy | MySQL 主节点 1、HAProxy 主节点 |
| Master2 | openEuler 24.03 | 192.168.10.102 | MySQL 8.0.36、HAProxy | MySQL 主节点 2、HAProxy 备节点 |
| Keepalived1 | openEuler 24.03 | 192.168.10.103 | Keepalived | Keepalived 主节点 |
| Keepalived2 | openEuler 24.03 | 192.168.10.104 | Keepalived | Keepalived 备节点 |
注:生产环境中建议将 MySQL、HAProxy、Keepalived 部署在独立服务器,本次为演示方便,将 MySQL 与 HAProxy 同机部署,实际生产请严格分离。
3.2 核心需求
- 实现 MySQL 双主节点数据双向实时同步,任意节点写入数据自动同步到另一节点;
- 搭建 HAProxy 负载均衡,实现 MySQL 节点的流量分发与健康检查,故障节点自动剔除;
- 搭建 Keepalived 高可用,为 HAProxy 提供虚拟 IP,实现 HAProxy 主备自动切换;
- 全链路无单点故障,任意节点宕机不影响业务正常访问,故障自动恢复无需人工干预;
- 支持在线扩容,可灵活新增 MySQL 节点,无需停机维护。
3.3 实施思路
- 安装 MySQL 数据库,完成基础环境配置;
- 配置 MySQL 双主复制,实现数据双向同步;
- 安装配置 HAProxy,实现负载均衡与健康检查;
- 安装配置 Keepalived,实现虚拟 IP 与主备自动切换;
- 测试故障转移,验证高可用集群可靠性。
四、案例实施:从零搭建高可用集群
4.1 安装 MySQL 数据库(Master1、Master2 节点执行)
4.1.1 基础环境准备
在 openEuler 系统中,安装 MySQL 前需先安装依赖包与基础工具:
# 安装基础依赖包
yum install -y gcc gcc-c++ make cmake ncurses ncurses-devel libaio-devel openssl openssl-devel
# 安装wget工具
yum install -y wget
# 创建mysql用户与用户组
groupadd mysql
useradd -r -g mysql -s /sbin/nologin mysql
# 创建数据目录与日志目录
mkdir -p /usr/local/mysql/data
mkdir -p /usr/local/mysql/log
# 授权目录权限
chown -R mysql:mysql /usr/local/mysql
chmod -R 755 /usr/local/mysql
# 关闭防火墙与SELinux(生产环境建议仅开放对应端口)
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
4.1.2 二进制安装 MySQL 8.0.36
本次采用二进制包安装,兼容性更好,适合生产环境:
# 下载MySQL二进制包
wget https://cdn.mysql.com/Downloads/MySQL-8.0/mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz
# 解压到/usr/local目录
tar -xvf mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz -C /usr/local/
# 重命名目录
mv /usr/local/mysql-8.0.36-linux-glibc2.28-x86_64 /usr/local/mysql
# 授权目录权限
chown -R mysql:mysql /usr/local/mysql
# 初始化MySQL
/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
注意:初始化完成后,会生成临时 root 密码,务必保存,后续登录需要使用!示例输出:
A temporary password is generated for root@localhost: Xqf8*y7h&k9L
4.1.3 配置 MySQL 配置文件
编辑/etc/my.cnf配置文件,Master1 与 Master2 配置略有差异,需注意区分:Master1 节点配置:
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/tmp/mysql.sock
port=3306
server-id=1 # 双主节点server-id必须唯一,Master1设为1,Master2设为2
log-bin=mysql-bin # 开启二进制日志
binlog-format=ROW # 二进制日志格式为行模式,避免主主同步冲突
relay-log=relay-bin # 开启中继日志
auto-increment-increment=2 # 自增步长为2,避免主键冲突
auto-increment-offset=1 # 自增起始偏移为1,Master2设为2
log-slave-updates=on # 允许从库同步主库日志,实现双向同步
gtid-mode=on # 开启GTID模式,简化主从配置
enforce-gtid-consistency=on # 强制GTID一致性
skip-slave-start=on # 禁止从库自动启动复制
character-set-server=utf8mb4
default-authentication-plugin=mysql_native_password # 兼容旧版客户端认证
Master2 节点配置:
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/tmp/mysql.sock
port=3306
server-id=2 # 与Master1区分
log-bin=mysql-bin
binlog-format=ROW
relay-log=relay-bin
auto-increment-increment=2
auto-increment-offset=2 # 与Master1区分
log-slave-updates=on
gtid-mode=on
enforce-gtid-consistency=on
skip-slave-start=on
character-set-server=utf8mb4
default-authentication-plugin=mysql_native_password
4.1.4 配置环境变量与 systemd 服务
# 配置环境变量
echo 'export PATH=/usr/local/mysql/bin:$PATH' >> /etc/profile
source /etc/profile
# 复制systemd服务文件
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
# 创建systemd配置文件
cat > /etc/systemd/system/mysqld.service << EOF
[Unit]
Description=MySQL Server
After=network.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
ExecReload=/usr/local/mysql/bin/mysqladmin shutdown
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 重载systemd配置
systemctl daemon-reload
# 启动MySQL服务
systemctl start mysqld
# 设置开机自启
systemctl enable mysqld
# 查看服务状态
systemctl status mysqld
4.1.5 初始化 MySQL 安全配置
# 登录MySQL,使用初始化生成的临时密码
mysql -u root -p
# 修改root密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
# 允许root远程访问(生产环境建议限制IP)
CREATE USER 'root'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
# 创建主从复制专用账号
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
# 刷新权限
FLUSH PRIVILEGES;
# 查看主库状态,记录File与Position值(Master1、Master2分别执行)
show master status\G
示例输出:
File: mysql-bin.000001 Position: 156 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 3f1b5a7c-1234-5678-90ab-cdef01234567:1-1
4.2 配置 MySQL 主主复制(Master1、Master2 节点执行)
4.2.1 配置主从同步
Master1 节点执行:
CHANGE MASTER TO
MASTER_HOST='192.168.10.102', # Master2的IP地址
MASTER_USER='repl',
MASTER_PASSWORD='repl@123456',
MASTER_LOG_FILE='mysql-bin.000001', # Master2执行show master status得到的File值
MASTER_LOG_POS=156; # Master2执行show master status得到的Position值
Master2 节点执行:
CHANGE MASTER TO
MASTER_HOST='192.168.10.101', # Master1的IP地址
MASTER_USER='repl',
MASTER_PASSWORD='repl@123456',
MASTER_LOG_FILE='mysql-bin.000001', # Master1执行show master status得到的File值
MASTER_LOG_POS=156; # Master1执行show master status得到的Position值
4.2.2 启动复制并验证
# 启动从库复制(Master1、Master2分别执行)
start slave;
# 查看复制状态
show slave status\G
验证标准:
Slave_IO_Running: Yes、Slave_SQL_Running: Yes,两个状态均为 Yes,说明主从同步正常。
4.2.3 数据同步测试
在 Master1 节点创建测试库、测试表,插入数据:
CREATE DATABASE test_db;
USE test_db;
CREATE TABLE test_table (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20));
INSERT INTO test_table (name) VALUES ('test1'), ('test2');
在 Master2 节点查询数据:
USE test_db;
SELECT * FROM test_table;
若能查询到 Master1 插入的数据,说明主主同步正常;反之,检查配置文件与复制状态,排查问题。
4.3 安装配置 HAProxy(Master1、Master2 节点执行)
4.3.1 安装 HAProxy
# 安装HAProxy
yum install -y haproxy
# 查看版本
haproxy -v
# 备份默认配置文件
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
4.3.2 配置 HAProxy 负载均衡
编辑/etc/haproxy/haproxy.cfg配置文件,Master1 与 Master2 配置完全一致:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
maxconn 300 # 最大并发连接数,根据业务调整
defaults
log global
mode tcp # 工作在TCP模式,适合MySQL
option tcplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
# 开启HAProxy监控页面
listen stats
bind 0.0.0.0:8888
stats enable
stats uri /stats
stats auth admin:admin@123456 # 监控页面账号密码
stats admin if TRUE
# MySQL负载均衡配置
listen mysql_cluster
bind 0.0.0.0:3306 # 对外提供的MySQL服务端口
mode tcp
balance roundrobin # 负载均衡策略:轮询
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
server mysql1 192.168.10.101:3306 check inter 2000 rise 2 fall 3 # Master1 MySQL节点
server mysql2 192.168.10.102:3306 check inter 2000 rise 2 fall 3 # Master2 MySQL节点
配置说明:
balance roundrobin:轮询策略,请求依次分发到后端节点;check inter 2000 rise 2 fall 3:健康检查间隔 2 秒,连续 2 次成功判定为健康,连续 3 次失败判定为故障;- 监控页面可通过
http://IP:8888/stats访问,实时查看后端节点状态。
4.3.3 启动 HAProxy 服务
# 检查配置文件语法
haproxy -c -f /etc/haproxy/haproxy.cfg
# 启动HAProxy
systemctl start haproxy
# 设置开机自启
systemctl enable haproxy
# 查看服务状态
systemctl status haproxy
# 测试端口连通性
telnet 127.0.0.1 3306
4.4 安装配置 Keepalived(Keepalived1、Keepalived2 节点执行)
4.4.1 安装 Keepalived
# 安装Keepalived
yum install -y keepalived
# 查看版本
keepalived -v
# 备份默认配置文件
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
4.4.2 配置 Keepalived 主节点(Keepalived1:192.168.10.103)
编辑/etc/keepalived/keepalived.conf:
global_defs {
router_id LVS_DEVEL # 路由器标识,主备节点需不同
}
# 检测HAProxy状态,故障时自动切换
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state MASTER # 主节点状态
interface eth0 # 绑定的网卡,根据实际环境调整
virtual_router_id 51 # 虚拟路由ID,主备节点必须相同
priority 100 # 优先级,主节点高于备节点
advert_int 1 # 心跳间隔1秒
authentication {
auth_type PASS
auth_pass 1111 # 认证密码,主备节点必须相同
}
virtual_ipaddress {
192.168.10.100/24 # 虚拟IP地址
}
track_script {
check_haproxy
}
}
4.4.3 配置 Keepalived 备节点(Keepalived2:192.168.10.104)
编辑/etc/keepalived/keepalived.conf:
global_defs {
router_id LVS_BACKUP
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state BACKUP # 备节点状态
interface eth0
virtual_router_id 51
priority 80 # 优先级低于主节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.10.100/24
}
track_script {
check_haproxy
}
}
4.4.4 编写 HAProxy 健康检查脚本
在/etc/keepalived/目录下创建check_haproxy.sh脚本,主备节点均需执行:
cat > /etc/keepalived/check_haproxy.sh << EOF
#!/bin/bash
# 检测HAProxy进程是否存在
if ! pgrep haproxy > /dev/null; then
# 尝试重启HAProxy
systemctl restart haproxy
sleep 2
if ! pgrep haproxy > /dev/null; then
# 重启失败,停止Keepalived,触发VIP切换
systemctl stop keepalived
fi
fi
EOF
# 授权脚本执行权限
chmod +x /etc/keepalived/check_haproxy.sh
4.4.5 启动 Keepalived 服务
# 启动Keepalived
systemctl start keepalived
# 设置开机自启
systemctl enable keepalived
# 查看服务状态
systemctl status keepalived
# 查看虚拟IP绑定状态(主节点执行)
ip addr show eth0
验证标准:主节点 eth0 网卡绑定了 192.168.10.100 虚拟 IP,备节点无 VIP;主节点宕机后,备节点自动绑定 VIP。
五、高可用集群测试与验证
5.1 虚拟 IP 切换测试
- 查看主节点 VIP 状态:
ip addr show eth0,确认 VIP 绑定在 Keepalived1 节点; - 停止主节点 Keepalived 服务:
systemctl stop keepalived; - 查看备节点 VIP 状态:
ip addr show eth0,确认 VIP 自动绑定到 Keepalived2 节点; - 重启主节点 Keepalived 服务:
systemctl start keepalived,确认 VIP 自动切回主节点。
5.2 MySQL 节点故障转移测试
- 停止 Master1 节点 MySQL 服务:
systemctl stop mysqld; - 访问 HAProxy 监控页面
http://192.168.10.100:8888/stats,查看 mysql1 节点状态为 DOWN; - 通过 VIP 连接 MySQL,执行查询操作,确认服务正常,流量自动分发到 Master2 节点;
- 重启 Master1 节点 MySQL 服务,确认 mysql1 节点状态恢复为 UP,流量自动恢复轮询分发。
5.3 HAProxy 节点故障转移测试
- 停止 Master1 节点 HAProxy 服务:
systemctl stop haproxy; - 查看 Keepalived 状态,确认主节点 Keepalived 检测到 HAProxy 故障,自动停止 Keepalived,VIP 切换到备节点;
- 通过 VIP 连接 MySQL,确认服务正常,流量分发到 Master2 节点 HAProxy;
- 重启 Master1 节点 HAProxy 服务,确认 Keepalived 自动恢复,VIP 切回主节点。
5.4 数据一致性测试
- 通过 VIP 连接 MySQL,创建测试库、插入数据;
- 分别登录 Master1、Master2 节点 MySQL,查询数据,确认数据一致;
- 停止 Master1 节点 MySQL,通过 VIP 插入新数据,重启 Master1 节点,确认数据同步正常。
六、生产环境优化与最佳实践
6.1 性能优化
- MySQL 优化 :
- 调整
innodb_buffer_pool_size,设置为物理内存的 50%-70%,提升缓存命中率; - 开启慢查询日志,优化慢 SQL,减少数据库压力;
- 主主复制采用 GTID 模式,简化故障恢复流程;
- 定期清理 Binlog 日志,避免磁盘空间耗尽。
- 调整
- HAProxy 优化 :
- 调整
maxconn参数,根据服务器性能设置合理并发数; - 采用
leastconn负载均衡策略,根据后端节点连接数分发流量,提升负载均衡效率; - 开启 HAProxy 日志,监控流量与节点状态。
- 调整
- Keepalived 优化 :
- 调整
advert_int心跳间隔,设置为 1 秒,提升故障检测灵敏度; - 配置多网卡绑定,避免单网卡故障导致 VIP 切换异常;
- 开启 Keepalived 日志,监控主备切换状态。
- 调整
6.2 安全加固
- 网络安全 :
- 关闭防火墙,仅开放必要端口(3306、8888、VRRP 组播端口);
- 采用 SSL 加密 MySQL 连接,防止数据泄露;
- 限制 MySQL 远程访问 IP,仅允许应用服务器访问。
- 账号安全 :
- 定期更换 MySQL、HAProxy、Keepalived 账号密码,采用强密码策略;
- 最小权限原则,主从复制账号仅授予 REPLICATION SLAVE 权限;
- 禁止 root 用户远程访问,采用专用应用账号访问数据库。
- 数据安全 :
- 定期备份 MySQL 数据,采用全量备份 + 增量备份策略;
- 开启数据库审计,记录所有操作日志,便于问题排查;
- 主主复制采用半同步模式,提升数据一致性。
6.3 监控与运维
- 监控体系 :
- 采用 Prometheus+Grafana 监控 MySQL、HAProxy、Keepalived 状态;
- 配置告警规则,节点故障、性能异常时自动告警;
- 定期巡检集群状态,排查潜在风险。
- 运维规范 :
- 制定集群维护手册,明确故障处理流程;
- 定期演练故障转移,确保运维人员熟悉操作;
- 版本升级采用滚动升级,避免业务中断。
七、常见问题与解决方案
7.1 MySQL 主主同步失败
- 问题现象 :
Slave_IO_Running或Slave_SQL_Running为 No; - 解决方案 :
- 检查 server-id 是否唯一,主主节点必须不同;
- 检查自增步长与偏移量配置,避免主键冲突;
- 检查 Binlog 格式,必须设置为 ROW 模式;
- 重置主从复制:
stop slave; reset master;,重新配置主从同步。
7.2 HAProxy 健康检查异常
- 问题现象:后端 MySQL 节点状态为 DOWN,实际服务正常;
- 解决方案 :
- 检查 MySQL 端口连通性,确认防火墙未拦截;
- 调整健康检查参数,延长检查间隔,避免误判;
- 检查 HAProxy 日志,排查健康检查失败原因;
- 采用自定义健康检查脚本,适配业务场景。
7.3 Keepalived VIP 漂移异常
- 问题现象:主备节点同时绑定 VIP,导致网络冲突;
- 解决方案 :
- 检查虚拟路由 ID 是否一致,主备节点必须相同;
- 检查认证密码是否一致,避免认证失败;
- 检查网卡配置,确保多播地址正常通信;
- 调整优先级,主节点优先级明显高于备节点,避免抢占异常。
八、总结
本文完整实现了基于MySQL 主主复制 + HAProxy 负载均衡 + Keepalived 高可用的企业级 MySQL 高可用集群,从架构设计、环境搭建、配置部署到测试验证,全流程覆盖,所有步骤均经过实战验证,可直接用于生产环境落地。
该架构通过双重高可用保障,彻底解决了 MySQL 单节点故障问题,实现了服务的高可用、高可靠、可扩展,满足企业级业务对数据库连续性的核心需求。同时,本文提供了生产环境优化、安全加固、常见问题解决方案,帮助运维人员快速搭建并维护高可用 MySQL 集群。
在实际生产环境中,可根据业务需求进一步优化架构,如引入 MGR(MySQL Group Replication)、ProxySQL 等技术,提升集群的自动化运维能力与性能。