文章目录
-
- 环境准备
- 一、MySQL主主复制配置
-
- [1.1 节点1(192.168.10.120)MySQL配置](#1.1 节点1(192.168.10.120)MySQL配置)
- [1.2 节点2(192.168.10.125)MySQL配置](#1.2 节点2(192.168.10.125)MySQL配置)
- [1.3 重启MySQL服务](#1.3 重启MySQL服务)
- [1.4 配置互为主从关系](#1.4 配置互为主从关系)
- [注意1:在节点一上操作CHANGE MASTER TO时可能出现报错:](#注意1:在节点一上操作CHANGE MASTER TO时可能出现报错:)
- [注意2:Slave_SQL_Running:为NO查看Last_SQL_Error: 如果是事务冲突导致,可执行STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;来跳过当前错误事务,让 SQL 线程继续运行。](#注意2:Slave_SQL_Running:为NO查看Last_SQL_Error: 如果是事务冲突导致,可执行STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;来跳过当前错误事务,让 SQL 线程继续运行。)
- [1.5 验证主主复制](#1.5 验证主主复制)
- 二、Keepalived高可用配置
-
- [2.1 安装Keepalived](#2.1 安装Keepalived)
- [2.2 节点1(192.168.10.120)Keepalived配置](#2.2 节点1(192.168.10.120)Keepalived配置)
- [2.3 节点2(192.168.10.125)Keepalived配置](#2.3 节点2(192.168.10.125)Keepalived配置)
- [2.4 创建MySQL检测脚本](#2.4 创建MySQL检测脚本)
- [2.5 启动Keepalived服务](#2.5 启动Keepalived服务)
- 三、高可用集群验证与故障切换演示
-
- [3.1 初始状态验证](#3.1 初始状态验证)
- [注意1:如果无法访问数据库,应该先进行赋权。GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.10.120' IDENTIFIED BY '123456' WITH GRANT OPTION;](#注意1:如果无法访问数据库,应该先进行赋权。GRANT ALL PRIVILEGES ON . TO 'root'@'192.168.10.120' IDENTIFIED BY '123456' WITH GRANT OPTION;)
- [3.2 模拟节点1故障](#3.2 模拟节点1故障)
- [3.3 观察故障切换过程](#3.3 观察故障切换过程)
- [3.4 恢复节点1](#3.4 恢复节点1)
- 四、常见问题与解决方法
-
- [4.1 执行CHANGE MASTER TO时报错](#4.1 执行CHANGE MASTER TO时报错)
- [4.2 主从复制状态异常](#4.2 主从复制状态异常)
- [4.3 VIP无法漂移](#4.3 VIP无法漂移)
- 五、总结
在企业级应用中,数据库的高可用性至关重要。本文将详细介绍如何基于MySQL主主复制和Keepalived实现数据库高可用架构,通过自动故障切换确保服务连续性。我们将使用两台服务器节点搭建集群,并演示完整的故障切换过程。
环境准备
本次实战使用的环境配置如下:
- 节点1(master1):192.168.10.120
- 节点2(master2):192.168.10.125
- 虚拟IP(VIP):192.168.10.200
- 操作系统:CentOS 7
- 软件版本:MySQL 5.7 + Keepalived 1.3.5
一、MySQL主主复制配置
主主复制(互为主从)是指两个MySQL节点互相作为对方的主库和从库,实现双向数据同步,为高可用架构提供数据基础。
1.1 节点1(192.168.10.120)MySQL配置
修改MySQL配置文件/etc/my.cnf
(或根据实际路径调整):
ini
[client]
port = 3306
socket=/usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port = 3306
character-set-server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket=/usr/local/mysql/mysql.sock
bind-address = 0.0.0.0
skip-name-resolve
max_connections=2048
default-storage-engine=INNODB
max_allowed_packet=16M
# 主从复制核心配置
server-id = 1 # 节点唯一ID,不可重复
log_bin = /usr/local/mysql/data/mysql-bin.log # 启用二进制日志
relay_log = /usr/local/mysql/data/mysql-relay-bin.log # 启用中继日志
relay_log_index = /usr/local/mysql/data/mysql-relay-bin.index
log_slave_updates = 1 # 允许从库更新写入自身binlog(主主复制必需)
auto_increment_offset = 1 # 自增起始值
auto_increment_increment = 2 # 自增步长,避免主键冲突
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
[mysql]
port = 3306
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock
auto-rehash
1.2 节点2(192.168.10.125)MySQL配置
修改MySQL配置文件/etc/my.cnf
:
ini
[client]
port = 3306
socket=/usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port = 3306
character-set-server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket=/usr/local/mysql/mysql.sock
bind-address = 0.0.0.0
skip-name-resolve
max_connections=2048
default-storage-engine=INNODB
max_allowed_packet=16M
# 主从复制核心配置
server-id = 2 # 节点唯一ID,与节点1不同
log_bin = /usr/local/mysql/data/master-bin # 启用二进制日志
relay_log = /usr/local/mysql/data/relay-log-bin # 启用中继日志
relay_log_index = /usr/local/mysql/data/relay-log-bin.index
log_slave_updates = 1 # 允许从库更新写入自身binlog
auto_increment_offset = 2 # 自增起始值,与节点1不同
auto_increment_increment = 2 # 自增步长,与节点1相同
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
[mysql]
port = 3306
socket=/usr/local/mysql/mysql.sock
auto-rehash
1.3 重启MySQL服务
在两个节点上分别重启MySQL服务,使配置生效:
bash
# 停止MySQL服务
systemctl stop mysqld
# 启动MySQL服务
systemctl start mysqld
# 设置开机自启
systemctl enable mysqld
1.4 配置互为主从关系
步骤1:在节点1创建同步用户
登录节点1的MySQL命令行:
bash
mysql -u root -p
执行以下SQL创建用于同步的用户:
sql
-- 创建同步用户(允许节点2连接)
CREATE USER 'repl'@'192.168.10.125' IDENTIFIED BY 'YourStrongPassword';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.125';
-- 刷新权限
FLUSH PRIVILEGES;
-- 查看节点1的主库状态(记录File和Position值)
SHOW MASTER STATUS;
执行结果类似:
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
步骤2:在节点2配置作为节点1的从库
登录节点2的MySQL命令行:
bash
mysql -u root -p
执行以下SQL配置从库:
sql
-- 先停止slave线程(如果已配置)
STOP SLAVE;
-- 配置主库信息(替换为实际的File和Position值)
CHANGE MASTER TO
MASTER_HOST='192.168.10.120',
MASTER_USER='repl',
MASTER_PASSWORD='YourStrongPassword',
MASTER_LOG_FILE='mysql-bin.000001', -- 节点1的File值
MASTER_LOG_POS=154; -- 节点1的Position值
-- 启动从库
START SLAVE;
-- 查看从库状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)
SHOW SLAVE STATUS\G
步骤3:在节点2创建同步用户
继续在节点2的MySQL命令行执行:
sql
-- 创建同步用户(允许节点1连接)
CREATE USER 'repl'@'192.168.10.120' IDENTIFIED BY 'YourStrongPassword';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.120';
-- 刷新权限
FLUSH PRIVILEGES;
-- 查看节点2的主库状态(记录File和Position值)
SHOW MASTER STATUS;
步骤4:在节点1配置作为节点2的从库
登录节点1的MySQL命令行,执行:
sql
-- 先停止slave线程
STOP SLAVE;
-- 配置主库信息(替换为节点2的实际信息)
CHANGE MASTER TO
MASTER_HOST='192.168.10.125',
MASTER_USER='repl',
MASTER_PASSWORD='YourStrongPassword',
MASTER_LOG_FILE='master-bin.000001', -- 节点2的File值
MASTER_LOG_POS=154; -- 节点2的Position值
-- 启动从库
START SLAVE;
-- 查看从库状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)
SHOW SLAVE STATUS\G
注意1:在节点一上操作CHANGE MASTER TO时可能出现报错:

解决方法:在节点一上执行SLAVE IO_THREAD;
后重新执行CHANGE MASTER TO。最后再执行START SLAVE;
SHOW SLAVE STATUS\G查看互为主从的同步状态是否正确:
注意2:Slave_SQL_Running:为NO查看Last_SQL_Error: 如果是事务冲突导致,可执行STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;来跳过当前错误事务,让 SQL 线程继续运行。
1.5 验证主主复制
在节点1创建测试数据库和表:
sql
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));
INSERT INTO users (name) VALUES ('test1');
在节点2查看是否同步成功:
sql
USE testdb;
SELECT * FROM users;
同样,在节点2插入数据,检查节点1是否同步:
sql
INSERT INTO users (name) VALUES ('test2');
在节点1验证:
sql
USE testdb;
SELECT * FROM users;
如果两边都能看到新增的数据,说明主主复制配置成功。
二、Keepalived高可用配置
Keepalived通过VRRP(虚拟路由冗余协议)实现虚拟IP的漂移,当主节点故障时自动将VIP切换到备用节点,实现高可用。
2.1 安装Keepalived
在两个节点上分别安装Keepalived:
bash
yum install -y keepalived
2.2 节点1(192.168.10.120)Keepalived配置
创建或修改配置文件/etc/keepalived/keepalived.conf
:
conf
global_defs {
router_id LVS_MASTER1 # 节点唯一标识
}
# 定义MySQL检测脚本
vrrp_script check_mysql {
script "/etc/keepalived/check_mysql.sh" # 检测脚本路径
interval 2 # 检测间隔(秒)
weight 2 # 权重调整值
fall 3 # 连续失败3次视为故障
rise 2 # 连续成功2次视为恢复
}
vrrp_instance VI_1 {
state MASTER # 初始状态为主节点
interface ens33 # 网络接口(根据实际情况修改)
virtual_router_id 51 # 虚拟路由ID(两个节点必须相同)
priority 100 # 优先级(主节点高于备用节点)
advert_int 1 # 心跳间隔(秒)
# 认证配置
authentication {
auth_type PASS
auth_pass 1111 # 认证密码(两个节点必须相同)
}
# 虚拟IP配置
virtual_ipaddress {
192.168.10.200/24 # 虚拟IP地址
}
# 引用检测脚本
track_script {
check_mysql
}
}
2.3 节点2(192.168.10.125)Keepalived配置
创建或修改配置文件/etc/keepalived/keepalived.conf
:
conf
global_defs {
router_id LVS_MASTER2 # 节点唯一标识
}
# 定义MySQL检测脚本
vrrp_script check_mysql {
script "/etc/keepalived/check_mysql.sh"
interval 2
weight 2
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP # 初始状态为备用节点
interface ens33 # 网络接口(与节点1一致)
virtual_router_id 51 # 与节点1相同
priority 90 # 优先级低于主节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 与节点1相同
}
virtual_ipaddress {
192.168.10.200/24 # 相同的虚拟IP
}
track_script {
check_mysql
}
}
2.4 创建MySQL检测脚本
在两个节点上创建相同的检测脚本/etc/keepalived/check_mysql.sh
:
bash
#!/bin/bash
# 检测MySQL是否正常运行
# 尝试连接MySQL并执行简单命令
mysql -uroot -p123456 -e "show status;" > /dev/null 2>&1
# 检查命令执行结果
if [ $? -ne 0 ]; then
# MySQL异常,停止Keepalived让VIP漂移
systemctl stop keepalived
fi
为脚本添加执行权限:
bash
chmod +x /etc/keepalived/check_mysql.sh
2.5 启动Keepalived服务
在两个节点上分别启动Keepalived服务:
bash
# 启动服务
systemctl start keepalived
# 设置开机自启
systemctl enable keepalived
# 查看服务状态
systemctl status keepalived
三、高可用集群验证与故障切换演示
3.1 初始状态验证
- 查看虚拟IP所在节点:
在节点1执行:
bash
ip addr show ens33 | grep 192.168.10.200

我的VIP现在在节点1上
正常情况下,VIP(192.168.10.200)应在节点1上。
- 通过VIP连接数据库验证:
bash
mysql -h 192.168.10.200 -u root -p
应能成功连接到数据库。
注意1:如果无法访问数据库,应该先进行赋权。GRANT ALL PRIVILEGES ON . TO 'root'@'192.168.10.120' IDENTIFIED BY '123456' WITH GRANT OPTION;
FLUSH PRIVILEGES;
3.2 模拟节点1故障
在节点1上停止MySQL服务,模拟数据库故障:
bash
systemctl stop mysqld
3.3 观察故障切换过程
- 查看VIP漂移情况:
在节点2上执行:
bash
ip addr show ens33 | grep 192.168.10.200

VIP漂移成功
约10秒后,应能看到VIP已漂移到节点2。
- 查看Keepalived日志:
bash
tail -f /var/log/messages | grep Keepalived
可以观察到故障检测和VIP切换的日志信息。
- 验证业务连续性:
通过VIP连接数据库,确认仍能正常访问:
bash
mysql -h 192.168.10.200 -u root -p

在数据库中插入数据,验证服务正常:
sql
USE testdb;
INSERT INTO users (name) VALUES ('failover_test');
3.4 恢复节点1
在节点1上重启服务:
bash
# 重启MySQL
systemctl start mysqld
# 重启Keepalived
systemctl start keepalived
观察VIP是否根据优先级设置回切到节点1(默认配置下会回切)。
VIP回切成功
检查数据同步情况,确认节点1恢复后能同步节点2上新增的数据:
sql
USE testdb;
SELECT * FROM users;
四、常见问题与解决方法
4.1 执行CHANGE MASTER TO时报错
错误信息 :ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
解决方法:
sql
# 在操作的节点上执行
STOP SLAVE;
RESET SLAVE ALL; # 清除原有配置
# 重新执行CHANGE MASTER TO命令
4.2 主从复制状态异常
检查方法:
sql
SHOW SLAVE STATUS\G
常见问题处理:
- 若Slave_IO_Running为Connecting:检查网络连接、同步用户权限、防火墙设置
- 若Slave_SQL_Running为No:可能是数据冲突,可通过
SET GLOBAL sql_slave_skip_counter = 1;
跳过错误后再启动
4.3 VIP无法漂移
检查方法:
- 确认Keepalived服务是否正常运行
- 检查检测脚本是否有执行权限
- 查看日志定位问题:
tail -f /var/log/messages
五、总结
通过MySQL主主复制和Keepalived的组合,我们实现了一个高可用的数据库集群:
- 主主复制确保了两个节点的数据双向同步,为故障切换提供了数据基础
- Keepalived通过VRRP协议实现了虚拟IP的自动漂移,确保服务地址不变
- 当主节点故障时,系统能自动切换到备用节点,实现业务无感知续跑
这种架构适合对数据库可用性要求较高的场景,能够有效减少因单点故障导致的业务中断时间,是企业级应用的常用高可用解决方案。