MHA,mysql 高可用集群的搭建与实现

目录

目录

MHA的简单介绍:

1. 核心组件

2. 工作原理(故障切换过程)

实验设备介绍:

MHA 集群设备信息表

设备的基础准备:

配置主从复制:

安装与配置MHA

首先配置主机名解析:

创建 MHA 管理用户

校验配置并启动 MHA:

检测MySQL的复制状态:

启动MHA manager

安装与配置proxy SQL

添加 ProxySQL 官方仓库:

安装与配置ProxySQL

创建MHA 与 ProxySQL 联动脚本

执行高可用切换验证


MHA的简单介绍:

MySQL MHA 是一款用于 MySQL 高可用性 的开源软件,它的核心功能是自动完成主库故障切换,并尽可能保证数据一致性。

在一个经典的 MySQL 主从复制 集群中:

  • 有一个 主库 ,负责处理应用的读写请求。

  • 有一个或多个 从库 ,复制主库的数据,负责读请求或作为备份。

问题: 如果主库因为硬件故障、网络中断等原因宕机了,整个系统将无法写入,业务会中断。这时需要人工干预,选择一个最新的从库,将其提升为新的主库,并让其他从库和应用程序指向这个新主库。这个过程手动操作非常缓慢、容易出错,而且会导致长时间的停机。

MHA 的作用就是自动化这个过程,在几十秒内完成故障切换,最大限度减少业务中断时间。

1. 核心组件
  • MHA Manager(管理节点): 这是“大脑”,通常是一个独立的服务器。它负责监控所有 MySQL 节点(主库和从库)的健康状态。

  • MHA Node(数据节点): 这是“手脚”,运行在每一个 MySQL 服务器上。它负责执行具体的命令,比如切换虚拟 IP、解析二进制日志等。

2. 工作原理(故障切换过程)

假设一个一主两从的架构,MHA Manager 会定期 ping 主库。

  1. 监控与探测: MHA Manager 发现主库无法连接。

  2. 确认故障: 通过多次重试和检查,确认主库确实发生了故障。

  3. 选择新主库: MHA 会从存活的从库中,选择数据最新(即拥有最新二进制日志位置)的那个从库作为候选新主库。

  4. 数据补偿(关键步骤):

    • 如果某个从库(我们称之为 Slave B)比候选新主库的数据稍微旧一点,MHA 会从宕机的主库服务器上尝试抢救出还没有被复制的二进制日志。

    • 将这些日志应用到候选新主库上,从而最大限度地保证数据不丢失。这是 MHA 的一个巨大优势。

  5. 提升新主库: 将选定的从库提升为新的主库。

  6. 切换其他从库: 让其他存活的从库开始从新的主库进行复制。

  7. 虚拟 IP 切换(可选但常用): 通知应用程序(或通过修改虚拟 IP)将写请求指向新的主库地址。

整个过程通常是 10-30秒 内完成,对应用来说是透明的。

实验设备介绍:

MHA 集群设备信息表

角色分配IP 地址主机名 主要软件功能描述
主库 (Master)192.168.4.50host50MySQL负责处理应用的读写请求,是复制的源库。
从库1 (Slave1)192.168.4.51host51MySQL复制主库的数据,通常用于读负载均衡,是主库的候选。
从库2 (Slave2)192.168.4.52host52MySQL复制主库的数据,用于冗余和读负载均衡。
MHA Manager 节点192.168.4.53host53MHA Manager, MySQL (客户端)监控节点

设备的基础准备:

三台机器都需要安装MySQL,host53不需要安装。四台机器全部需要安装:mha4mysql-node-0.58-0.el7.centos.noarch.rpm,host53需要额外安装mha4mysql-manager-0.58-0.el7.centos.noarch.rpm。

yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm
yum -y install mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

此外host53机器需要连接外网下载对应的包

yum -y install wget.x86_64
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
yum install -y epel-release
yum install -y perl-Config-Tiny perl-Mail-Sender perl-Mail-Sendmail perl-MIME-Lite perl-Parallel-ForkManager perl-Log-Dispatch

配置主从复制:

对于host50,51,52做如下配置:

vim /etc/my.cnf

对应的server id号分别是1,2,3。把如下内容分别添加进去再重启MySQL:

master (192.168.4.50):
[mysqld]
server-id=1
log_bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=1
relay_log_recovery=ON
binlog_format=ROW
replica1 (192.168.4.51):
[mysqld]
server-id=2
log_bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
read_only=1
relay_log_recovery=ON
replica2 (192.168.4.52):
[mysqld]
server-id=3
log_bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
read_only=1
relay_log_recovery=ON

重启MySQL:

systemctl restart mysqld

回到host50上,进入MySQL中执行下面三个命令:

CREATE USER 'repl'@'%' IDENTIFIED BY '123qqq...A';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

再在host51,52上执行下面的命令:

CHANGE MASTER TO MASTER_HOST='192.168.4.50',
  MASTER_USER='repl',
  MASTER_PASSWORD='123qqq...A',
  MASTER_AUTO_POSITION=1;

START SLAVE;

SHOW SLAVE STATUS\G
#确认 Slave_IO_Running: Yes、Slave_SQL_Running: Yes

安装与配置MHA

这里的安装是在host53上进行,查看设备的基础准备。

首先配置主机名解析:

先在host53上执行这个命令,配置主机名解析:

echo -e "192.168.4.50 host50\n192.168.4.51 host51\n192.168.4.52 host52\n192.168.4.53 host53" >> /etc/hosts

之后在host53上生成密钥对,复制给另外3台机器

具体操作如下,操作完成应该得到这样的结果:

ssh-keygen -t rsa
ssh-copy-id root@192.168.4.50
ssh-copy-id root@192.168.4.51
ssh-copy-id root@192.168.4.52

接下来测试一下,在host53上执行如下命令看看是否能连上:

ssh host50 "hostname"

参考host53的操作,在host50,51,52上都要配置好。

创建 MHA 管理用户

在host50上执行:

-- 创建 MHA 管理用户
CREATE USER 'mha'@'%' IDENTIFIED BY '123qqq...A';

-- 授予必要权限
GRANT REPLICATION CLIENT, SUPER, PROCESS, RELOAD, SELECT ON *.* TO 'mha'@'%';

-- 刷新权限
FLUSH PRIVILEGES;

-- 验证用户创建
SELECT user, host FROM mysql.user WHERE user = 'mha';

校验配置并启动 MHA:

在host53上执行:

masterha_check_ssh --conf=/etc/mha/app1.cnf

看到以上结果就说明成功了。

检测MySQL的复制状态:

masterha_check_repl --conf=/etc/mha/app1.cnf

在最后看到以上信息就说明也ok了。

启动MHA manager

依旧在host53上执行如下操作:

# 启动 MHA Manager
nohup masterha_manager --conf=/etc/mha/app1.cnf > /var/log/mha/manager.log 2>&1 &

# 检查启动状态
masterha_check_status --conf=/etc/mha/app1.cnf

看到如图的内容说明没有问题。

安装与配置proxy SQL

添加 ProxySQL 官方仓库:

依旧是在host53上。

# 安装必要的依赖
yum install -y gnupg2

# 下载并安装 ProxySQL 仓库
cat > /etc/yum.repos.d/proxysql.repo << 'EOF'
[proxysql]
name=ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/centos/\$releasever
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key
EOF

安装与配置ProxySQL

# 清理 yum 缓存并安装
yum clean all
yum install -y proxysql

安装完成之后查看状态:

# 启动并设置开机自启
systemctl enable --now proxysql

# 检查服务状态
systemctl status proxysql

因为host53没有安装MySQL,所以要安装mariadb,再进入到proxy SQL中:

yum -y install mariadb
mysql -uadmin -padmin -h 127.0.0.1 -P6032

接下来将以下所有 SQL 命令一次性复制粘贴到MySQL [(none)]> 提示符下:

-- 清空现有服务器配置
DELETE FROM mysql_servers;

-- 添加 MySQL 服务器
INSERT INTO mysql_servers (hostgroup_id, hostname, port, max_connections) VALUES
(10, '192.168.4.50', 3306, 200), -- 写组 (writer)
(20, '192.168.4.51', 3306, 200), -- 读组 (reader)
(20, '192.168.4.52', 3306, 200); -- 读组 (reader)

-- 清空现有用户配置
DELETE FROM mysql_users;

-- 添加 MySQL 用户
INSERT INTO mysql_users (username, password, default_hostgroup, transaction_persistent) VALUES
('appuser', 'AppUs3r#P@ssw0rd', 10, 1),
('proxy_monitor', 'Mha#Adm1nP@ss', 10, 0);

-- 清空现有查询规则
DELETE FROM mysql_query_rules;

-- 添加查询路由规则
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply) VALUES
(1, 1, '^SELECT.*FOR UPDATE', 10, 1),  -- SELECT FOR UPDATE 路由到写组
(2, 1, '^SELECT', 20, 1);              -- 普通 SELECT 路由到读组

-- 加载配置到运行时
LOAD MYSQL SERVERS TO RUNTIME;
LOAD MYSQL USERS TO RUNTIME;
LOAD MYSQL QUERY RULES TO RUNTIME;

-- 保存配置到磁盘
SAVE MYSQL SERVERS TO DISK;
SAVE MYSQL USERS TO DISK;
SAVE MYSQL QUERY RULES TO DISK;

现在需要登录到 MySQL 主库 (192.168.4.50) 创建对应的用户:

-- 创建允许远程连接的 root 用户
CREATE USER 'root'@'%' IDENTIFIED BY '123qqq...A';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

-- 验证用户创建
SELECT user, host FROM mysql.user WHERE user = 'root';

在host53上看看能否连接:

mysql -h 192.168.4.50 -u root -p123qqq...A

在host53上做如下操作:

-- 创建应用用户
CREATE USER 'appuser'@'%' IDENTIFIED BY 'AppUs3r#P@ssw0rd';
GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'%';

-- 创建 ProxySQL 监控用户
CREATE USER 'proxy_monitor'@'%' IDENTIFIED BY 'Mha#Adm1nP@ss';
GRANT USAGE ON *.* TO 'proxy_monitor'@'%';

-- 刷新权限
FLUSH PRIVILEGES;

-- 验证用户创建
SELECT user, host FROM mysql.user WHERE user IN ('appuser', 'proxy_monitor');

在host50上做如下操作:

创建MHA 与 ProxySQL 联动脚本

在host53上创建脚本:

# 1. 创建脚本目录(如果不存在)
mkdir -p /usr/local/bin

# 2. 创建脚本文件
cat > /usr/local/bin/mha_post_failover.sh << 'EOF'
#!/bin/bash
set -euo pipefail

NEW_MASTER="${1:-${NEW_MASTER_HOST:-}}"
if [ -z "$NEW_MASTER" ]; then
  echo "[ERROR] No new master provided" >&2
  exit 1
fi

PROXY_ADMIN_USER="admin"
PROXY_ADMIN_PASS="admin"
PROXY_ADMIN_HOST="127.0.0.1"
PROXY_ADMIN_PORT=6032

BACKENDS=("192.168.4.50" "192.168.4.51" "192.168.4.52")
WRITER_HG=10
READER_HG=20

mysql_admin() {
  mysql -u${PROXY_ADMIN_USER} -p${PROXY_ADMIN_PASS} -h ${PROXY_ADMIN_HOST} -P ${PROXY_ADMIN_PORT} -e "$1"
}

mysql_admin "DELETE FROM mysql_servers WHERE hostgroup_id=${WRITER_HG};"
mysql_admin "INSERT INTO mysql_servers (hostgroup_id, hostname, port, max_connections) VALUES (${WRITER_HG}, '${NEW_MASTER}', 3306, 200);"

for h in "${BACKENDS[@]}"; do
  if [ "$h" != "$NEW_MASTER" ]; then
    mysql_admin "REPLACE INTO mysql_servers (hostgroup_id, hostname, port, max_connections) VALUES (${READER_HG}, '${h}', 3306, 200);"
  fi
done

mysql_admin "LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;"
mysql_admin "SELECT hostgroup_id, hostname, status FROM runtime_mysql_servers;"
echo "[INFO] ProxySQL updated: writer -> ${NEW_MASTER}"
EOF

# 3. 设置执行权限
chmod +x /usr/local/bin/mha_post_failover.sh

# 4. 测试脚本语法
bash -n /usr/local/bin/mha_post_failover.sh

# 5. 手动测试脚本功能
/usr/local/bin/mha_post_failover.sh 192.168.4.51

执行高可用切换验证

脚本创建完成就可以开始验证了。

# 查看当前的 ProxySQL 配置
mysql -u admin -padmin -h 127.0.0.1 -P6032 -e "SELECT hostgroup_id, hostname, port, status FROM runtime_mysql_servers ORDER BY hostgroup_id;"

# 检查 MHA 状态
masterha_check_status --conf=/etc/mha/app1.cnf

# 创建测试数据
mysql -u appuser -p123qqq...A -h 127.0.0.1 -P6033 -e "CREATE DATABASE IF NOT EXISTS failover_test; USE failover_test; CREATE TABLE IF NOT EXISTS test_table (id INT AUTO_INCREMENT PRIMARY KEY, data VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP); INSERT INTO test_table (data) VALUES ('before_failover'); SELECT * FROM test_table;"

再开一个host53的终端:

# 在一个新的终端窗口中实时监控 MHA 日志
tail -f /var/log/mha/app1/manager.log

创建测试数据:

mysql -u appuser -p123qqq...A -h 127.0.0.1 -P6033 << 'EOF'
CREATE DATABASE IF NOT EXISTS failover_test;
CREATE TABLE IF NOT EXISTS failover_test.test_table (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    data VARCHAR(100), 
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO failover_test.test_table (data) VALUES ('before_failover');
SELECT * FROM failover_test.test_table;
EOF

接下来就可以模拟主机宕机了。

# 停止 host50 的 MySQL 服务
ssh host50 "systemctl stop mysqld"

# 确认服务已停止
ssh host50 "systemctl status mysqld"

ok,接下来在监控日志中看看是否成功了,看看你的是不是如下结果。

成功切换后再在host53上输入以下命令来验证:

# 检查 ProxySQL 配置是否自动更新
mysql -u admin -padmin -h 127.0.0.1 -P6032 -e "SELECT hostgroup_id, hostname, port, status FROM runtime_mysql_servers ORDER BY hostgroup_id;"

# 检查 MHA 状态
masterha_check_status --conf=/etc/mha/app1.cnf

# 测试应用连接(应该连接到新的主库)
mysql -u appuser -p123qqq...A -h 127.0.0.1 -P6033 -e "SELECT @@hostname as new_master;"

# 测试数据读写功能
mysql -u appuser -p123qqq...A -h 127.0.0.1 -P6033 -e "USE failover_test; INSERT INTO test_table (data) VALUES ('after_failover'); SELECT * FROM test_table;"

可以看到再次成功验证了。

配置 host50 作为 host52 的从库

# 在 host52 (新主库) 上获取复制信息
mysql -h 192.168.4.52 -u root -p123qqq...A -e "SHOW MASTER STATUS\G"

# 在 host50 上配置复制到新的主库 host52
mysql -h 192.168.4.50 -u root -p123qqq...A -e "
STOP SLAVE;
CHANGE MASTER TO 
MASTER_HOST='192.168.4.52',
MASTER_USER='repl',
MASTER_PASSWORD='123qqq...A',
MASTER_AUTO_POSITION=1;
START SLAVE;
SHOW SLAVE STATUS\G"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值