一、MySQL的MHA相关概念
1.1 MHA是什么
MHA是 MySQL Master High Availability,高可用模式下的故障切换,基于主从复制。
用于解决单点故障和主从复制不能切换的问题。
至少需要3台。故障切换过程0-30秒。
核心是VIP地址,根据vip地址所在的主机,确定主备。
主和备不是优先级确定的,主从复制的时候就确定了主,备是在MHA的过程中确定(配置文件声明)。
1.2 MHA的组件
MHA NODE :数据节点
- 每台MySQL和管理服务器都要安装,监控服务器状态以及收集数据。
MHA 的manager :管理节点
管理MySQL的高可用集群
可以单独部署在一台独立的服务器,也可以部署多个。
manager实现主备切换,主发生故障,切换到备。
1.3 MHA的特点
- 通过manager实现主备切换
- 通过二进制日志binlog,实现数据同步。最大程度上保证数据的完整(不一定是100%)
- 半同步的方式,尽量保证数据的完整
- 一主多从的架构,实现最少要三台
注:5.6以后的版本开始支持GTID,通过GTID全局事务唯一标识,可以取代binlog的数据同步方法,使用GTID实现主从复制和数据同步。不过实验环境使用的MHA版本是0.57,不支持基于GTID的auto_position的主备切换,那么使用GTID和binlog的流程就区别不大。MHA0.58版本以后开始支持基于auto_position的主备切换,可以自动识别复制的起始点,而不用人为地设置,有兴趣的可以自行实验。
二、MHA架构的搭建
2.1 架构
1主2备,主由主从复制确认,备在配置文件中声明
主宕机,保存二进制日志
备从主的二进制日志当中更新,更新到自己的slave日志当中
备成为主,同步到master的二进制文件
其他备服务器从新的主服务器同步数据
原来的备成为主,其他的备服务器从新的主继续同步数据
实验流程:
搭建完成MHA的架构
主备之间的切换
故障恢复
架构:
mysql1 :master 20.0.0.41 mysql 8.0 node组件
mysql2 :slave1 20.0.0.42 mysql 8.0 node组件
mysql3 :slave2 20.0.0.43 mysql 8.0 node组件
test1 :管理节点 :20.0.0.10 node组件 manager组件
2.2 搭建步骤
- 全部节点同步操作
关闭防火墙、守护进程、时间同步
systemctl stop firewalld setenforce 0 #安装时间同步服务 ntpdate yum -y install ntpdate ntpdate ntp.aliyun.com date ##查看时间是否同步
- 更改主机名
# mysql1 改主机名为 master hostnamectl set-hostname master # mysql2 改主机名为 slave1 hostnamectl set-hostname slave1 # mysql3 改主机名为 slave2 hostnamectl set-hostname slave2 ## 后面有需要根据主机名的操作
添加hosts
vim /etc/hosts master 20.0.0.41 slave1 20.0.0.42 slave2 20.0.0.43
- 配置主从节点的二进制日志及恢复功能
主: master节点
vim /etc/my.cnf #[mysqld]模块 server-id = 1 ##server-id 不能一致 log-bin = master-bin binlog_format = MIXED log_slave_updates = true relay_log_recovery = 1 systemctl restart mysqld
从1:slave1
vim /etc/my.cnf #[mysqld]模块 server-id = 2 log-bin = master-bin #主宕机时,备服务器顶替主 binlog_format = MIXED relay-log = relay-log-bin relay-log-index = slave-relay-bin.index relay_log_recovery = 1 systemctl restart mysqld
从2:slave2(纯备胎)
vim /etc/my.cnf #[mysqld]模块 server-id = 3 relay-log = relay-log-bin relay-log-index = slave-relay-bin.index relay_log_recovery = 1 systemctl restart mysqld
- 主从都要做软连接
ln -s /usr/local/mysql/bin/mysql /usr/sbin/ ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/
- 配置MySQL一主两从
(1)所有数据库节点进行 mysql 授权
mysql -u root -p123456 #从数据库同步使用 CREATE USER 'myslave'@'20.0.0.%' IDENTIFIED WITH mysql_native_password BY '123456'; GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'20.0.0.%'; #manager 使用 CREATE USER 'mha'@'20.0.0.%' IDENTIFIED WITH mysql_native_password BY 'manager'; GRANT ALL PRIVILEGES ON *.* TO 'mha'@'20.0.0.%' WITH GRANT OPTION; #防止从库通过主机名连接不上主库 CREATE USER 'mha'@'master' IDENTIFIED WITH mysql_native_password BY 'manager'; GRANT ALL PRIVILEGES ON *.* TO 'mha'@'master'; CREATE USER 'mha'@'slave1' IDENTIFIED WITH mysql_native_password BY 'manager'; GRANT ALL PRIVILEGES ON *.* TO 'mha'@'slave1'; CREATE USER 'mha'@'slave2' IDENTIFIED WITH mysql_native_password BY 'manager'; GRANT ALL PRIVILEGES ON *.* TO 'mha'@'slave2'; flush privileges;
(2)对主库
show master status; +-------------------+----------+ | File | Position | +-------------------+----------+ | master-bin.000001 | 3539 | +-------------------+----------+
(3)对从库:建立同步
change master to master_host='20.0.0.41',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=3539; #启动主从复制,查看服务状态 start slave; show slave status\G; #两个从库必须设置为只读模式: set global read_only=1;
- 安装MHA所有组件
先在所有服务器上必须先安装 node 组件
对于每个操作系统版本不一样,这里 CentOS7.6选择 0.57 版本。
在所有服务器上必须先安装 node 组件,最后在 MHA-manager 节点上安装 manager 组件,
三台mysql和test1 同步安装node组件
#安装依赖环境 yum install -y perl-DBD-MySQL \ perl-Config-Tiny \ perl-Log-Dispatch \ perl-Parallel-ForkManager \ perl-ExtUtils-CBuilder \ perl-ExtUtils-MakeMaker \ perl-CPAN cd /opt #解压,进入node目录 tar -xf mha4mysql-node-0.57.tar.gz cd mha4mysql-node-0.57 #使用perl动态库编译安装 perl Makefile.PL make && make install
在test1: MHA manager 节点上安装 manager 组件
cd /opt tar -xf mha4mysql-manager-0.57.tar.gz cd mha4mysql-manager-0.57 perl Makefile.PL make && make install
manager 组件安装后在/usr/local/bin 下面会生成几个工具,主要包括以下几个:
- masterha_check_ssh :所有的数据库节点和管理节点通过ssh来进行互相通信,检查集群的ssh配置
- masterha_check_repl :检查mysql的复制情况,即数据同步
- masterha_check_status :检查mha集群运行状态的文件
- masterha_master_switch :控制故障转移
- masterha_manager :manager文件的启动脚本
- masterha_stop :关闭manager服务
- 在所有服务器上配置免密登录(密钥对方式)
在 manager 节点上配置到所有数据库节点的无密码认证
ssh-keygen -t rsa ssh-copy-id 20.0.0.41 ssh-copy-id 20.0.0.42 ssh-copy-id 20.0.0.43
在 master 上配置到数据库节点 slave1 和 slave2 的无密码认证
ssh-keygen -t rsa ssh-copy-id 20.0.0.42 ssh-copy-id 20.0.0.43
在 slave1 上配置到数据库节点 master 和 slave2 的无密码认证
ssh-keygen -t rsa ssh-copy-id 20.0.0.41 ssh-copy-id 20.0.0.43
在 slave2 上配置到数据库节点 master 和 slave1 的无密码认证
ssh-keygen -t rsa ssh-copy-id 20.0.0.41 ssh-copy-id 20.0.0.42
- 在 manager 节点上配置 MHA
(1)在 manager 节点上复制相关脚本到/usr/local/bin 目录
cd /opt/mha4mysql-manager-0.57/samples/ cp -rp scripts /usr/local/bin #拷贝后会有四个执行文件
master_ip_failover :故障切换时,vip的管理脚本
master_ip_online_change :在线切换时,vip的管理脚本(手动切换)
power_manager :故障发生后,关闭主机的脚本
send_report :故障发生后,发送报警的脚本
cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin #master_ip_failover管理 VIP 的故障切换
修改文件内容如下
vim /usr/local/bin/master_ip_failover #先进入set paste模式,粘贴以下配置 #!/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 = '20.0.0.200'; my $brdc = '20.0.0.255'; my $ifdev = 'ens33'; my $key = '1'; my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip"; my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down"; my $exit_code = 0; 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"; }
my $vip = '20.0.0.100';
:指定vip地址my $brdc = '20.0.0.255';
:指定vip广播地址my $ifdev = 'ens33';
:指定vip绑定的网络设备my $key = '1';
:指定vip绑定的虚拟网卡序列号my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
:代表此变量值为ifconfig ens33:1 20.0.0.200my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";
:代表此变量值为ifconfig ens33:1 20.0.0.200 downmy $exit_code = 0;
:指定退出状态码为0
管理 MySQL 主从复制设置中的虚拟 IP 故障切换而设计的,可能用于主服务器需要切换到另一台服务器的情景。
它使用 SSH 在远程服务器上执行命令来控制虚拟 IP 地址
(2)创建 MHA 软件目录并拷贝配置文件,这里使用app1.cnf
配置文件来管理 mysql 节点服务器
mkdir /etc/masterha cp /opt/mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/masterha
vim /etc/masterha/app1.cnf #删除原有内容,直接复制并修改节点服务器的IP地址 #shift: set paste [server default] manager_log=/var/log/masterha/app1/manager.log #主日志文件,报错就看它 manager_workdir=/var/log/masterha/app1 #manager的工作目录 master_binlog_dir=/usr/local/mysql/data #mysql的主数据库的binlog文件保存目录 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 #ping主库的时间间隔:1秒ping1次, #默认间隔是3s,ping3次不通就会自动切换 remote_workdir=/tmp repl_password=123456 repl_user=myslave secondary_check_script=/usr/local/bin/masterha_secondary_check -s 20.0.0.42 -s 20.0.0.43 #从对主监听 shutdown_script="" ssh_user=root user=mha [server1] hostname=20.0.0.41 #主服务器 port=3306 [server2] candidate_master=1 #设置为备用的master check_repl_delay=0 #类似于抢占模式,默认是选择一个slave,这个slave和master的数据一致性最佳 #如果slave的同步数据落后主100Mb,MHA永远不会选择该服务器作为备主 #设置为0,则不考虑主从延迟的问题,强制指定为备主 hostname=20.0.0.42 #备用主服务器 port=3306 [server3] hostname=20.0.0.43 #从服务器2 port=3306
- 第一次配置需要在 Master 节点上手动开启虚拟IP
ifconfig ens33:1 20.0.0.200/24
对MHA运行状态进行检测
在 manager 节点上测试 ssh 无密码认证,如果正常最后会输出 successfully
masterha_check_ssh -conf=/etc/masterha/app1.cnf
在 manager 节点上测试 mysql 主从连接情况,最后出现 MySQL Replication Health is OK 字样说明正常。如下所示。
masterha_check_repl --conf=/etc/masterha/app1.cnf #最后出现类似下面这一行 MySQL Replication Health is OK.
- 在 manager 节点上启动 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 &
- nohup :用于在后台运行命令,并且忽略挂断(SIGHUP)信号。这意味着即使当前终端会话结束,命令也会继续在后台运行。在这里,
nohup
用于确保masterha_manager
进程不会因为终端关闭而停止。 - masterha_manager --conf=/etc/masterha/app1.cnf: 指定masterha_manager配置文件的路径,配置文件包含有关于 MySQL 主从复制集群的配置信息,例如数据库连接信息、监控参数、故障转移策略等。
- –remove_dead_master_conf: 这个选项告诉
masterha_manager
在启动时删除先前故障的主服务器的配置。这样做是为了确保在切换后不会再将宕机的主服务器误认为是正常的主服务器。 - –ignore_last_failover: 这个选项告诉
masterha_manager
在启动时忽略上一次故障转移的状态。这可以避免在重启时重复执行先前的故障转移操作。 - < /dev/null: 将标准输入重定向到
/dev/null
,这意味着命令不会从标准输入接收任何输入。这对于后台运行的进程是一种常见做法,因为它们通常不需要从标准输入读取任何数据。 - > /var/log/masterha/app1/manager.log 2>&1: 将标准输出和标准错误输出重定向到文件
/var/log/masterha/app1/manager.log
。这样做可以记录masterha_manager
进程的输出和错误信息,以便后续排查问题或者进行监控和日志记录。 - &: 在命令末尾的
&
符号将命令放入后台运行,允许终端继续接受新的命令输入,而不会等待masterha_manager
进程结束。
查看 MHA 状态,可以看到当前的 master 是 master 节点。
masterha_check_status --conf=/etc/masterha/app1.cnf
查看 MHA 日志,也以看到当前的 master 是 20.0.0.41
cat /var/log/masterha/app1/manager.log | grep "current master"
查看master 的 VIP 地址 20.0.0.200 是否存在,这个 VIP 地址不会因为 manager 节点停止 MHA 服务而消失。
#在master节点查看VIP ip addr
若要关闭 manager 服务,可以使用如下命令。
masterha_stop --conf=/etc/masterha/app1.cnf
2.3 故障恢复
停止mysql1的服务,模拟主服务器故障
重新查看 MHA 状态,可以看到当前的 master 是 slave1节点。
masterha_check_status --conf=/etc/masterha/app1.cnf
去mysql2上查看ip
ip addr
发现VIP已经转移到mysql2上
查看/etc/masterha/app1.cnf
vim /etc/masterha/app1.cnf
发现配置文件中server1(原主服务器的模块)被删除了
如果要把mysql1重新加入进来,作为候选主服务器,就套用server2模块(mysql2)的设置,再把mysql2的设置改成之前mysql1的设置,使mysql2作为新的主服务器。
[server1] candidate_master=1 check_repl_delay=0 hostname=20.0.0.41 port=3306 [server2] hostname=20.0.0.42 port=3306
再修改数据库mysql的配置
mysql1 节点:原master成为新的slave
vim /etc/my.cnf #[mysqld]模块 server-id = 1 log-bin = master-bin binlog_format = MIXED log-slave-updates = true relay-log = relay-log-bin relay-log-index = slave-relay-bin.index relay_log_recovery = 1 systemctl restart mysqld
mysql2节点:原slave1成为新的master
vim /etc/my.cnf #[mysqld]模块 server-id = 2 log-bin = master-bin #主宕机时,备服务器顶替主 binlog_format = MIXED relay-log = relay-log-bin relay-log-index = slave-relay-bin.index relay_log_recovery = 1 systemctl restart mysqld
slave2(纯备胎)
mysql2变为新的主