MHA简介
MHA(Master HighAvailability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
实验环境
os:rhel7.3
主机 | ip | 节点 |
---|---|---|
server1 | 172.25.62.1 | master |
server2 | 172.25.62.1 | slave |
server3 | 172.25.62.1 | slave |
server5 | 172.25.62.1 | MHA |
在server1,server2,server3这3台主机都要安装mysql,详见mysql的主从复制(异步复制)这里的mysql安装。
搭建步骤:
1.在server1,server2,server3主机进行配置
1.配置gtid的主从复制
gtid的组从复制详见mysql的主从复制(异步复制)这里不再重复。要注意的是要修改的配置文件有所不同,配置的内容为server1作为master,另外两台作为slave。
vim /etc/my.cnf
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
log_bin=binlog
三台主机的server_id修改时要记得是不一样的。
搭建好一主两从的主从复制之后就可以进行下一步了。
2.在三台主机安装mha4mysql-manager
2.在server5上进行MHA配置
1.安装相关软件
[root@server5 MHA-7]# ls
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-manager-0.58.tar.gz
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm
[root@server5 MHA-7]# yum install -y mha4mysql-manager-0.58-0.el7.centos.noarch.rpm perl-* \
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
2设置4台主机的免密访问
[root@server5 ~]# ssh-keygen
生成密钥。
[root@server5 ~]# ssh-copy-id server1
[root@server5 ~]# ssh-copy-id server2
[root@server5 ~]# ssh-copy-id server3
给三台主机发送密钥。
[root@server5 ~]# scp -r .ssh server1:
id_rsa 100% 1679 1.6KB/s 00:00
id_rsa.pub 100% 394 0.4KB/s 00:00
known_hosts 100% 543 0.5KB/s 00:00
[root@server5 ~]# scp -r .ssh server2:
id_rsa 100% 1679 1.6KB/s 00:00
id_rsa.pub 100% 394 0.4KB/s 00:00
known_hosts 100% 543 0.5KB/s 00:00
[root@server5 ~]# scp -r .ssh server3:
id_rsa 100% 1679 1.6KB/s 00:00
id_rsa.pub 100% 394 0.4KB/s 00:00
known_hosts 100% 543 0.5KB/s 00:00
使3台主机互相免密。
3.进行MHA配置
[root@server5 MHA-7]# mkdir /etc/masterha
[root@server5 MHA-7]# cd /etc/masterha/
[root@server5 masterha]# vim app1.cnf
[server default]
manager_workdir=/etc/masterha
manager_log=/var/log/masterha.log
master_binlog_dir=/etc/masterha
#master_ip_failover_script= /usr/local/bin/master_ip_failover
#master_ip_online_change_script= /usr/local/bin/master_ip_online_change
password=Hang+123 #MySQL管理帐号和密码
user=root
ping_interval=1
remote_workdir=/tmp
repl_password=Hang+123
repl_user=repl
#report_script=/usr/local/send_report
#secondary_check_script= /usr/local/bin/masterha_secondary_check -s server03 -s server02
#shutdown_script=""
ssh_user=root ## 系统ssh用户
[server1]
hostname=172.25.62.1
port=3306
[server2]
hostname=172.25.62.2
port=3306
candidate_master=1
check_repl_delay=0
[server3]
hostname=172.25.62.3
port=3306
no_master=1 ##no_master表示这个节点不能作为master
创建目录,编写配置文件。
4.检测ssh连接
[root@server5 ~]# masterha_check_ssh --conf=/etc/masterha/app1.cnf
没有报错,ssh检测成功。
5.检测复制功能
[root@server5 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
出现错误,因为server5默认是用root用远程连接数据库的,但在初始化数据库授权时禁止了root远程访问,所以要对数据库重新授权。
重新授权在master节点server上进行。
mysql> grant all on *.* to root@'%' identified by 'Hang+123';
对数据库授权之后在进行测试
[root@server5 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
复制功能检测成功。
6.master节点手动切换
现在的master节点是server1,现在测试使server1的mysql停掉,把server2转换为master。
首先要测试一下manager能否开启
[root@server5 ~]# nohup masterha_manager \
--conf=/etc/masterha/app1.cnf \
--remove_dead_master_conf \
--ignore_last_failover < /dev/null > /var/log/masterha.log 2>&1 &
[1] 2450
[root@server5 ~]# ps ax
master正常开启。
[root@server5 ~]# masterha_stop --conf=/etc/masterha/app1.cnf
关闭master,之后在server1手动将mysql服务停止。
之后,手动切换master为server2.
[root@server5 ~]# masterha_master_switch \
--master_state=dead \
--conf=/etc/masterha/app1.cnf \
--dead_master_host=172.25.62.1 --dead_master_port=3306 \
--new_master_host=172.25.62.2 --new_master_port=3306
切换时中间出现的选项都填yes,之后在server3上查看状态。
mysql> show slave status\G
master已经切换为server2了。
测试完成之后,我们再把刚才停掉的server再次加入集群,这次加入集群后server1将作为slave节点。
在server1开启mysql,登陆。
mysql> change master to master_host='172.25.62.2', master_user='repl', master_password='Hang+123', master_auto_position=1;
加入集群。
加入集群成功,master为server2.
7.master的手动在线切换
这次的切换和上面的不同在于要在master正常工作的状态下切换master节点。
切换master节点为server1
[root@server5 MHA-7]# masterha_master_switch \
--conf=/etc/masterha/app1.cnf \
--master_state=alive --new_master_host=172.25.62.1 --new_master_port=3306 \
--orig_master_is_new_slave --running_updates_limit=10000
同样中间的选项都填yes,之后在server2或server3查看状态。
master节点已经切换为server1。
配置脚本和vip漂移
1.在server1上配置vip
[root@server1 ~]# ip addr add 172.25.62.100/24 dev ens3
2.编写脚本
[root@server5 ~]# vim /usr/local/bin/master_ip_failover
1 #!/usr/bin/env perl
2 use strict;
3 use warnings FATAL => 'all';
4 use Getopt::Long;
5
6 my (
7 $command, $ssh_user, $orig_master_host, $orig_master_ip,
8 $orig_master_port, $new_master_host, $new_master_ip, $new_master_port
9 );
10
11 my $vip = '172.25.62.100/24'; ##修改ip
12 my $key = '1';
13 my $ssh_start_vip = "/sbin/ip addr add $vip dev ens3";
14 my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens3";
15
16 GetOptions(
17 'command=s' => \$command,
18 'ssh_user=s' => \$ssh_user,
19 'orig_master_host=s' => \$orig_master_host,
20 'orig_master_ip=s' => \$orig_master_ip,
21 'orig_master_port=i' => \$orig_master_port,
22 'new_master_host=s' => \$new_master_host,
23 'new_master_ip=s' => \$new_master_ip,
24 'new_master_port=i' => \$new_master_port,
25 );
26
27 exit &main();
28
29 sub main {
30
31 print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
32
33 if ( $command eq "stop" || $command eq "stopssh" ) {
34
35 my $exit_code = 1;
36 eval {
37 print "Disabling the VIP on old master: $orig_master_host \n";
38 &stop_vip();
39 $exit_code = 0;
40 };
41 if ($@) {
42 warn "Got Error: $@\n";
43 exit $exit_code;
44 }
45 exit $exit_code;
46 }
47 elsif ( $command eq "start" ) {
48
49 my $exit_code = 10;
50 eval {
51 print "Enabling the VIP - $vip on the new master - $new_master_host \n";
52 &start_vip();
53 $exit_code = 0;
54 };
55 if ($@) {
56 warn $@;
57 exit $exit_code;
58 }
59 exit $exit_code;
60 }
61 elsif ( $command eq "status" ) {
62 print "Checking the Status of the script.. OK \n";
63 exit 0;
64 }
65 else {
66 &usage();
67 exit 1;
68 }
69 }
70
71 sub start_vip() {
72 `ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
73 }
74 sub stop_vip() {
75 return 0 unless ($ssh_user);
76 `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
77 }
78
79 sub usage {
80 print
81 "Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_m aster_host=host --new_master_ip=ip --new_master_port=port\n";
82 }
[root@server5 ~]# vim /usr/local/bin/master_ip_online_change
1 #!/usr/bin/env perl
2 use strict;
3 use warnings FATAL =>'all';
4
5 use Getopt::Long;
6
7 my $vip = '172.25.62.100/24'; #Virtual IP
8 my $key = "1";
9 my $ssh_start_vip = "/sbin/ip addr add $vip dev ens3";
10 my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens3";
11 my $exit_code = 0;
12
13 my (
14 $command, $orig_master_is_new_slave, $orig_master_host,
15 $orig_master_ip, $orig_master_port, $orig_master_user,
16 $orig_master_password, $orig_master_ssh_user, $new_master_host,
17 $new_master_ip, $new_master_port, $new_master_user,
18 $new_master_password, $new_master_ssh_user,
19 );
20 GetOptions(
21 'command=s' => \$command,
22 'orig_master_is_new_slave' => \$orig_master_is_new_slave,
23 'orig_master_host=s' => \$orig_master_host,
24 'orig_master_ip=s' => \$orig_master_ip,
25 'orig_master_port=i' => \$orig_master_port,
26 'orig_master_user=s' => \$orig_master_user,
27 'orig_master_password=s' => \$orig_master_password,
28 'orig_master_ssh_user=s' => \$orig_master_ssh_user,
29 'new_master_host=s' => \$new_master_host,
30 'new_master_ip=s' => \$new_master_ip,
31 'new_master_port=i' => \$new_master_port,
32 'new_master_user=s' => \$new_master_user,
33 'new_master_password=s' => \$new_master_password,
34 'new_master_ssh_user=s' => \$new_master_ssh_user,
35 );
36
37
38 exit &main();
39
40 sub main {
41
42 #print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
43
44 if ( $command eq "stop" || $command eq "stopssh" ) {
45
46 # $orig_master_host, $orig_master_ip, $orig_master_port are passed.
47 # If you manage master ip address at global catalog database,
48 # invalidate orig_master_ip here.
49 my $exit_code = 1;
50 eval {
51 print "\n\n\n***************************************************************\n";
52 print "Disabling the VIP - $vip on old master: $orig_master_host\n";
53 print "***************************************************************\n\n\n\n";
54 &stop_vip();
55 $exit_code = 0;
56 };
57 if ($@) {
58 warn "Got Error: $@\n";
59 exit $exit_code;
60 }
61 exit $exit_code;
62 }
63 elsif ( $command eq "start" ) {
64
65 # all arguments are passed.
66 # If you manage master ip address at global catalog database,
67 # activate new_master_ip here.
68 # You can also grant write access (create user, set read_only=0, etc) here.
69 my $exit_code = 10;
70 eval {
71 print "\n\n\n***************************************************************\n";
72 print "Enabling the VIP - $vip on new master: $new_master_host \n";
73 print "***************************************************************\n\n\n\n";
74 &start_vip();
75 $exit_code = 0;
76 };
77 if ($@) {
78 warn $@;
79 exit $exit_code;
80 }
81 exit $exit_code;
82 }
83 elsif ( $command eq "status" ) {
84 print "Checking the Status of the script.. OK \n";
85 `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_start_vip \"`;
86 exit 0;
87 }
88 else {
89 &usage();
90 exit 1;
91 }
92 }
93
94 # A simple system call that enable the VIP on the new master
95 sub start_vip() {
96 `ssh $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;
97 }
98 # A simple system call that disable the VIP on the old_master
99 sub stop_vip() {
100 `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
101 }
102
103 sub usage {
104 print
105 "Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_maste r_host=host --new_master_ip=ip --new_master_port=port\n";
106 }
设置自动添加和删除vip,如果脚本没有执行权限要记得给执行权限。
3.测试vip漂移
[root@server5 bin]# masterha_master_switch \
--conf=/etc/masterha/app1.cnf \
--master_state=alive \
--new_master_host=172.25.62.2 --new_master_port=3306 \
--orig_master_is_new_slave --running_updates_limit=1000
测试vip是否可以漂移,使vip从server1漂移到server2.
,在server2查看,vip成功漂移到server2.
vip漂移之后,master节点也由server1变为server。
4.测试全自动切换
设置好vip漂移就可以设置master的全自动切换了。
首先,删除app1.failover.complete文件。
之后开启manager
[root@server5 masterha]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/dev/null &
此时master为server2,所以关闭server2的mysql服务,模拟故障。
[root@server2 ~]# systemctl stop mysqld.service
之后在server5上查看日志
[root@server5 masterha]# cat /var/log/masterha.log
可以看到,vip漂移成功。
vip漂移到了server1,在server3上查看
master也成功切换到了server1。