MySQL主主复制+Keepalived高可用集群搭建与故障切换实战

文章目录

    • 环境准备
    • 一、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 初始状态验证

  1. 查看虚拟IP所在节点:

在节点1执行:

bash 复制代码
ip addr show ens33 | grep 192.168.10.200

我的VIP现在在节点1上

正常情况下,VIP(192.168.10.200)应在节点1上。

  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 观察故障切换过程

  1. 查看VIP漂移情况:

在节点2上执行:

bash 复制代码
ip addr show ens33 | grep 192.168.10.200

VIP漂移成功

约10秒后,应能看到VIP已漂移到节点2。

  1. 查看Keepalived日志:
bash 复制代码
tail -f /var/log/messages | grep Keepalived

可以观察到故障检测和VIP切换的日志信息。

  1. 验证业务连续性:

通过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无法漂移

检查方法

  1. 确认Keepalived服务是否正常运行
  2. 检查检测脚本是否有执行权限
  3. 查看日志定位问题:tail -f /var/log/messages

五、总结

通过MySQL主主复制和Keepalived的组合,我们实现了一个高可用的数据库集群:

  1. 主主复制确保了两个节点的数据双向同步,为故障切换提供了数据基础
  2. Keepalived通过VRRP协议实现了虚拟IP的自动漂移,确保服务地址不变
  3. 当主节点故障时,系统能自动切换到备用节点,实现业务无感知续跑

这种架构适合对数据库可用性要求较高的场景,能够有效减少因单点故障导致的业务中断时间,是企业级应用的常用高可用解决方案。

相关推荐
IvorySQL1 分钟前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·11 分钟前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德14 分钟前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫39 分钟前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i1 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.1 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn1 小时前
【Redis】渐进式遍历
数据库·redis·缓存
橙露1 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot
冰暮流星1 小时前
sql语言之分组语句group by
java·数据库·sql
符哥20081 小时前
Ubuntu 常用指令集大全(附实操实例)
数据库·ubuntu·postgresql