前言
MySQL 数据库 MHA(Master High Availability)高可用集群是一种用于提高 MySQL 数据库可用性的解决方案。它通过自动故障切换和监控来确保数据库系统在主服务器发生故障时能够快速切换到备用服务器;在 MHA 高可用集群中,Master 和 Slave 之间通过复制机制保持数据同步,而 MHA Manager 监控数据库服务器的健康状态,并在必要时执行自动故障转移,确保数据库系统的持续可用性。
目录
一、MHA 介绍
1. 概述
2. 主从复制同步方式
2.1 异步复制
2.2 同步复制
2.3 半同步复制
3. 组成
3.1 管理节点(Manager Node)
3.2 数据节点(Data Node)
4. 特点
5. 工作原理
二、MySQL 配置主从复制
1. 修改 master、slave1master、slave2 Mysql 核心配置文件
2. 在 master、slave1master、slave2 上创建两个软链接
3. 配置 mysql 一主两从
三、安装 MHA 所有组件
1. 安装 MHA 软件
2. 在所有服务器上配置无密码认证
3. 在 manager 节点上配置 MHA
三、单点故障模拟
1. 关闭服务
2. 模拟修复
一、MHA 介绍
1. 概述
① MHA 是 MySQL 高可用环境下故障切换和主从复制的软件,用于数据库的高可用性解决方案
② MHA 能够监控主服务器、数据库集群的状态,发生故障能在0-30秒内自动切换,可以解决单点故障
③ MHA 能在故障切换的过程中最大程度上保证数据的一致性以达到真正意义上的高可用
2. 主从复制同步方式
主从复制技术不仅确保了数据在主从服务器之间的一致性、支持读写分离,同时还提供了故障恢复和高可用性的能力,为数据库系统的稳定性、可靠性和性能提供了重要支持。
2.1 异步复制
客户端提交事务后,只要 master 完成客户端提交的事务,就会直返回信息给客户端,并不关心与 slave 的数据是否同步。
2.2 同步复制
客户端提交事务后,master 需要等待所有的 slave 数据同步完成,才会将信息返回给客户端。
2.3 半同步复制
客户端提交事务后,只要有一个 slave 数据与 master 完成同步,master 就会将信息返回给客户端。
3. 组成
3.1 管理节点(Manager Node)
- 功能:管理节点负责监控数据库集群中的主从复制拓扑结构,监控主服务器的健康状况,以及在主服务器发生故障时执行自动故障转移操作。
- 原理:管理节点通过定期检查数据库服务器的可用性和复制状态来监控数据库集群。当检测到主服务器故障时,管理节点会自动将一个从服务器提升为新的主服务器,确保数据库系统的高可用性。同时管理节点随之关闭。
- 配置:在MHA中,通常会有一个或多个管理节点,一般部署在一台独立的机器上,也可以部署在一台slave上。
3.2 数据节点(Data Node)
- 功能:数据节点是实际存储数据的MySQL数据库服务器,通常包括主服务器(master)和从服务器(slave)。
- 原理:数据节点负责处理实际的数据库读写操作,主服务器用于接收写操作并将数据变更复制到从服务器上,从服务器则用于处理读操作。
- 配置:MHA通过管理节点管理数据节点之间的复制关系和故障转移操作,确保数据节点的高可用性和数据一致性。
注意:管理节点依赖于数据节点,部署 MHA 需要先安装 Data Node 再安装 Manager Node。
4. 特点
① 自动故障切换过程中,MHA 试图从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失
② 使用半同步复制,可以大大降低数据丢失的风险,如果只有一个 slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此可以保证所有节点的数据一致性
③ 目前 MHA 支持一主多从架构,最少三台服务,即一主两从
5. 工作原理
① MHA 能够自动监控数据库集群中的主服务器状态,分配 vip(虚拟IP) 给集群,默认绑定 master
② 当主服务器发生故障或不可访问时,从宕机崩溃的master 保存二进制日志事件(binlog events),并应用差异的中继日志(relay log)到其他的 slave
③ 然后会将指定备用切换的 slave 或者识别与 master 数据偏移量最少的(即数据最全、最接近主服务器)从服务器作为新的主服务器,此时 vip 会绑定新的 master,应用从 master 保存的二进制日志事件
④ 当原主服务器恢复正常时,MHA 可以协助将其重新加入数据库集群,作为新的从服务器实现主从复制关系,实现故障后的平稳过渡
二、MySQL 配置主从复制
环境准备:关闭所有设备防火墙及核心防护
master 节点服务器:CentOS7(64 位) mysql1/192.168.190.100,安装mysql5.7、MHA node 组件
slave1 节点服务器:CentOS7(64 位) mysql2/192.168.190.101,安装mysql5.7、MHA node 组件
slave2 节点服务器:CentOS7(64 位) mysql3/192.168.190.102,安装mysql5.7、MHA node 组件mha manager 节点服务器:CentOS7(64 位) manager/192.168.190.103 ,安装MHA node 和 manager 组件
1. 修改 master、slave1master、slave2 Mysql 核心配置文件
master:
[root@master ~]# vim /etc/my.cnf
[client]
#default-character-set=utf8 #注销
[mysqld]
server-id = 1
log_bin = master-bin #开启二进制日志
binlog_format = MIXED #设置binglog的格式
log-slave-updates=true #允许slave从master复制数据
[root@master ~]# systemctl restart mysqld.service
slave1master:
[root@slave1master ~]# vim /etc/my.cnf
[client]
#default-character-set=utf8 #注销
[mysqld]
server-id = 2
relay-log = relay-log-bin #开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index = slave-relay-bin.index #定义中继日志文件的位置和名称
log_bin = master-bin
binlog_format = MIXED
[root@slave1master ~]# systemctl restart mysqld.service
[root@slave2 ~]# vim /etc/my.cnf
[client]
#default-character-set=utf8 #注销
[mysqld]
server-id = 3
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index
[root@slave2 ~]# systemctl restart mysqld.service
2. 在 master、slave1master、slave2 上创建两个软链接
ln -s /usr/local/mysql/bin/mysql /usr/sbin/
ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/
3. 配置 mysql 一主两从
① 分别在所有数据库节点进行 mysql 授权
mysql -u root -p'123456'
mysql> grant replication slave on *.* to 'myslave'@'192.168.190.%' identified by '123456';
mysql> grant all privileges on *.* to 'mha'@'192.168.190.%' identified by 'manager';
mysql> flush privileges;
② 在 master 节点查看二进制文件和同步点
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 895 | | | |
+-------------------+----------+--------------+------------------+-------------------+
③ 分别在 slave1master、slave2 节点执行同步操作
mysql> change master to master_host='192.168.190.100',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=895;
mysql> start slave;
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes # IO和SQL线程都是Yes,代表同步正常
④ 设置两个从库为只读模式
mysql> set global read_only=1;
⑤ 插入数据测试数据库同步
在 Master 主库插入条数据,测试是否同步
master:
mysql> create database school;
mysql> use school
mysql> create table class (id int,name char(15));
mysql> insert into class values (1,'zs');
slave1master、slave2:
mysql> select * from school.class;
+------+------+
| id | name |
+------+------+
| 1 | zs |
+------+------+
三、安装 MHA 所有组件
1. 安装 MHA 软件
① 所有服务器上都安装 MHA 依赖的环境,首先安装 epel 源
yum install epel-release --nogpgcheck -y
yum install -y perl-DBD-MySQL \
perl-Config-Tiny \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
perl-ExtUtils-CBuilder \
perl-ExtUtils-MakeMaker \
perl-CPAN
② 安装 MHA 软件包,先在所有服务器上必须先安装 node 组件
必须先安装 node 组件,最后在 MHA-manager 节点上安装 manager 组件,因为 manager 依赖 node 组件。
cd /opt/
ls
mha4mysql-node-0.57.tar.gz
tar zxvf mha4mysql-node-0.57.tar.gz
cd mha4mysql-node-0.57/
ls
AUTHORS bin COPYING debian inc lib Makefile.PL MANIFEST META.yml README rpm t
perl Makefile.PL
make && make install
③ 在 MHA manager 节点上安装 manager 组件
[root@mha opt]# ls
mha4mysql-manager-0.57.tar.gz mha4mysql-node-0.57
[root@mha opt]# tar zxvf mha4mysql-manager-0.57.tar.gz
[root@mha opt]# cd mha4mysql-manager-0.57/
[root@mha mha4mysql-manager-0.57]# ls
AUTHORS bin COPYING debian inc lib Makefile.PL MANIFEST META.yml README rpm samples t tests
[root@mha mha4mysql-manager-0.57]# perl Makefile.PL
[root@mha mha4mysql-manager-0.57]# make && make install
manager 组件安装后在/usr/local/bin 下面会生成几个工具,主要包括以下几个:
# masterha_check_ssh 检查 MHA 的 SSH 配置状况
# masterha_check_repl 检查 MySQL 复制状况
# masterha_manger 启动 manager的脚本
# masterha_check_status 检测当前 MHA 运行状态
# masterha_master_monitor 检测 master 是否宕机
# masterha_master_switch 控制故障转移(自动或者 手动)
# masterha_conf_host 添加或删除配置的 server 信息
# masterha_stop 关闭manager
node 组件安装后也会在/usr/local/bin 下面会生成几个脚本(这些工具通常由 MHAManager 的脚本触发,无需人为操作)主要如下:
# save_binary_logs 保存和复制 master 的二进制日志
# apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的 slave
# filter_mysqlbinlog 去除不必要的 ROLLBACK 事件(MHA 已不再使用这个工具)
# purge_relay_logs 清除中继日志(不会阻塞 SQL 线程)
2. 在所有服务器上配置无密码认证
① 在 manager 节点上配置到所有数据库节点的无密码认证
[root@mha ~]# ssh-keygen -t rsa #一直按回车键
[root@mha ~]# ssh-copy-id 192.168.190.100
[root@mha ~]# ssh-copy-id 192.168.190.101
[root@mha ~]# ssh-copy-id 192.168.190.102
② 在 master 上配置到数据库节点 slave1master 和 slave2 的无密码认证
[root@master ~]# ssh-keygen -t rsa
[root@master ~]# ssh-copy-id 192.168.190.101
[root@master ~]# ssh-copy-id 192.168.190.102
③ 在 slave1master 上配置到数据库节点 master 和 slave2 的无密码认证
[root@slave1master ~]# ssh-keygen -t rsa
[root@slave1master ~]# ssh-copy-id 192.168.190.100
[root@slave1master ~]# ssh-copy-id 192.168.190.102
④ 在 slave2 上配置到数据库节点 master 和 slave1master 的无密码认证
[root@slave2 ~]# ssh-keygen -t rsa
[root@slave2 ~]# ssh-copy-id 192.168.190.100
[root@slave2 ~]# ssh-copy-id 192.168.190.101
3. 在 manager 节点上配置 MHA
① 在 manager 节点上复制相关脚本到/usr/local/bin 目录
[root@mha ~]# cp -rp /opt/mha4mysql-manager-0.57/samples/scripts /usr/local/bin
[root@mha ~]# ls /usr/local/bin/scripts/
master_ip_failover # 自动切换时 VIP 管理的脚本
master_ip_online_change # 在线切换时 vip 的管理
power_manager # 故障发生后关闭主机的脚本
send_report # 因故障切换后发送报警的脚本
② 复制 VIP 管理的脚本,并编辑粘贴脚本
[root@mha ~]# cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin
[root@mha ~]# vim /usr/local/bin/master_ip_failover
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
my (
$command, $ssh_user, $orig_master_host, $orig_master_ip,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port
);
#############################添加内容部分#########################################
my $vip = '192.168.190.200'; #指定vip的地址
my $brdc = '192.168.190.255'; #指定vip的广播地址
my $ifdev = 'ens33'; #指定vip绑定的网卡
my $key = '1'; #指定vip绑定的虚拟网卡序列号
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip"; #代表此变量值为ifconfig ens33:1 192.168.10.200
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down"; #代表此变量值为ifconfig ens33:1 192.168.10.200 down
my $exit_code = 0; #指定退出状态码为0
#my $ssh_start_vip = "/usr/sbin/ip addr add $vip/24 brd $brdc dev $ifdev label $ifdev:$key;/usr/sbin/arping -q -A -c 1 -I $ifdev $vip;iptables -F;";
#my $ssh_stop_vip = "/usr/sbin/ip addr del $vip/24 dev $ifdev label $ifdev:$key";
##################################################################################
GetOptions(
'command=s' => \$command,
'ssh_user=s' => \$ssh_user,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
);
exit &main();
sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $command eq "stop" || $command eq "stopssh" ) {
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
exit 0;
}
else {
&usage();
exit 1;
}
}
sub start_vip() {
`ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
## A simple system call that disable the VIP on the old_master
sub stop_vip() {
`ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
③ 创建 MHA 软件目录并拷贝配置文件,这里使用app1.cnf配置文件来管理 mysql 节点服务器
[root@mha ~]# mkdir /etc/masterha
[root@mha ~]# cp /opt/mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/masterha
[server default]
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
master_binlog_dir=/usr/local/mysql/data
master_ip_failover_script=/usr/local/bin/master_ip_failover
master_ip_online_change_script=/usr/local/bin/master_ip_online_change
password=manager
ping_interval=1
remote_workdir=/tmp
repl_password=123456
repl_user=myslave
secondary_check_script=/usr/local/bin/masterha_secondary_check -s 192.168.190.101 -s 192.168.190.102
shutdown_script=""
ssh_user=root
user=mha
[server1]
hostname=192.168.190.100
port=3306
[server2]
candidate_master=1
#设置为候选master,设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个从库不是集群中最新的slave
check_repl_delay=0
hostname=192.168.190.101
port=3306
[server3]
hostname=192.168.190.102
port=3306
④ 在 master 节点上手动开启虚拟ip
[root@master ~]# ifconfig ens33:1 192.168.190.88/24
⑤ 在 manager 节点上测试 ssh 无密码认证
[root@mha ~]# masterha_check_ssh -conf=/etc/masterha/app1.cnf
Fri Mar 29 20:54:06 2024 - [info] All SSH connection tests passed successfully.
⑥ 在 manager 节点上测试 mysql 主从连接情况
[root@mha ~]# masterha_check_repl -conf=/etc/masterha/app1.cnf
MySQL Replication Health is OK.
⑥ 在 manager 节点上启动 MHA
[root@mha ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &
[1] 6083
⑦ 查看 MHA 状态,可以看到当前的 master 是 master 节点
[root@mha ~]# masterha_check_status --conf=/etc/masterha/app1.cnf
app1 (pid:6083) is running(0:PING_OK), master:192.168.190.100
⑧ 查看 MHA 日志,也以看到当前的 master 是 192.168.190.100
[root@mha ~]# cat /var/log/masterha/app1/manager.log | grep "current master"
Fri Mar 29 21:06:24 2024 - [info] Checking SSH publickey authentication settings on the current master..
192.168.190.100(192.168.190.100:3306) (current master)
⑨ 查看 master 的 VIP 地址 192.168.190.88 是否存在
[root@master ~]# ip a
inet 192.168.190.88/24 brd 192.168.190.255 scope global secondary ens33:1
三、单点故障模拟
1. 关闭服务
① 在 master 节点上停止mysql服务
[root@master ~]# systemctl stop mysqld.service
② 在 manager 节点上查看日志记录
[root@mha ~]# tail -f /var/log/masterha/app1/manager.log
192.168.190.102(192.168.190.102:3306): OK: Applying all logs succeeded. Slave started, replicating from 192.168.190.101(192.168.190.101:3306)
#从服务器(slave)已经开始复制来自 192.168.190.101 主服务器(master)的数据。
③ 验证 vip 地址是否来到 slave1master
[root@slave1master ~]# ip a
inet 192.168.190.200/24 brd 192.168.190.255 scope global secondary ens33:1
④ 查看 app1.cnf 文件内容,是否将宕机的 master 节点删除
[root@mha ~]# vim /etc/masterha/app1.cnf
# [server1] 配置已删除
2. 模拟修复
① 模拟修复原 master mysql
[root@master ~]# systemctl restart mysqld.service
② 在现主库服务器 mysql2 查看二进制文件和同步点
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000002 | 154 | | | |
+-------------------+----------+--------------+------------------+-------------------+
③ 在原主库服务器 mysql1 执行同步操作
mysql> change master to master_host='192.168.190.101',master_user='myslave',master_password='123456',master_log_file='master-bin.000002',master_log_pos=154;
mysql> start slave;
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
④ 在 manager 节点上修改配置文件app1.cnf
[root@mha ~]# vim /etc/masterha/app1.cnf
secondary_check_script=/usr/local/bin/masterha_secondary_check -s 192.168.190.100 -s 192.168.190.102
[server1]
hostname=192.168.190.100
port=3306
⑤ 在 manager 节点上启动 MHA
[root@mha ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &
[1] 6827
[root@mha ~]# ps aux | grep manager
root 6827 1.4 1.1 297308 21760 pts/0 S 21:30 0:00 perl /usr/local/bin/masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover
root 6898 0.0 0.0 112824 988 pts/0 S+ 21:30 0:00 grep --color=auto manager
⑥ 在现主库服务器 mysql2 更新数据,在现从服务器 mysql1、mysql3 查看数据
mysql2:
mysql> use school
mysql> insert into class values (2,'ls');
mysql1、mysql3:
mysql> select * from school.class where id=2;
+------+------+
| id | name |
+------+------+
| 2 | ls |
+------+------+