1.MHA简介
MHA(Master High Availability)是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,
MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
MHA由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。
MHA Manager可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave节点/master结点上。
MHA Node运行在每台MySQL服务器上,MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,
然后将所有其他的slave重新指向新的master。整个故障转移过程对应用程序完全透明。
在MHA自动故障切换过程中,MHA试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。
例如,如果主服务器硬件故障或无法通过ssh访问,MHA没法保存二进制日志,只进行故障转移而丢失了最新的数据。
使用MySQL 5.5的半同步复制,可以大大降低数据丢失的风险。MHA可以与半同步复制结合起来。
如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性。
2.Manager工具包主要包括以下几个工具
masterha_check_ssh #检查MHA的SSH配置状况
masterha_check_repl #检查MySQL复制状况
masterha_manger #启动MHA
masterha_check_status #检测当前MHA运行状态
masterha_master_monitor #检测master是否宕机
masterha_master_switch #控制故障转移(自动或者手动)
masterha_conf_host 添加或删除配置的server信息
3.Node工具包主要包括以下几个工具
save_binary_logs #保存和复制master的二进制日志
apply_diff_relay_logs #识别差异的中继日志事件并将其差异的事件应用于其他的slave
filter_mysqlbinlog #去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
purge_relay_logs #清除中继日志(不会阻塞SQL线程)
这些工具通常由MHA Manager的脚本触发,无需人为操作
实验环境:
server1:172.25.66.1 master/manager
server2:172.25.66.2 slave
server3:172.25.66.3 slave
实验前提:
注意:主从复制的前提是,数据高度一致性,如果你之前已经做好了一主一从,再继续添从库时,会出现SQL线程连接失败,因为此时主库与新添加的从库数据不一致 ,为了避免此类问题,建议重新打开3个虚拟机做一主二从,保证实验环境的纯净
先做好一主二从的基于GTID的主从复制与半同步复制(基于GTID主从复制在复制过程中更加方便,而半同步复制有效的避免了数据的丢失)
1.配置一主二从
为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL 5.5的半同步复制
安装包:
mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
点击此处即可查看主从复制与半同步复制详细配置及实验原理
(1).基于GTID的主从复制
配置master端:
#1.解压并安装数据库
[root@server1 ~]# ls
mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
[root@server1 ~]# tar -xf mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
[root@server1 ~]# ls
[root@sever1 ~]# yum install -y mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm
[root@sever1 ~]# scp mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm root@172.25.66.2:
[root@sever1 ~]# scp mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm root@172.25.66.3:
2.更改文件
[root@server1 mysql]# vim /etc/my.cnf
#####################
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
#3.开启数据库
[root@server1 mysql]# systemctl start mysqld
#4.查看初始密码
[root@server1 mysql]# cat /var/log/mysqld.log | grep password
#5.初始化
[root@sever1 ~]# mysql_secure_installation
#6.登陆数据库并用户授权
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
#用户授权
mysql> grant replication slave on *.* to repl@'172.25.66.%' identified by 'hym19970818HYM#';
#刷新授权表
mysql> flush privileges;
配置slave端:(server2)
#1.安装数据库
[root@sever2 ~]# ls
[root@sever2 ~]# yum install -y *
#2.更改配置文件;仅server-id不同
[root@server2 mysql]# vim /etc/my.cnf
#####################
server-id=2
log-bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
#3.开启数据库
[root@server2 mysql]# systemctl start mysqld
#4.查看初始密码
[root@server2 mysql]# cat /var/log/mysqld.log | grep password
#5.初始化
[root@sever2 ~]# mysql_secure_installation
#6.复制主库
[root@server2~]# mysql -u root -p'hym19970818HYM#'
#GTID方式复制主库
mysql> change master to master_host='172.25.66.1',master_user='repl',master_password='hym19970818HYM#',MASTER_AUTO_POSITION = 1;
#开启slave
mysql> start slave;
#查看slave的状态
mysql> show slave status\G;
配置slave端:(server3)
操作步骤完全同server2结点
#1.安装数据库
[root@sever3 ~]# ls
[root@sever3 ~]# yum install -y *
#2.更改配置文件;仅server-id不同
[root@server3 mysql]# vim /etc/my.cnf
#####################
server-id=3
log-bin=mysql-bin
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
#3.开启数据库
[root@server3 mysql]# systemctl start mysqld
#4.查看初始密码
[root@server3 mysql]# cat /var/log/mysqld.log | grep password
2019-02-26T06:37:39.817817Z 1 [Note] A temporary password is generated for root@localhost: lVyoaMAbj8(!
#5.初始化
[root@sever3 ~]# mysql_secure_installation
#6.复制主库
[root@server3~]# mysql -u root -p'hym19970818HYM#'
#GTID方式复制主库
mysql> change master to master_host='172.25.66.1',master_user='repl',master_password='hym19970818HYM#',MASTER_AUTO_POSITION = 1;
#开启slave
mysql> start slave;
#查看slave的状态
mysql> show slave status\G;
(2).半同步复制
配置master端:
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
#1.安装master插件
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
##2.安装slave插件;因为后边要做主从切换,所以server1结点也可能会切成slave
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
#3.设定master插件自动开启
mysql> set global rpl_semi_sync_master_enabled = 1;
##4.slave插件自动开启
mysql> set global rpl_semi_sync_slave_enabled = 1;
##5.设定延迟时间,在可控范围内,越大越好,这样有利于保证主从数据的一致性
mysql> set global rpl_semi_sync_master_timeout=10000000000;
#6.查看半同的步状态
mysql> show variables like '%rpl%';
配置slave端:(server2)
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
##1.安装master插件;因为后边要做主从切换,所以server2结点也可能会切成master
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
#2.安装slave插件
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
#3.设定slave插件自动开启
mysql> set global rpl_semi_sync_slave_enabled = 1;
#4.重启IO线程
mysql> stop slave IO_THREAD;
mysql> start slave IO_THREAD;
#5.查看半同步的状态
mysql> show variables like '%rpl%';
#6.查看salve端的状态
mysql> show slave status\G;
配置slave端:(server3)
操作步骤完全同server2结点
[root@server3~]# mysql -u root -p'hym19970818HYM#'
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
mysql> set global rpl_semi_sync_slave_enabled = 1;
mysql> stop slave IO_THREAD;
mysql> start slave IO_THREAD;
mysql> show variables like '%rpl%';
mysql> show slave status\G;
测试:
在主库中:创建表并插入数据
[root@server1 mysql]# mysql -u root -p'hym19970818HYM#'
mysql> show databases;
mysql> create database wesstos;
mysql> use wesstos;
mysql> create table userlist (
-> username varchar(20) not null,
-> password varchar(15) not null);
mysql> desc userlist;
mysql> insert into userlist values ('user1','111');
mysql> select * from userlist;
在主库中:在从库中:查看数据,发现数据同步创建表并插入数据
[root@server2 mysql]# mysql -u root -p'hym19970818HYM#'
mysql> show databases;
mysql> use wesstos;
mysql> show tables;
mysql> select * from userlist;
[root@server3 mysql]# mysql -u root -p'hym19970818HYM#'
mysql> show databases;
mysql> use wesstos;
mysql> show tables;
mysql> select * from userlist;
2.配置MHA高可用
注意:
server1和server2和server3结点上都有解析(/etc/hosts)
配置管理机:
为了节省结点,我们将server1设定为既是master又是管理机
1.安装软件
在主库安装MHA Manage:(perl是依赖包)
[root@server1 ~]# ls
[root@server1 ~]# yum install -y *
[root@server1 ~]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server2:
[root@server1 ~]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server3:
在从库安装MHA Node:
[root@server2 ~]# ls
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@server2 ~]# yum install -y *
[root@server3 ~]# ls
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@server3 ~]# yum install -y *
2.设定ssh免密
(1)管理机可以免密连接其他结点
[root@server1 ~]# ssh-keygen
[root@server1 ~]# ssh-copy-id server1
[root@server1 ~]# ssh-copy-id server2
[root@server1 ~]# ssh-copy-id server3
测试:
[root@server1 ~]# ssh server1
Last login: Tue Feb 26 12:57:24 2019 from foundation66.localdomain
[root@server1 ~]# exit
logout
Connection to server1 closed.
[root@server1 ~]# ssh server2
Last login: Tue Feb 26 13:08:35 2019 from foundation66.localdomain
[root@server2 ~]# exit
logout
Connection to server2 closed.
[root@server1 ~]# ssh server3
Last login: Tue Feb 26 14:23:17 2019 from foundation66.localdomain
[root@sever3 ~]# exit
logout
Connection to server3 closed.
(2)主从结点之间相互免密
只需将在管理机端生成的公钥和私钥发送给其他结点即可
[root@server1 ~]# cd .ssh/
[root@server1 .ssh]# ls
authorized_keys id_rsa id_rsa.pub known_hosts
[root@server1 .ssh]# cd
#将.ssh/整个目录发送到其他结点
[root@server1 ~]# scp -r .ssh/ server2:
[root@server1 ~]# scp -r .ssh/ server3:
测试:
server结点就不用再测试了,因为它既是master又是管理结点,管理结点刚已经测试过了
server2可以免密连接其他结点:
[root@server2 ~]# cd .ssh/
[root@server2 .ssh]# ls
authorized_keys id_rsa id_rsa.pub known_hosts
[root@server2 .ssh]# ssh server1
Last login: Tue Feb 26 15:58:03 2019 from server2
[root@server1 ~]# exit
logout
Connection to server1 closed.
[root@server2 .ssh]# ssh server3
Last login: Tue Feb 26 15:58:11 2019 from sever2
[root@sever3 ~]# exit
logout
Connection to server3 closed.
server3可以免密连接其他结点:
[root@sever3 ~]# cd .ssh/
[root@sever3 .ssh]# ls
authorized_keys id_rsa id_rsa.pub known_hosts
[root@sever3 .ssh]# ssh server1
Last login: Tue Feb 26 15:58:26 2019 from server2
[root@server1 ~]# exit
logout
Connection to server1 closed.
[root@sever3 .ssh]# ssh server2
Last login: Tue Feb 26 15:58:06 2019 from server2
[root@server2 ~]# exit
logout
Connection to server2 closed.
3.编写配置文件
[root@server1 ~]# mkdir /etc/masterha
[root@server1 ~]# cd /etc/masterha/
[root@server1 masterha]# vim app1.conf
########################
[server default] #默认设置
manager_workdir=/etc/masterha #指定manager工作目录
manager_log=/var/log/masterha.log #指定manager日志存放路径
master_binlog_dir=/etc/masterha #指定mysql的数据目录
user=root #设定管理员用户
password=hym19970818HYM# #设置管理员密码
ping_interval=1 #设置监控频率,默认是3秒,尝试三次没有回应的时候自动进行railover
remote_workdir=/tmp #设置远端mysql在发生切换时,binlog(二进制日志)的保存位置
repl_user=repl #设置复制环境中的复制用户名
repl_password=hym19970818HYM# #设置复制用户的密码
ssh_user=root #设置免密用户
[server1] #master
hostname=172.25.66.1
port=3306
[server2] #salve
hostname=172.25.66.2
port=3306
candidate_master=1 #设置为候选master
check_repl_delay=0 #忽略复制延
[server3] #salve
hostname=172.25.66.3
port=3306
no_master=1 #不竞选master
3.测试
1.检测ssh免密
[root@server1 masterha]# masterha_check_ssh --conf=/etc/masterha/app1.conf
排错:若出现如下报错,一定是主从结点的免密没有做好
2.检测复制过程
报错:不允许root用户远程登陆
[root@server1 masterha]# masterha_check_repl --conf=/etc/masterha/app1.conf
解决方案:在master端,给root用户添加权限即可
[root@server1 masterha]# mysql -u root -p'hym19970818HYM#'
#给root用户授权
mysql> grant all on *.* to root@'%' identified by 'hym19970818HYM#';
[root@server1 masterha]# masterha_check_repl --conf=/etc/masterha/app1.conf
根据提示,设定slave端只读:
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
mysql> set global read_only=1;
[root@server3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> set global read_only=1
3.检测故障切换
1.手动切换
(1).故障切换
模拟主库master宕机:
#关闭数据库
[root@server1 ~]# systemctl stop mysqld
手动切换:
#由于server1(主库)已经宕机,此时将手动master切换到server2结点上
[root@server1 ~]# masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.conf --dead_master_host=172.25.66.1 --dead_master_ip=172.25.66.1 --dead_master_prot=3306 --new_master_host=172.25.66.2 --new_master_port=3306
测试:
发现当server1(主库)宕机后,server2结点接管master,server3结点依旧是slave
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
#查看slave信息为空,因为此时server2已经切换为master
mysql> show slave status\G;
mysql> show master status;
[root@sever3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G;
开启server1的数据库,手动将其添加到slave中
[root@server1 ~]# systemctl start mysqld
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
# MASTER_HOST为master主库的ip
mysql> CHANGE MASTER TO MASTER_HOST='172.25.66.2', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='hym19970818HYM#';
#开启slave
mysql> start slave;
mysql> show slave status\G;
(2)热切换
热切换:在主库没有宕机的情况下,手动切换 master
#删除app1.failover.complete文件
[root@server1 ~]# cd /etc/masterha/
[root@server1 masterha]# ls
app1.conf app1.failover.complete
[root@server1 masterha]# cat app1.failover.complete
[root@server1 masterha]# rm -rf app1.failover.complete
[root@server1 masterha]# ls
app1.conf
在主库活跃的情况下,手动将master切回到server1结点上
[root@server1 masterha]# masterha_master_switch --master_state=alive --conf=/etc/masterha/app1.conf --new_master_host=172.25.66.1 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
测试:
发现的确实现了在主库活跃的情况下,将master回切到server1结点上
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show master status;
[root@sever2 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G;
[root@sever3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show master status;
2.自动切换
设定自动切换:
[root@server1 ~]# cd /etc/masterha/
#自动切换
[root@server1 masterha]# nohup masterha_manager --conf=/etc/masterha/app1.conf &> /dev/null &
[1] 6286
[root@server1 masterha]# ps a
测试:
当主库宕机后,master自动切换到server2结点上
[root@server1 masterha]# systemctl stop mysqld
[1]+ Done nohup masterha_manager --conf=/etc/masterha/app1.conf &>/dev/null
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show master status;
[root@sever3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G
[root@server1 masterha]# pwd
/etc/masterha
[root@server1 masterha]# ls
app1.conf app1.failover.complete
[root@server1 masterha]# rm -rf app1.failover.complete
开启server1的数据库,手动添加到slave中(此过程没办法自动完成)
[root@server1 ~]# systemctl start mysqld
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
mysql> CHANGE MASTER TO MASTER_HOST='172.25.66.2', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='hym19970818HYM#';
#开启slave
mysql> start slave;
mysql> show slave status\G;
4.脚本实现vip的漂移
1.下载脚本
[kiosk@foundation66 Desktop]$ scp master_ip_failover master_ip_online_change root@172.25.66.1:/usr/local/bin/
[root@server1 ~]# cd /usr/local/bin/
[root@server1 bin]# ls
master_ip_failover master_ip_online_change
2.更改脚本
#此脚本用于实现手动切换vip
[root@server1 bin]# vim master_ip_online_change
###################
my $vip = '172.25.66.100/24'; #设定vip
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0"; #添加vip
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0"; #删除vip
#此脚本用于实现自动切换vip
[root@server1 bin]# vim master_ip_failover
###################
my $vip = '172.25.66.100/24'; #设定vip
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0"; #添加vip
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0"; #删除vip
my $exit_code = 0;
3.给脚本一个可执行权限
[root@server1 bin]# ll
total 8
-rw-r--r-- 1 root root 2179 Feb 26 21:14 master_ip_failover
-rw-r--r-- 1 root root 3796 Feb 26 21:13 master_ip_online_change
[root@server1 bin]# chmod +x *
[root@server1 bin]# ll
total 8
-rwxr-xr-x 1 root root 2179 Feb 26 21:14 master_ip_failover
-rwxr-xr-x 1 root root 3796 Feb 26 21:13 master_ip_online_change
4.更改配置文件
[root@server1 bin]# cd /etc/masterha/
[root@server1 masterha]# ls
app1.conf
[root@server1 masterha]# vim app1.conf
########################
master_ip_failover_script=/usr/local/bin/master_ip_failover #设置自动failover时候的切换脚本
master_ip_online_change_script=/usr/local/bin/master_ip_online_change #设置手动切换时候的切换脚本
5.给master端添加vip
[root@server2 ~]# ip addr
#添加vip
[root@server2 ~]# ip addr add 172.25.66.100/24 dev eth0
[root@server2 ~]# ip addr
6.测试
(1)手动热切换
手动切换:
#将master手动切换到server1上(热切换)
[root@server1 masterha]# masterha_master_switch --master_state=alive --conf=/etc/masterha/app1.conf --new_master_host=172.25.66.1 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
检测:
发现vip漂移到server1结点上,因为此时server1切换为了master
[root@server1 masterha]# ip addr
[root@server2 ~]# ip addr
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show master status;
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G;
[root@server3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G;
(2)自动切换
设定自动切换
[root@server1 ~]# nohup masterha_manager --conf=/etc/masterha/app1.conf &> /dev/null &
[1] 2220
检测:
发现当主库(server1)宕机后,server2自动接管master,此时vip漂移到server2结点上。也即是说,vip会随着master的切换而漂移,谁接管master,vip便会漂向谁
[root@server1 ~]# systemctl stop mysqld
[1]+ Done nohup masterha_manager --conf=/etc/masterha/app1.conf &>/dev/null
[root@server2 ~]# ip addr
[root@server1 ~]# ip addr
[root@server2 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show master status;
[root@server3 ~]# mysql -u root -p'hym19970818HYM#'
mysql> show slave status\G;
开启server1的数据库,手动将其添加到slave中
[root@server1 ~]# systemctl start mysqld
[root@server1 ~]# mysql -u root -p'hym19970818HYM#'
mysql> CHANGE MASTER TO MASTER_HOST='172.25.66.2', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='hym19970818HYM#';
mysql> start slave;
mysql> show slave status\G;
排错:
当开启slave时,报错
#启动slave时,使用repository中信息初始化relay log结构失败了
mysql> start slave;
ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
解决方案:先重置slave,再重新启动机即可
mysql> reset slave;
Query OK, 0 rows affected (0.25 sec)
mysql> start slave;
Query OK, 0 rows affected (0.14 sec)