实验环境:
server1 :172.25.254.1 是server2和server3的master结点
server2 :172.25.254.2
server3 :172.25.254.3
server4 :172.25.254.4 高可用结点
在企业的日常生产运营中,为了保证日常的业务稳定,通常会注意以下几个部分:
我们就需要对数据库进行集群,并做高可用的相关配置。
MHA 分为两种结点: manager 和 node 结点。
manager可以单独部署到一台服务器上,也可以部署到slave结点上,它可以管理多个master和slave结点,
目前大多的MHA部署会遵从 一主多从的架构,集群中最少需要有三台mysql服务器。
server1
server2
server3
工作原理:
在主节点的切换过程中,MHA会最大程度上去缓存二进制日志,识别拥有最新日志的slave结点,让其充当新的master结点,让其它的slave结点去同步新master结点的 relaylog 和 binlog ,更新差异,保证数据不丢失。同时MHA 可以和 半同步复制共同使用,以最大化的降低数据丢失,保持数据的一致性。
集群与高可用的配置需要两个重要的内容,就是主从复制和结点之间的免密登陆(因为i通过ssh连接)。
我们先配置
#server1:
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
log_bin=binlog
##下面这三行写在配置文件中就不用每次在mysql中进行设置了,必须先在mysql中安装这两个插件才可以,不然会报错
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
rpl_semi_sync_master_timeout = 1000000000000000 #超时时间可以不用加,会影响实验。
#server2:
server_id=2
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
log_bin=binlog
#server3:
server_id=3
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
log_bin=binlog
重启mysqld。
在server1和2中配置半同步
server1:
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
安装半同步插件
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
由于也可能成为slave结点,所以也安装slave插件
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
设置使用半同步复制
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
mysql> SET GLOBAL rpl_semi_sync_master_timeout = 1000000000000000;
设置超时时间。
server2中;
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> stop slave io_thread;
mysql> start slave io_thread;
重启io线程
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
此时我们在server1中插入数据,
在server2中查看
说明半同步复制操作已经配置好。
在进行绵密登陆的配置
server3 中也配置为slave结点,因为集群中至少两个slave结点:
mysql> change master to master_host='172.25.254.1',master_user='repl',master_password='Cc990718-+',master_auto_position=1;
mysql> start slave;
#################################
如果在开启slave时IO线程没有启动(使用show slave status\G查看),则是因为前面server1已经产生数据的缘故,这里我教大家怎样解决:
mysql> show global variables like '%gtid%'; 查看数据。
server1:
命令行中,手动备份数据给server3。
mysqldump --all-databases --single-transaction --triggers --routines --events --host=127.0.0.1 --port=3306 --user=root --password=Cc990718-+ > cay.sql 这就是数据库中全部的数据了。
scp cay.sql server3: 复制给server3.
server3:
mysql> stop slave;
Query OK, 0 rows affected (0.08 sec)
mysql> reset master; 清除master信息。
Query OK, 0 rows affected (0.37 sec)
命令行:
[root@server3 ~]# mysql -p < cay.sql
Enter password: 输入密码就ok了。
在重新change master
mysql> change master to master_host='172.25.254.1',master_user='repl',master_password='Cc990718-+',master_auto_position=1;
mysql> start slave;
就ok了 此时IO线程开启。
################################
在server4上进行高可用配置:
这里server4既做manager结点,又做node结点。
安装MHA的rpm包如下:
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
我们用到了4台主机,我们要保证每一台主机都可以和其它主机进行免密登陆。
#在server4中
ssh-keygen
ssh-copy-id server1
ssh-copy-id server2
ssh-copy-id server3
scp -r ~/.ssh server1: 将目录复制给其它三个主机,它们就不用去做免密了
scp -r ~/.ssh server2:
scp -r ~/.ssh server3:
在server1 2 3 上安装node软件包
yum install -y mha4mysql-node-0.58-0.el7.centos.noarch.rpm
然后配置server4上的配置文件:
mkdir /etc/masterha 建立MHA工作目录
vim /etc/masterha/masterha.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=Cc990718-+
user=root
ping_interval=1
remote_workdir=/tmp
repl_password=Cc990718-+
repl_user=repl
#report_script=/usr/local/send_report
#secondary_check_script= /usr/local/bin/master_secondary_check -s server03 -s server02
#shutdown_script=""
ssh_user=root
[server1]
hostname=172.25.254.1
port=3306
[server2]
hostname=172.25.254.2
port=3306
candidate_master=1 可以成为新的master
check_repl_delay=0
[server3]
hostname=172.25.254.3
port=3306
no_master=1 表示不可以成为新master
然后我们就可以去检查我们的主从复制和免密登陆了:
masterha_check_ssh --conf=/etc/masterha/masterha.cnf
masterha_check_repl --conf=/etc/masterha/masterha.cnf
但是在测试复制时就报错了,因为我们最开始安装mysql的时候设置了禁止root用户远程登陆,所以这里我们要在server1 2 3中重新授权root用户。
mysql> grant all on *.* to root@'%' identified by 'Cc990718-+';
Query OK, 0 rows affected, 1 warning (0.28 sec)
mysql> flush privileges; 刷新授权表
Query OK, 0 rows affected (0.28 sec)
再次测试:
然后我们就可以测试在server4中进行切换了。
我们先测试手动切换 master 结点:
要注意每次切换都会生成/etc /masterha/masterha.failover.error|complete 文件,下次切换前必须删除这个文件才可以进行新的切换,
目前我们的master结点是server1,我们手动切换是需要挂掉server1的mysql服务,然后server4上执行:
server1:
systemctl stop mysqld
server4命令行中执行:
masterha_master_switch \
--master_state=dead \ 状态为挂掉的
--conf=/etc/masterha/masterha.cnf \ 配置文件
--dead_master_host=172.25.254.1 \ 挂掉的master地址
--dead_master_ip=172.25.254.1 \
--dead_master_port=3306 \
--new_master_host=172.25.254.2 \ 新的master地址
--new_master_port=3306
可以看出重置了master结点,切换到了server2。
此时server4的目录中就出现了 .complete .这个文件,这就是切换的数据,代表切换成功,下次手动切换前需要删除这个文件。
而且在server2中已经没有slave的信息,而且server3 的master已经切换:
刚才的是离线切换,现在我们尝试在线切换:
先开启server1的mysql,在把它加回到集群中去:
systemctl start mysqld.service
#设置server1的主节点为server2:
mysql> change master to master_host='172.25.254.2',master_user='repl',master_password='Cc990718-+',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.51 sec)
mysql> start slave;
mysql> show slave status\G
命令行中执行:
masterha_master_switch --conf=/etc/masterha/masterha.cnf --master_state=alive --new_master_host=172.25.254.1 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
就切换成功了。
server1:
server2:
server3:
删除 /etc/masterha/masterha.failover.complete 刚刚转换完成产生的文件。
自动切换的工具为: masterha_manager ,它会检测数据库的master结点的状态,如果出现故障,会自动进行切换。
它只能执行一次,因为每次执行都回生成我们上面删除的文件,它自带守护进程,不能kill -9 杀掉。
我们启动:
在server4中:
nohup masterha_manager --conf=/etc/masterha/masterha.cnf &> /dev/null &
nohup 静默输出,& 后台运行。
测试:
这时我们挂掉当前的master主机 server1 ,
systemctl stop mysqld.service
这时我们发现server4 中的manager进程消失, 说明它只执行一次
然后我们在server2 和server3 中查看:
server2:
server3:
就切换成功了。
我们可以查看日志看看发生了神什么动作:
还是执行了changermaster的动作,和我们手动切换执行的命令相同,只不过自动执行。
并且这时manager进程自动结束了,这就是manager的自动切换.
在实际情况下,客户的访问都有一个固定的ip ,这个ip是对外的,我们不能告诉用户访问的地址变了,所以应做一个固定的接口,不论后端的数据库怎样改变,都让客户使用这个IP进行访问,所以我们应该设置VIP进行故障切换。
mysql> change master to master_host='172.25.254.2',master_user='repl',master_password='Cc990718-+',master_auto_position=1;
mysql> start slave;
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 = '172.25.0.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens3";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens3";
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 \"`;
}
sub stop_vip() {
return 0 unless ($ssh_user);
`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";
}
master_ip_online_change:
#!/usr/bin/env perl
use strict;
use warnings FATAL =>'all';
use Getopt::Long;
my $vip = '172.25.0.100/24'; # Virtual IP
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens3";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens3";
my $exit_code = 0;
my (
$command, $orig_master_is_new_slave, $orig_master_host,
$orig_master_ip, $orig_master_port, $orig_master_user,
$orig_master_password, $orig_master_ssh_user, $new_master_host,
$new_master_ip, $new_master_port, $new_master_user,
$new_master_password, $new_master_ssh_user,
);
GetOptions(
'command=s' => \$command,
'orig_master_is_new_slave' => \$orig_master_is_new_slave,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'orig_master_user=s' => \$orig_master_user,
'orig_master_password=s' => \$orig_master_password,
'orig_master_ssh_user=s' => \$orig_master_ssh_user,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
'new_master_user=s' => \$new_master_user,
'new_master_password=s' => \$new_master_password,
'new_master_ssh_user=s' => \$new_master_ssh_user,
);
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 $orig_master_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 $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
# A simple system call that disable the VIP on the old_master
sub stop_vip() {
`ssh $orig_master_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";
}
[root@server4 ~]# cp master_ip_* /usr/local/bin/
[root@server4 ~]# chmod +x /usr/local/bin/master_ip_*
[root@server4 ~]# ll /usr/local/bin/master_ip_*
-rwxr-xr-x 1 root root 2156 May 15 10:07 /usr/local/bin/master_ip_failover
-rwxr-xr-x 1 root root 3829 May 15 10:07 /usr/local/bin/master_ip_online_change
当前master结点为server2。server1 和 server3 是它的slave结点
先给server 添加172.25.254.100/24 的vip
测试我们的vip是否可以迁移到新的master结点中去,
在 serevr4中在先切换:
masterha_master_switch --conf=/etc/masterha/masterha.cnf --master_state=alive --new_master_host=172.25.254.1 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
且server2的ip消失:
此时的主结点已经切换为塞server1:
我们还需要开启 masterha_manager 进程
nohup masterha_manager --conf=/etc/masterha/masterha.cnf &> /dev/null &
我们挂掉server1的msyqld服务
[root@server1 ~]# systemctl stop mysqld
此时;
vip 又回到了server2上,而且master结点也已经切换。
server3:
这样对于用户来说只需要一直访问100 这个vip就可以持续访问了。