目录
一、MHA介绍
MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案,是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。
在 MySQL 故障切换过程中,MHA 能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA 能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
该软件由两部分组成:MHA Manager(管理节点)和 MHA Node(数据节点)。MHA Manager 可以单独部署在一台独立的机器上管理多个 master-slave 集群,也可以部署在一台 slave 节点上。MHA Node 运行在每台 MySQL 服务器上,MHA Manager 会定时探测集群中的 master 节点,当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master,然后将所有其他的 slave 重新指向新的 master。整个故障转移过程对应用程序完全透明。
在 MHA 自动故障切换过程中,MHA 试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过ssh访问,MHA 没法保存二进制日志,只进行故障转移而丢失了最新的数据。使用 MySQL 5.5 的半同步复制,可以大大降低数据丢失的风险。MHA 可以与半同步复制结合起来。如果只有一个 slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此可以保证所有节点的数据一致性。
目前 MHA 主要支持一主多从的架构,要搭建 MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当 master,一台充当备用 master,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,淘宝TMHA已经支持一主一从。
MHA原理:
MHA用于维持 MySQL Replication 中 master 库的高可用性,最大的特点是可以修复多个slave上的差异日志,最终使所有slave保持数据一致,然后从中选取一个充当新的 master,并让其他 slave 指向它。
当master出现故障时,通过对比 slave 之间的 I/O thread 读取主库的 binlog 的 position 号,选取最接近的slave作为备胎(被选主库),其它从库通过与备胎对比,生成差异的中继日志,在备胎上运用从原来的 master 保存的 binlog,同时将备胎提升为master。最后在其他 slave 上运用相应的差异中继日志,并从新的 master 开始复制。
MHA优点:
① 故障切换时,自动判断哪个从库与主库离的最近,并切换到该从库
② 支持binlog server,提高 binlog 的传送效率
③ 结合半同步功能,确保故障切换时数据不丢失
二、MHA搭建
1.环境准备
IP | Hostname | OS Version | Role |
192.168.16.18 | centos8-min8 | CentOS Linux release 8.2.2004 | master |
192.168.16.19 | centos8-min9 | CentOS Linux release 8.2.2004 | slave1 |
192.168.16.20 | centos8-min10 | CentOS Linux release 8.2.2004 | slave2+ manager |
由于安装MHA-Node过程中发现centos8并不能安装MHA-Node,所以将操作系统重装换成centos7
IP | Hostname | OS Version | Role |
192.168.16.21 | centos7-min-ha1 | CentOS Linux release 7.8.2003 | master |
192.168.16.22 | centos7-min-ha2 | CentOS Linux release 7.8.2003 | slave1 |
192.168.16.23 | centos7-min-ha3 | CentOS Linux release 7.8.2003 | slave2+ manager |
2.MHA下载与MySQL安装
> MHA下载地址
wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58.tar.gz
- MySQL官网下载MYSQL:https://downloads.mysql.com/archives/community/
目前MYSQL官网并未提供redhat8版本的MYSQL产品
centos8-min8:
centos8-min9:
centos8-min10:
- MySQL安装
使用mysql自动化安装脚本在三台服务器上安装mysql,自动化安装脚本可参考如下:
###采用二进制安装包安装MySQL###
###############################
#!/bin/bash
## The 3 messages you need to update according to your package
dir_package='/opt'
install_package=${dir_package}'/mysql-5.7.24-el7-x86_64.tar.gz'
package_version='mysql-5.7.24'
## The default linux system version is Redhat/CentOS7
clear
echo "=========================================================================="
echo "A tool to auto-compile & install $package_version on Redhat/CentOS7 Linux "
echo "=========================================================================="
## 1. check the integrity of your mysql package
echo ">>Step1: md5sum 验证包的完整性"
echo `md5sum $install_package` | awk '{print $1}'
echo "If the md5sum is the same with the one obtained from https://downloads.mysql.com/archives/community/ ?"
read -p "(Please input yes or no):" checkmysql
case "$checkmysql" in
yes|y|Y|YES|yeS|yES|Yes|YeS|yEs|YEs)
checkmysql='y'
echo "安装包完整,可以开始安装"
;;
*)
echo "安装包不完整,请重新获取安装包"
checkmysql='n'
exit
esac
## 2. preparations for mysql installation
echo ">>Step2: mysql安装准备中..."
package_tar_name=${install_package##*/}
package_name=${package_tar_name%%.tar*}
## decompress the install package
tar zxvf $package_tar_name -C ${dir_package}/
cd ${dir_package}/
mv ${package_name} mysql
## create user mysql
useradd mysql
## create some directories needed by this installation
cd ${dir_package}/mysql/
touch my.cnf
mkdir -p data
mkdir -p log
mkdir -p mylog
mkdir -p pid
mkdir -p socket
mkdir -p tmp
chown -R mysql:mysql ${dir_package}/mysql
## assign the port for mysql installation
read -p "Tell me a viable port you'd like to install mysql (the default port is 3306):" port
if [ ! $port ];then
mport=3306
elif [ !`$port -eq 3306` ];then
mport=$port
fi
echo "The port="$mport
## define the my.cnf
cat >>${dir_package}/mysql/my.cnf<<EOF
[client]
port = $mport
socket = ${dir_package}/mysql/socket/mysqld-T-prod-$mport.sock
default-character-set=utf8
[mysqld]
user = mysql
port = $mport
socket = ${dir_package}/mysql/socket/mysqld-T-prod-$mport.sock
datadir = ${dir_package}/mysql/data
basedir = ${dir_package}/mysql
server-id = 1
log-bin = ${dir_package}/mysql/mylog/mysql-bin-T-prod-$mport
sync-binlog=1
tmpdir = ${dir_package}/mysql/tmp
[mysqld_safe]
pid-file = ${dir_package}/mysql/pid/mysql-T-prod-$mport.pid
log-error = ${dir_package}/mysql/log/mysql-T-prod-$mport.err
EOF
## Update ${dir_package}/mysql/support-files/mysql.server for mysql start | stop
cd ${dir_package}/mysql/support-files
sed -i "/^datadir=/{s/$/\\${dir_package}\\/mysql\\/data/}" mysql.server ##datadir=${dir_package}/mysql/data
sed -i "/^basedir=/{s/$/\\${dir_package}\\/mysql/}" mysql.server ##basedir=${dir_package}/mysql
sed -i "/^mysqld_pid_file_path=/{s/$/\\${dir_package}\\/mysql\\/pid\\/mysql-T-prod-$mport.pid/}" mysql.server
#default_conf="conf=/etc/my.cnf"
#conf="conf=/opt/mysql57/my.cnf"
#sed -i "s/${default_conf}/${conf}/g" mysql.server
sed -i "s/\\/etc\\/my.cnf/\\${dir_package}\\/mysql\\/my.cnf/g" mysql.server ##conf=${dir_package}/mysql/my.cnf
## 3. initial and start mysql installation
###function installMysql(){
echo ">>Step3: 开始安装$package_version"
echo "We are about to install $package_version, please wait..."
echo ">>Step3-1: 数据库初始化"
${dir_package}/mysql/bin/mysqld --defaults-file=${dir_package}/mysql/my.cnf --initialize --user=mysql --basedir=${dir_package}/mysql --datadir=${dir_package}/mysql/data
echo "=======Very important!! Please remember the password of root if the initial is successful=========="
echo ">>Step3-2: 启动数据库"
## 使用mysql用户启动mysql服务(如果mysql没有启动,请手动启动哈)
su - mysql -s /bin/bash -c "${dir_package}/mysql/support-files/mysql.server start"
## 检查mysql启动的进程
if [ `ps -ef | grep mysql | grep -v grep | wc -l` -eq 0 ]
then
echo "Mysql started failed"
else
echo "Mysql started successfully"
fi
###}
##installMysql 2&>1 | tee ${dir_package}/mysql/installMysql.log
## 4. what you need to do after mysql installation
## ① 设置mysql环境变量
#echo `export MYSQL_HOME=${dir_package}/mysql` >> /home/mysql/.bashrc
#echo `export PATH=$PATH:$MYSQL_HOME/bin`>> /home/mysql/.bashrc
#source /home/mysql/.bashrc
## ② 使用临时root密码登录mysql并修改root密码
#su - mysql
#mysql -uroot -p
#mysql> alter user user() identified by '123456';
定制my.cnf
[root@centos8-min8 mysql]# cat my.cnf
[client]
port = 3306
socket = /root/mysql/socket/mysqld-T-prod-3306.sock
default-character-set=utf8
[mysqld]
user = mysql
port = 3306
socket = /root/mysql/socket/mysqld-T-prod-3306.sock
datadir = /root/mysql/data
basedir = /root/mysql
tmpdir = /root/mysql/tmp
##server-id = 1618
##log-bin = /root/mysql/mylog/mysql-bin-T-prod-3306
##sync-binlog=1
##relay_log = /root/mysql/mylog/relay-log-T-prod-3306
###log_slave_updates=1
#GTID
gtid_mode=on
enforce_gtid_consistency=on
server-id=1618 #每一台服务器的server-id应该不同
#binlog
log-bin=/root/mysql/mylog/mysql-bin-T-prod-3306
sync-binlog=1
log_slave_updates=1
binlog_format=row
#relay log
skip_slave_start=1
[mysqld_safe]
pid-file = /root/mysql/pid/mysql-T-prod-3306.pid
log-error = /root/mysql/log/mysql-T-prod-3306.err
[root@centos8-min8 ~]# mysql -uroot -p
mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory
[root@centos8-min8 ~]# yum -y install libncurses*
[root@centos8-min10 ~]# mysql -uroot -p
Enter password:
mysql> alter user user() identified by '123456';
3.配置三台服务器基本信息
① 将Hostname与IP进行关联
[root@centos7-min-ha1 ~]# cat /etc/hosts
192.168.16.21 centos7-min-ha1
192.168.16.22 centos7-min-ha2
192.168.16.23 centos7-min-ha3
[root@centos7-min-ha1 ~]# scp /etc/hosts root@192.168.16.22:/etc/hosts
[root@centos7-min-ha1 ~]# scp /etc/hosts root@192.168.16.23:/etc/hosts
② 配置SSH免密登录
[root@centos8-min8 ~]# ssh -V
OpenSSH_8.0p1, OpenSSL 1.1.1c FIPS 28 May 2019 —— CentOS8.2 ssh默认版本
[root@centos7-min-ha1 ~]# ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017 —— CentOS7.8 ssh默认版本
/root/.ssh
[root@centos8-min8 ~]# ssh-keygen ——生成公私钥对
[root@centos8-min8 .ssh]# ll
total 12
-rw-------. 1 root root 2602 Feb 2 17:35 id_rsa
-rw-r--r--. 1 root root 571 Feb 2 17:35 id_rsa.pub
-rw-r--r--. 1 root root 350 Feb 2 13:52 known_hosts
[root@centos8-min8 .ssh]# ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.16.19 ——把公钥拷贝到其它机器
[root@centos8-min8 .ssh]# ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.16.20
拷贝完毕之后可在对应机器上查看到公钥信息
[root@centos8-min9 .ssh]# cat /root/.ssh/authorized_keys
[root@centos8-min8 .ssh]# ssh 192.168.16.19 ——min8可免密登录到保存了其公钥的机器
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Tue Feb 2 13:04:52 2021 from 192.168.16.1
[root@centos8-min9 ~]#
同理配置min9和min10两台机器的ssh免密登录即可
4.选择主从模式
> 经典主从复制模式
使用binlog+pos开启复制,在从库指定主库的binlog_file和 log_pos
MYSQL主备复制可参考 :http://t.csdn.cn/QOKci
> GTID模式
开启GTID,无需找到binlog和pos点,直接change master to master_auto_postion=1即可,它会自动寻找同步
① GTID的概述:
1、全局事物标识:global transaction identifieds。
2、GTID事物是全局唯一性的,且一个事务对应一个GTID。
3、一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。
4、GTID用来代替classic的复制方法,不在使用binlog+pos开启复制。而是使用master_auto_postion=1的方式自动匹配GTID断点进行复制。
5、MySQL-5.6.5开始支持的,MySQL-5.6.10后开始完善。
6、在传统的slave端,binlog是不用开启的,但是在GTID中,slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。
② GTID的组成部分:
前面是server_uuid:后面是一个序列号
例如:server_uuid:sequence number
7800a22c-95ae-11e4-983d-080027de205a:10
UUID:每个mysql实例的唯一ID,由于会传递到slave,所以也可以理解为源ID。
Sequence number:在每台MySQL服务器上都是从1开始自增长的序列,一个数值对应一个事务。
③ GTID比传统复制的优势:
1、更简单的实现failover,不用以前那样在需要找log_file和log_Pos。
2、更简单的搭建主从复制。
3、比传统复制更加安全。
4、GTID是连续没有空洞的,因此主从库出现数据冲突时,可以用添加空事物的方式进行跳过。
④ GTID的工作原理:
1、master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。
2、slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
3、sql线程从relay log中获取GTID,然后对比slave端的binlog是否有记录。
4、如果有记录,说明该GTID的事务已经执行,slave会忽略。
5、如果没有记录,slave就会从relay log中执行该GTID的事务,并记录到binlog。
6、在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。
⑤ 使用GTID搭建mysql的主从复制的主要参数:
[mysqld]
#GTID:
gtid_mode=on
enforce_gtid_consistency=on
server_id=2003306 #每个实例的server_id都要不一样
#binlog
log-bin=mysqlbin
log-slave-updates=1 #允许下端接入slave
binlog_format=row #强烈建议,其他格式可能造成数据不一致
#relay log
skip_slave_start=1
注意:建议使用mysql-5.6.5以上的最新版本。
⑥ 启动GTID的两种方法:
方法一、
1、如果是在已经跑的服务器,你需要重启一下mysql server。
2、启动之前,一定要先关闭master的写入,保证所有slave端都已经和master端数据保持同步。
3、所有slave需要加上skip_slave_start=1的配置参数,避免启动后还是使用老的复制协议。
方法二、
1、如果是新搭建的服务器,直接启动就行了。
⑦ master-slave搭建的注意事项
(一)、使用GTID的方式,把salve端挂载master端:
1、启动以后最好不要立即执行事务,而是先change master上。
2、然后在执行事务,当然知不是必须的。
3、使用下面的sql切换slave到新的master。
stop slave;
change master to
master_host = 192.168.100.200,
master_port = 3306,
master_user = abobo,
master_password=123,
master_auto_position = 1;
(二)、如果给已经运行的GTID的master端添加一个新的slave
有两种方法:
方法一、适用于master也是新建不久的情况。
1、如果你的master所有的binlog还在。可以选择类似于上面的方法,安装slave,直接change master to到master端。
2、原理是直接获取master所有的GTID并执行。
3、优点:简单方便。
4、缺点:如果binlog太多,数据完全同步需要时间较长,并且master一开始就启用了GTUD。
方法二、适用于拥有较大数据的情况。(推荐)
1、通过master或者其他slave的备份搭建新的slave。(看第三部分)
2、原理:获取master的数据和这些数据对应的GTID范围,然后通过slave设置@@global.gtid_purged跳过备份包含的gtid。
3、优点:是可以避免第一种方法的不足。
4、缺点:相对来说有点复杂。
5.搭建主从环境
① 环境说明
本次实验搭建一主两从环境,使用的版本是5.7.28,基于GTID+row+增强半同步模式
GTID —— Global Transaction Identifier
复制格式 —— 推荐使用row格式,statement和mixed格式坑太多。
增强半同步 —— rpl_semi_sync_master_wait_point = AFTER_SYNC
#5.7中默认已经是after_sync
② 在三台MySQL服务器上创建主从复制账号和管理账号
#创建主从复制账号
[mysql@centos8-min8 support-files]$ mysql -uroot -p
Enter password: 123456
mysql> create user 'gtid'@'192.168.16.%' identified by 'gtid123';
mysql> grant replication slave on *.* to 'gtid'@'192.168.16.%';
mysql> flush privileges;
#创建管理账号
mysql> create user 'manage'@'192.168.16.%' identified by 'manage123';
mysql> grant all privileges on *.* to 'manage'@'192.168.16.%';
mysql> flush privileges;
mysql> select Host,User from mysql.user;
③ 在主库上复制数据到所有从库,完成在某个时刻GTID的同步
[mysql@centos8-min8 mysql]$ mysqldump --single-transaction -uroot -p -A > all.sql
Enter password: 123456
[mysql@centos7-min-ha1 mysql]$ mysqldump --all-databases --triggers --routines --events -uroot -p -A > all.sql
Enter password:
[mysql@centos7-min-ha1 mysql]$
[mysql@centos7-min-ha1 mysql]$ ll
total 1132
-rw-rw-r--. 1 mysql mysql 848521 Feb 23 14:12 all.sql
[root@centos8-min8 mysql]# scp all.sql 192.168.16.19:/root/mysql/
[root@centos8-min8 mysql]# scp all.sql 192.168.16.20:/root/mysql/
④ 从各从库恢复备份并配置主从复制,开启主从同步
[mysql@centos8-min9 mysql]$ mysql -uroot -p < all.sql
[mysql@centos8-min10 mysql]$ mysql -uroot -p < all.sql
> 问题追踪
主要原因是之前的数据库里面配置了主从,再导出的时候一起导出来了,所以导入时会出现这个问题。
解决办法:在导入的服务器重置一下主数据库服务器,再重新导入sql文件即可
配置文件my.cnf修改(主从服务器配置除server-id之外其余信息一致):
注意:每台MySQL服务器的server-id必须是不一样的!
[mysql@centos7-min-ha1 root]$ vi mysql/my.cnf
[client]
port = 3306
socket = /root/mysql/socket/mysqld-T-prod-3306.sock
default-character-set=utf8
[mysqld]
user = mysql
port = 3306
socket = /root/mysql/socket/mysqld-T-prod-3306.sock
datadir = /root/mysql/data
basedir = /root/mysql
tmpdir = /root/mysql/tmp
##server-id = 1620
##log-bin = /root/mysql/mylog/mysql-bin-T-prod-3306
##sync-binlog=1
##relay_log = /root/mysql/mylog/relay-log-T-prod-3306
###log_slave_updates=1
#GTID
gtid_mode=on
enforce_gtid_consistency=on
server-id=1621
#binlog
log-bin=/root/mysql/mylog/mysql-bin-T-prod-3306
sync-binlog=1
log_slave_updates=1
binlog_format=row
#relay log
skip_slave_start=1
[mysqld_safe]
pid-file = /root/mysql/pid/mysql-T-prod-3306.pid
log-error = /root/mysql/log/mysql-T-prod-3306.err
[root@centos7-min-ha2 ~]# vi mysql/my.cnf
#GTID
gtid_mode=on
enforce_gtid_consistency=on
server-id=1622
[mysql@centos7-min-ha3 mha]$ vi /root/mysql/my.cnf
#GTID
gtid_mode=on
enforce_gtid_consistency=on
server-id=1623
重启主从mysql服务并查看gtid模式启用状态
[mysql@centos8-min8 mysql]$ support-files/mysql.server restart
主库master状态:
从库192.168.16.22同步主库master:
mysql> change master to
-> master_host='192.168.16.21',
-> master_port=3306,
-> master_user='gtid',
-> master_password='gtid123',
-> master_auto_position=1;
从库192.168.16.20同步主库master:
- 问题追踪
1. gtid_mode未开启
这个参数gtid_mode是一个单项的修改过程,也就是说从off到on,需要经过中间的OFF <-> OFF_PERMISSIVE <-> ON_PERMISSIVE <-> ON
过程,而相邻的两个状态之间可以相互转换。否则会出错。
[mysqld]
gtid_mode=on
enforce_gtid_consistency=on
2. slave IO进程通信连接不上
开放mysql端口或者关闭防火墙即可
[root@centos8-min9 ~]# systemctl stop firewalld
[root@centos8-min9 ~]# systemctl disable firewalld
[root@centos8-min9 ~]# systemctl status firewalld
服务器挂掉之后MySQL主从同步失败,需要重启slave
6.安装MHA-Node节点
在所有节点上安装数据节点
安装MySQL依赖的perl环境
①安装epel源
yum install -y epel-release
②安装perl
yum install perl-DBD-MySQL
yum install perl-Config-Tiny
yum install perl-Log-Dispatch
yum install perl-Parallel-ForkManager
yum install perl-Params-Validate
③安装mha-node
tar -zxf mha4mysql-node-0.58.tar.gz
cd mha4mysql-node-0.58/
yum install perl-CPAN* -y
perl Makefile.PL
make && make install
- 问题追踪
执行yum命令失败,服务器不能访问外网
Cannot find a valid baseurl for repo: base/7/x86_64
添加DNS到网卡配置并重启网络
[root@centos8-min8 ~]# yum install perl-DBD-MySQL -y
解压mha4mysql-node-0.58.tar.gz 并安装 per-cpan
[root@centos8-min8 ~]# tar -zxf mha4mysql-node-0.58.tar.gz
[root@centos8-min8 ~]# cd mha4mysql-node-0.58/
[root@centos8-min8 mha4mysql-node-0.58]# yum install perl-CPAN* -y
perl Makefile.PL
make && make install
Can't locate inc/Module/Install.pm in @INC (you may need to install the inc::Module::Install module)
查看是否安装cpan软件包,已安装后可通过cpan进行perl模块的安装
#yum install perl-CPAN*
[root@centos8-min8 mha4mysql-node-0.58]# cpan inc::Module::Install
> 问题追踪
在centos8.2中执行perl Makefile.PL失败,但在centos7.8中执行成功
7.安装MHA-Manager管理节点
仅在centos7-min-ha3 192.168.16.23上安装mha-manager管理节点
安装环境需要的介质包 —— (在安装MHA-Node的时候已安装了)
①安装mha-manager
[root@centos7-min-ha3 ~]# tar -zxf mha4mysql-manager-0.58.tar.gz
[root@centos7-min-ha3 ~]# chown -R root.root mha4mysql-manager-0.58
[root@centos7-min-ha3 ~]# cd mha4mysql-manager-0.58
[root@centos7-min-ha3 mha4mysql-manager-0.58]# perl Makefile.PL
[root@centos7-min-ha3 mha4mysql-manager-0.58]# make && make install
②配置MHA
mkdir /etc/mha
mkdir -p /usr/local/mha
cd /etc/mha/
[root@centos7-min-ha3 scripts]# cat /etc/mha/mha.conf
[root@centos7-min-ha3 scripts]#
cat /usr/local/mha/scripts/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.16.100/24'; # Virtual IP 这里需要根据自己的环境修改
my $key = "1";
##my $ssh_start_vip = "/sbin/ifcfg ens33:$key $vip"; #注意网卡
##my $ssh_stop_vip = "/sbin/ifcfg ens33:$key down";
my $ssh_start_vip = "sudo ip addr add $vip dev ens33:$key";
my $ssh_stop_vip = "sudo ip addr delete $vip dev ens33:$key";
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" ) {
# $orig_master_host, $orig_master_ip, $orig_master_port are passed.
# If you manage master ip address at global catalog database,
# invalidate orig_master_ip here.
my $exit_code = 1;
eval {
print "\n\n\n***************************************************************\n";
print "Disabling the VIP - $vip on old master: $orig_master_host\n";
print "***************************************************************\n\n\n\n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
# all arguments are passed.
# If you manage master ip address at global catalog database,
# activate new_master_ip here.
# You can also grant write access (create user, set read_only=0, etc) here.
my $exit_code = 10;
eval {
print "\n\n\n***************************************************************\n";
print "Enabling the VIP - $vip on new master: $new_master_host \n";
print "***************************************************************\n\n\n\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";
`ssh $ssh_user\@$orig_master_host \" $ssh_start_vip \"`;
exit 0;
}
else {
&usage();
exit 1;
}
}
# A simple system call that enable the VIP on the new master
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 {
"Usage: master_ip_failover –command=start|stop|stopssh|status –orig_master_host=host –orig_master_ip=ip –orig_master_port=po
rt –new_master_host=host –new_master_ip=ip –new_master_port=port\n";
}
[root@centos7-min-ha3 scripts]#
cat /usr/local/mha/scripts/master_ip_online_change
#注意VIP
#/bin/bash
source /root/.bash_profile
vip=`echo '192.168.16.100/24'` # Virtual IP
key=`echo '1'`
command=`echo "$1" | awk -F = '{print $2}'`
orig_master_host=`echo "$2" | awk -F = '{print $2}'`
new_master_host=`echo "$7" | awk -F = '{print $2}'`
orig_master_ssh_user=`echo "${12}" | awk -F = '{print $2}'`
new_master_ssh_user=`echo "${13}" | awk -F = '{print $2}'`
##stop_vip=`echo "ssh root@$orig_master_host /sbin/ifcfg ens33:$key down"`
##start_vip=`echo "ssh root@$new_master_host /sbin/ifcfg ens33:$key $vip"`
stop_vip=`echo "ssh root@$orig_master_host sudo ip addr delete 192.168.16.100/24 dev ens33:1"`
start_vip=`echo "ssh root@$new_master_host sudo ip addr add 192.168.16.100/24 dev ens33:1"`
if [ $command = 'stop' ]
then
echo -e "\n\n\n***************************************************************\n"
echo -e "Disabling the VIP - $vip on old master: $orig_master_host\n"
$stop_vip
if [ $? -eq 0 ]
then
echo "Disabled the VIP successfully"
else
echo "Disabled the VIP failed"
fi
echo -e "***************************************************************\n\n\n\n"
fi
if [ $command = 'start' -o $command = 'status' ]
then
echo -e "\n\n\n***************************************************************\n"
echo -e "Enabling the VIP - $vip on new master: $new_master_host \n"
$start_vip
if [ $? -eq 0 ]
then
echo "Enabled the VIP successfully"
else
echo "Enabled the VIP failed"
fi
echo -e "***************************************************************\n\n\n\n"
fi
检测所有主机的连通性:
[root@centos7-min-ha3 scripts]#
/usr/local/bin/masterha_check_ssh --conf=/etc/mha/mha.conf
解决方法:
SSH互信问题,之前是使用ssh-copy-id命令,所以在authorized_keys中只保存了除本机外的另外两台机器的公钥,需要将三台机器上的本机ssh公钥加入authorized_keys文件
重试成功
检测复制状态:
[root@centos7-min-ha3 mha]#
/usr/local/bin/masterha_check_repl --conf=/etc/mha/mha.conf
问题解决:启动三台服务器上的mysql服务
[root@centos7-min-ha3 mha]# /root/mysql/support-files/mysql.server start
问题解决:需要重启两台mysql从服务的主从同步复制功能
[root@centos7-min-ha3 mha]# su mysql
[mysql@centos7-min-ha3 mha]$ mysql -uroot -p
Enter password: 123456
mysql> start slave;
8.在主库上添加VIP
[root@centos7-min-ha1 ~]# ip addr add 192.168.16.100/24 dev ens33
删除VIP
[root@centos7-min-ha1 ~]# ip addr del 192.168.16.100/24 dev ens33
9.在管理节点启动MHA服务
启动MHA:
nohup masterha_manager --conf=/etc/mha/mha.conf > /tmp/mha_manager.log < /dev/null 2>&1 &
检测MHA是否启动:
masterha_check_status --conf=/etc/mha/mha.conf
注意:
三、模拟主库故障,故障切换
1.MHA自动切换主库
MHA自动切换卡在通过ssh漂移VIP阶段
主要原因是因为master_ip_failover与master_ip_online_change两个文件配置有问题
[root@centos7-min-ha3 scripts]# find / -name mha.failover.complete
/usr/local/mha/mha.failover.complete
[root@centos7-min-ha3 scripts]# cd /usr/local/mha/
[root@centos7-min-ha3 mha]# rm -rf mha.failover.complete
mha.failover.complete 文件:该文件生成后,将不在允许主库故障后自动切换
删除manager机器上的mha.failover.complete文件后,master机器上就能查看到VIP信息
mha-manager正常运行,MySQL主从复制正常,模拟主库故障查看VIP从主库21漂移到从库22
将master MySQL服务停止
[root@centos7-min-ha1 ~]# mysql/support-files/mysql.server stop
Shutting down MySQL........... SUCCESS!
centos7-min-ha1
centos7-min-ha2
VIP漂移之后,centos7-min-ha2从库变成主库,查看centos7-min-ha2 的主从状态
查看centos7-min-ha3 从库的主从状态
> 问题追踪 : 把从库的 Master_Host改成VIP试试,测试结果为不能解决该问题。这个问题产生的原因是min-ha3与min-ha2的server-id配置成了一样的。
注意:每台MySQL服务器的server-id必须是不一样的
2.手动切换主库
前提:一主二从状态正常,主库VIP正常,MHA manager启动正常
停止主库服务,VIP切换到从库min-ha2
[root@centos7-min-ha1 ~]# mysql/support-files/mysql.server stop
Shutting down MySQL........... SUCCESS!
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
Query OK, 0 rows affected, 1 warning (0.01 sec)
客户端通过VIP访问MySQL服务
数据库主从状态检查
min-ha2 (mater): 自动没有slave
min-ha3: 自动同步切换master到192.168.16.22
min-ha1: 没有slave状态,没有同步新master
后续恢复
① 把min-ha1从库与min-ha2主库进行复制
min-ha1:
② 重启min-ha1 MySQL服务后检查Mha manager服务器并删除mha.failover.complete 文件
该文件生成后,将不在允许主库故障后自动切换
再重启mha-manager服务
[root@centos7-min-ha3 mha]#
[root@centos7-min-ha3 mha]# nohup masterha_manager --conf=/etc/mha/mha.conf > /tmp/mha_manager.log < /dev/null 2>&1 &
[root@centos7-min-ha3 mha]# masterha_check_status --conf=/etc/mha/mha.confmha (pid:2641) is running(0:PING_OK), master:192.168.16.22
mha.failover.complete存在,min-ha2 (master)故障切换不成功,VIP仍然在min-ha2
再重启min-ha2 MySQL服务,查看主从状态都正常
[root@centos7-min-ha2 ~]# mysql/support-files/mysql.server start
Starting MySQL. SUCCESS!
再测试将/usr/local/mha/mha.failover.complete删除,重启mha服务,再停止MySQL master
[root@centos7-min-ha3 mha]# rm -rf mha.failover.complete
[root@centos7-min-ha3 mha]# nohup masterha_manager --conf=/etc/mha/mha.conf > /tmp/mha_manager.log < /dev/null 2>&1 &
[1] 3127
[root@centos7-min-ha3 mha]# masterha_check_status --conf=/etc/mha/mha.confmha (pid:3127) is running(0:PING_OK), master:192.168.16.22
[root@centos7-min-ha2 ~]# mysql/support-files/mysql.server status
SUCCESS! MySQL running (2720)
[root@centos7-min-ha2 ~]# mysql/support-files/mysql.server stop
Shutting down MySQL............ SUCCESS!
VIP成功再次切换回min-ha1
MySQL高可用通过,测试完毕。
Min-ha1:
Min-ha2:
Min-ha3:
再将min-ha2以MySQL从机的形式同步min-ha1 MySQL主机