介绍
MHA是一套MySQL高可用管理软件,除了检测Master宕机后,提升候选Slave为New Master之外(漂虚拟IP),还会自动让其他Slave与New Master建立复制关系。MHA Manager可以单独部署在一台独立的机器上,并管理多个master-slave集群。
架构
原理
MHA Manager:MHA的管理节点,负责检测MySQL的状态,以及管理MySQL的复制关系
Master:MySQL对外提供的服务( 通过 VIP )的主节点
Slave(M):MySQL候选主节点,本质上为一个Slave节点,只是在Master宕机后,会被提升为 New Master
Slave N:MySQL从机节点,对外可以提供只读服务
当Master宕机后,MHA Manager会让 Slave(M) 提升为 New Master ,然后修改 Slave N 的复制关系( CHANGE MASTER ),指向 New Master
MHA Manager检测Master是否宕机, 不会简单的只检查自身与Master之间的直连状态
MHA Manager会 透过其他Slave节点去检测Master,进行二次探测 ,最大限度的避免脑裂的发生
比如说,检测到Master宕机了,MHA Manager会 透过Slave(M) 检测是否为宕机
如果检测后仍为宕机状态,会继续 透过Slave1...SlaveN 进行探测,只有在 透过所有节点 检测到Master宕机了,才真的认为Master宕机了
以上操作步骤的前提是,MHA Manager到所有MySQL节点的 SSH免密码登录要打通
最后将提供对外服务的 VIP漂移到New Master 上,继续对外提供服务
一个MHA Manager可以 管理多个 MySQL的Master-Slave集群(通过不同的app.conf)
搭建步骤
MHA安装
MHA由两个部分组成MHA Manager和MHA Node,Manager依赖Node,所以需要先安装Node。
MHA Node的安装,所有服务器均要安装 (包括MHA Manager)
安装Perl依赖
yum install perl-DBI perl-DBD-MySQL -y
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
安装成功后在/usr/bin/目录下生成以下文件
apply_diff_relay_logs
filter_mysqlbinlog
purge_relay_logs
save_binary_logs
MHA Manager的安装,仅仅只需要在MHA Manager服务器上安装
安装Perl依赖
yum install -y perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
安装成功后在/usr/bin/目录下生成以下文件
/usr/bin/masterha_check_repl
/usr/bin/masterha_check_ssh
/usr/bin/masterha_check_status
/usr/bin/masterha_conf_host
/usr/bin/masterha_manager
/usr/bin/masterha_master_monitor
/usr/bin/masterha_master_switch
/usr/bin/masterha_secondary_check
/usr/bin/masterha_stop
创建目录存放配置文件
mkdir -p /etc/masterha
配置SSH免密登录
SSH免密码登录是为了能够让MHA Manager可以远程登录到各个MySQL Server,以及各个MySQL Server之间可以相互远程登录,然后进行相关操作
MHA Manager生成Key
ssh-keygen
公钥分发
执行ssh.sh,需要修改里面的ip地址
sh ssh.sh
MHA Manager
将 MHA Manager 服务器的公钥,依次分发给 Master 、 Slave1 和 Slave2
MySQL Master
将 Master 的公钥依次分发给 Slave-M 和 Slave-1
MySQL Slave-M
将 Slave-M 的公钥依次分发给 Master 和 Slave-1
MySQL Slave2-1
将 Slave-1 的公钥依次分发给 Master 和 Slave-M
修改hosts
为了方便使用主机名登录, 同时MHA Manager在Failover阶段会做resolve name 的操作,所以需要把下列信息加入到 所有的节点 中
cat /etc/hosts
10.100.172.45 MHA-MySQL-M
10.100.172.43 MHA-MySQL-S1
10.100.172.44 MHA-MySQL-S2
MHA环境说明
Role |
IP |
Hostname |
Server_id |
Desc |
---|---|---|---|---|
Master & MHA Manager |
10.100.172.45 |
MHA-MySQL-M |
11 |
MHA 管理服务器,用于监控,MySQL Master服务器,用于read-write |
Candicate Master (Slave) |
10.100.172.43 |
MHA-MySQL-S1 |
44 |
MySQL Slave服务器,read-only,当Master宕机后,被提升为Master(New) |
Slave |
10.100.172.44 |
MHA-MySQL-S2 |
55 |
MySQL Slave服务器,read-only |
MySQL建立复制,此处不赘述
MHA配置
MHA配置文件和说明 配置文件统一放在 /etc/masterha/ 中,针对当前这个MySQL复制组,我们定义为 jfrog-cn.conf ,如果还有 其他MySQL复制组 ,可以 继续定义
[server default]
log_level=debug
manager_log=/var/log/masterha/jfrog-cn/manager.log
manager_workdir=/var/log/masterha/jfrog-cn
master_binlog_dir=/data/mysql/
master_ip_failover_script=/usr/local/bin/master_ip_failover
master_ip_online_change_script=/usr/local/bin/master_ip_online_change
password=*******
ping_interval=3
ping_type=INSERT
remote_workdir=/tmp
repl_password=*******
repl_user=repl
secondary_check_script=/usr/bin/masterha_secondary_check -s 10.100.172.43 -s 10.100.172.44 --user=root --master_host=10.100.172.45 --master_port=3306
ssh_user=root
user=root
[server1]
candidate_master=1
check_repl_delay=0
hostname=10.100.172.45
port=3306
[server2]
candidate_master=1
check_repl_delay=0
hostname=10.100.172.43
port=3306
[server3]
hostname=10.100.172.44
no_master=1
port=3306
MHA脚本说明
#!/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 = '10.100.172.47/24';
my $key = '88';
my $ssh_start_vip = "/sbin/ifconfig ens192:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens192:$key down";
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 (
$command, $ssh_user, $orig_master_host, $orig_master_ip,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port
#);
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,
);
my $vip = '10.100.172.47/24';
注意修改系统对应的接口名称(CentOS比较变态)
my $eth = 'ens192';
my $key = '47';
my $ssh_start_vip = "/sbin/ifconfig $eth:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig $eth:$key down";
my $ssh_user = "root";
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,
'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" ) {
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 --ssh-user=user --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";
}
-
修改上述两个脚本中的 $vip ,以符合自己实际的需求
-
将上述两个文件复制到 MHA Manager 节点的 /usr/local/bin 中(同masterha_*在同一个目录)
-
将上述两个文件赋予执行权限: ◦ chmod +x master_ip_failover ◦ chmod +x master_ip_online_change
定时清理relay-log的脚本
将下面这个脚本以及定时任务放入 所有的Slave节点,并添加到定时任务
#!/bin/bash
Filename:/opt/mha/cron_purge_relay_logs.sh
user=root
passwd=*********
port=3306
host=localhost
socket=/data/mysql/mysql.sock
log_dir='/data/mysql/purge_relay_logs'
work_dir='/data/mysql/relay_log_hardlink'
purge='/usr/bin/purge_relay_logs'
if [[ ! -d ${work_dir} ]];then
mkdir ${work_dir} -p
fi
if [[ ! -d ${log_dir} ]];then
mkdir ${log_dir} -p
fi
${purge} --user=${user} --password=${passwd} --host=${host} --socket=${socket} --workdir=${work_dir} --disable_relay_log_purge >> ${log_dir}/purge_relay_logs.log 2>&1
SSH检测
masterha_check_ssh --conf=/etc/masterha/jfrog-cn.conf
复制关系检测
masterha_check_repl --conf=/etc/masterha/jfrog-cn.conf
启动MHA
在MySQL Master上添加虚拟ip
ifconfig ens192:88 10.100.172.47/24
自动Failover测试
停止MySQL Master,虚拟ip自动切换到Slave-M上