环境:
centos 6.8 x64
1主1从,manager放在从库。
master:192.168.139.130 centos1
**slave:192.168.139.129 centos2 **
VIP:192.168.139.222
实施大概步骤:
1. 两节点配置epel的yum源,安装相关依赖包
2. 建立主从复制关系
3. ssh-keygen实现两台机器之间相互免密钥登录
4. 安装mha(一主一从的架构建议两个节点都安装manager和node包)
5. 在slave上管理MHA配置文件
6. masterha_check_ssh验证ssh信任登录是否成功,masterha_check_repl验证mysql复制是否成功
7. 启动MHA manager,并监控日志文件
8. 切换测试
准备工作:
iptables打开mysql端口
selinx关闭
shell > vim /etc/selinux/config
SELINUX=disabled
hosts配置
shell > vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 centos1
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.139.130 centos1
192.168.139.129 centos2
最好在两主机的127.0.0.1也配置 。
1:两节点
配置epel的yum源,安装相关依赖包
shell > rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm
shell > rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
2:建立主从复制关系
这里不再详细介绍,具体可以翻看前面文章:Mysql5.7 主从复制实现
3:ssh-keygen实现两台机器之间相互免密钥登录
注:如果管理节点和数据节点共用,要自己能免密钥登录自己
在master上:
shell > ssh-keygen -t rsa #创建密钥
shell > ssh-copy-id -i ~/.ssh/id_rsa.pub centos2 #发送ssh密钥到其他服务器
shell > ssh-copy-id -i ~/.ssh/id_rsa.pub centos1 #发送ssh密钥到自己
在slave上:
shell > ssh-keygen -t rsa #创建密钥
shell > ssh-copy-id -i ~/.ssh/id_rsa.pub centos1 #发送ssh密钥到其他服务器
shell > ssh-copy-id -i ~/.ssh/id_rsa.pub centos2 #发送ssh密钥到自己
4:安装mha(一主一从的架构建议两个节点都安装manager和node包)
两台服务器
安装依赖包:
shell > yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes -y
安装mha软件,这里两个包都有,还有配置文件,直接下载mha_packge.zip即可 :mha4mysql-manager mha4mysql-node
master
解压mha_packge.zip:
shell > cd packge
shell > rpm -Uvh mha4mysql-manager-0.56-0.el6.noarch.rpm mha4mysql-node-0.56-0.el6.noarch.rpm
shell > cp -ar masterha /etc/
shell > mkdir /var/log/masterha/app1 -p
slave
解压mha_packge.zip:
shell > cd packge
shell > rpm -Uvh mha4mysql-manager-0.56-0.el6.noarch.rpm mha4mysql-node-0.56-0.el6.noarch.rpm
shell > cp -ar masterha /etc/
shell > mkdir /var/log/masterha/app1 -p
5:在slave上管理MHA配置文件
MHA的配置简单,只用在manager节点上进行配置限可。配置文件最少一个,一般可以分成两个,为了减少一个manager节点管理多个集群时可以少写一点配置。但我们这里一主一从结构,建议配置文件配置完毕后,放置到两台机器上都是一样的
。
配置文件如下:
[root@centos6-2 masterha]# cd /etc/masterha
[root@centos6-2 masterha]# cat masterha_default.conf #修改全局配置文件
[server default]
#MySQL的用户和密码
user=root
password=123456
#系统ssh用户
ssh_user=root
#复制用户
repl_user=backup
repl_password=123456
#监控
ping_interval=1
#shutdown_script=""
#切换调用的脚本
master_ip_failover_script= /etc/masterha/master_ip_failover
master_ip_online_change_script= /etc/masterha/master_ip_online_change
[root@centos6-2 masterha]# cat app1.conf #修改集群配置文件
[server default]
#mha manager工作目录
manager_workdir = /var/log/masterha/app1
manager_log = /var/log/masterha/app1/app1.log
remote_workdir = /var/log/masterha/app1
[server1]
hostname=centos1 #当前master
master_binlog_dir = /usr/local/mysql/data
candidate_master = 1
check_repl_delay = 0 #用防止master故障时,切换时slave有延迟,卡在那里切不过来。
[server2]
hostname=centos2
master_binlog_dir= /usr/local/mysql/data
candidate_master=1
check_repl_delay=0
注:如果有一主多从架构,那么只需要在app1/conf文件后面再多添加几个配置即可,类似如下:
[server3]
hostname=192.168.139.x
port=3306
master_binlog_dir= /usr/local/mysql/data
修改master_ip_*文件中的VIP和绑定网卡:
[root@centos6-2 masterha]# cat drop_vip.sh
vip="192.168.139.211/24"
/sbin/ip addr del $vip dev eth0
[root@centos6-2 masterha]# cat init_vip.sh
vip="192.168.139.211/24"
/sbin/ip addr add $vip dev eth0
[root@centos6-2 masterha]# vim master_ip_failover
my $vip = "192.168.139.211"; #改为如此
my $if = "eth0"; #改为如此
[root@centos6-2 masterha]# vim master_ip_online_change
my $vip = "192.168.139.211"; #改为如此
my $if = "eth0"; #改为如此
把脚本赋予执行权限:shell > chmod +x drop_vip.sh init_vip.sh master_ip_*
6.masterha_check_ssh验证ssh信任登录是否成功,masterha_check_repl验证mysql复制是否成功
主一从架构的主库和从库上的管理节点建议都要进行测试,不单单只测试从库上的管理节点,测试ssh连通性:
shell > masterha_check_ssh --conf=/etc/masterha/app1.conf
注意:如果你是用虚拟机做实验,很可能碰到这步骤报错,碰到两边都无法ssh或者一边可以,一边不可以,此时,可以重新创建密钥试试,如果多次尝试仍然不行,那么就把发起ssh连接而失败的虚拟机换一台再试。或者,看看你的架构是不是把管理节点和数据节点放一起,而管理节点上又没有配置自己到自己免密钥登录。
看到最后提示:[info] All SSH connection tests passed successfully.
表示测试通过
测试集群中的主从复制:
shell > masterha_check_repl --conf=/etc/masterha/app1.conf --global_conf=/etc/masterha/masterha_default.conf
注意:执行这个检测命令的时候使用的是user=root帐号去检测,注意user=root帐号也要有远程权限,另外,把mysql目录下的命令做个链接:ln -s /usr/local/mysql/bin/ /usr/bin/*
看到最后提示:MySQL Replication Health is OK.
表示测试通过
7.启动MHA manager,并监控日志文件
启动管理节点最好使用screen启动:
shell > nohup masterha_manager --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --remove_dead_master_conf --ignore_last_failover> /tmp/mha_manager.log 2>&1 &
sh /etc/masterha/init_vip.sh
确认VIP 绑定成功,如果业务按VIP 配置的访问DB,应该已经可以正常访问
启动之后查看控制台输出日志:
/tmp/mha_manager.log
查看app1日志输出:
/var/log/masterha/app1/app1.log
查看master的健康状况日志:
/var/log/masterha/app1/app1.master_status.health
检查是否启动成功:
shell > masterha_check_status --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
8.切换测试
1).在线手工切换(维护切换,需要把MHA监控进程关掉)
:
shell > masterha_master_switch --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --master_state=alive --new_master_host=centos2 --orig_master_is_new_slave --running_updates_limit=10000
–orig_master_is_new_slave:把旧的master配置为从库
–running_updates_limit=10000:如果主从库同步延迟在10000s内都允许切换,但是但是切换的时间长短是由recover时relay 日志的大小决定
切换成功需要看到类似下面的提示:
info] Switching master to centos2(192.168.139.129:3306) completed successfully
同时要查看VIP是否已经漂移到了新的主库上面
2).故障手工切换(MHA进程没启动或者挂了的同时主库也挂了)
:
shell > masterha_master_switch --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --dead_master_host=old_ip
--master_state=dead --new_master_host=new_ip --ignore_last_failover
切换成功需要看到类似如下提示:
Master centos1(192.168.139.130:3306) is down!
Check MHA Manager logs at centos6-2:/var/log/masterha/app1/app1.log for details.
Started automated(non-interactive) failover.
Invalidated master IP address on centos1(192.168.139.130:3306)
The latest slave centos2(127.0.0.1:3306) has all relay logs for recovery.
Selected centos2(127.0.0.1:3306) as a new master.
centos2(127.0.0.1:3306): OK: Applying all logs succeeded.
centos2(127.0.0.1:3306): OK: Activated master IP address.
Generating relay diff files from the latest slave succeeded.
centos2(127.0.0.1:3306): Resetting slave info succeeded.
Master failover to centos2(127.0.0.1:3306) completed successfully.
注意:如果是主库服务器还活着,只是mysqld挂了的时候,VIP在切换的时候也会自动漂移,如果是服务器挂了,那么在挂掉的主库重启后,注意不要让VIP随开机启动,因为此时VIP已经漂移到了从库上,从库上可能正在接管业务,故障主库起来后,需要确认数据是否跟新的主库一样,如果一样,那么就把故障主库作为新的从库加入新主库下
3).故障自动切换(启动MHA监控进程)手动把主库mysqld停掉,观察/var/log/masterha/app1.log日志输出,看到如下信息:
Master centos1(192.168.139.130:3306) is down!
Check MHA Manager logs at centos6-2:/var/log/masterha/app1/app1.log for details.
Started automated(non-interactive) failover.
Invalidated master IP address on centos1(192.168.139.130:3306)
The latest slave centos2(127.0.0.1:3306) has all relay logs for recovery.
Selected centos2(127.0.0.1:3306) as a new master.
centos2(127.0.0.1:3306): OK: Applying all logs succeeded.
centos2(127.0.0.1:3306): OK: Activated master IP address.
Generating relay diff files from the latest slave succeeded.
centos2(127.0.0.1:3306): Resetting slave info succeeded.
Master failover to centos2(127.0.0.1:3306) completed successfully.
表示成功切换,切换成功后,查看VIP是否漂移到了从库上(切换成功后,MHA进程会自动停止),同时查看/etc/masterha/app1.conf文件中的[server1]的配置是否都被删除掉了
故障主库起来后,需要确认数据是否跟新的主库一样,如果一样,那么就把故障主库作为新的从库加入新主库下。然后在故障主库上启动MHA进程。
故障转移后,用命令恢复原来的master
(1)、在旧master上执行:
shell>service mysql start //数据库启动
shell>mysql -usunney -psunney
mysql> reset master;
mysql> change master to master_host='192.168.139.129', master_port=3306, master_user='backup', master_password='123456', master_log_file='mysql-bin.00002', master_log_pos=1184;
mysql> start slave; #暂时先把旧master变为slave
如果主从未同步,报错 ERROR] Slave I/O for channel '': error connecting to master 'backup@192.168.139.129:3306' - retry-time: 60 retries: 36, Error_code: 1045
检查backup 是否可以远程登陆,以及防火墙。如果是远程问题,可以flush privileges;
再尝试。
附:
MHA 日常维护命令集:
1).查看ssh 登陆是否成功
shell > masterha_check_ssh --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
2).查看复制是否建立好
shell > masterha_check_repl --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
3).检查启动的状态
shell > masterha_check_status–global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
4).停止mha
shell > #masterha_stop --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
5).启动mha
shell > nohup masterha_manager --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf > /tmp/mha_manager.log < /dev/null 2>&1 &
注意:当有slave 节点宕掉的情况是启动不了的,加上–ignore_fail_on_start 即使有节点宕掉也能启动mha,需要在配置文件中设置ignore_fail=1
6).failover 后下次重启
每次failover 切换后会在管理目录生成文件app1.failover.complete ,下次在切换的时候会发现有这个文件导致切换不成功,需要手动清理掉。
shell > rm -rf /masterha/app1/app1.failover.complete
也可以加上参数–ignore_last_failover
7).手工failover
手工failover 场景,master 死掉,但是masterha_manager 没有开启,可以通过手工failover:
shell > masterha_master_switch --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --dead_master_host=old_ip --master_state=dead --new_master_host=new_ip --ignore_last_failover
8).masterha_manager 是一种监视和故障转移的程序。另一方面,masterha_master_switch 程序不监控主库。masterha_master_switch 可以用于主库故障转移,也可用于在线总开关。
9).手动在线切换(master还或者,比如做维护切换时)
shell > masterha_master_switch --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --master_state=alive --new_master_host=192.168.199.78 --orig_master_is_new_slave
或者
shell > masterha_master_switch --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --master_state=alive --new_master_host=192.168.199.78 -orig_master_is_new_slave --running_updates_limit=10000
–orig_master_is_new_slave 切换时加上此参数是将原master 变为slave 节点,如果不加此参数,原来的master 将不启动
–running_updates_limit=10000 切换时候选master 如果有延迟的话,mha 切换不能成功,加上此参数表示延迟在此时间范围内都可切换(单位为s),但是切换的时间长短是由recover时relay 日志的大小决定
手动在线切换mha,切换时需要将在运行的mha 停掉后才能切换。
在备库先执行DDL,一般先stop slave,一般不记录mysql 日志,可以通过set SQL_LOG_BIN =0 实现。然后进行一次主备切换操作,再在原来的主库上执行DDL。这种方法适用于增减索引,如果是增加字段就需要额外注意。
注意:Online master switch 开始只有当所有下列条件得到满足。
1). IO threads on all slaves are running // 在所有slave 上IO 线程运行。
2). SQL threads on all slaves are running //SQL 线程在所有的slave 上正常运行。
3). Seconds_Behind_Master on all slaves are less or equal than --running_updates_limit
seconds // 在所有的slaves 上Seconds_Behind_Master 要小于等于running_updates_limit
seconds
4). On master, none of update queries take more than --running_updates_limit seconds in the
show processlist output // 在主上,没有更新查询操作多于running_updates_limit seconds
附上mha56的脚本,亲测MHA集群,好使: 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.1.100/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$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 \"`;
}
# 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 {
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
# Copyright (C) 2011 DeNA Co.,Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
## Note: This is a sample script and is not complete. Modify the script based on your environment.
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
use MHA::DBHelper;
use MHA::NodeUtil;
use Time::HiRes qw( sleep gettimeofday tv_interval );
use Data::Dumper;
my $_tstart;
my $_running_interval = 0.1;
my (
$command, $orig_master_host, $orig_master_ip,
$orig_master_port, $orig_master_user,
$new_master_host, $new_master_ip, $new_master_port,
$new_master_user,
);
my $vip = '192.168.1.100/24'; # Virtual IP
my $key = "1";
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";
my $ssh_user = "root";
my $new_master_password='Mobiyun!2345678';
my $orig_master_password='Mobiyun!2345678';
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,
'orig_master_user=s' => \$orig_master_user,
#'orig_master_password=s' => \$orig_master_password,
'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,
);
exit &main();
sub current_time_us {
my ( $sec, $microsec ) = gettimeofday();
my $curdate = localtime($sec);
return $curdate . " " . sprintf( "%06d", $microsec );
}
sub sleep_until {
my $elapsed = tv_interval($_tstart);
if ( $_running_interval > $elapsed ) {
sleep( $_running_interval - $elapsed );
}
}
sub get_threads_util {
my $dbh = shift;
my $my_connection_id = shift;
my $running_time_threshold = shift;
my $type = shift;
$running_time_threshold = 0 unless ($running_time_threshold);
$type = 0 unless ($type);
my @threads;
my $sth = $dbh->prepare("SHOW PROCESSLIST");
$sth->execute();
while ( my $ref = $sth->fetchrow_hashref() ) {
my $id = $ref->{Id};
my $user = $ref->{User};
my $host = $ref->{Host};
my $command = $ref->{Command};
my $state = $ref->{State};
my $query_time = $ref->{Time};
my $info = $ref->{Info};
$info =~ s/^\s*(.*?)\s*$/$1/ if defined($info);
next if ( $my_connection_id == $id );
next if ( defined($query_time) && $query_time < $running_time_threshold );
next if ( defined($command) && $command eq "Binlog Dump" );
next if ( defined($user) && $user eq "system user" );
next
if ( defined($command)
&& $command eq "Sleep"
&& defined($query_time)
&& $query_time >= 1 );
if ( $type >= 1 ) {
next if ( defined($command) && $command eq "Sleep" );
next if ( defined($command) && $command eq "Connect" );
}
if ( $type >= 2 ) {
next if ( defined($info) && $info =~ m/^select/i );
next if ( defined($info) && $info =~ m/^show/i );
}
push @threads, $ref;
}
return @threads;
}
sub main {
if ( $command eq "stop" ) {
## Gracefully killing connections on the current master
# 1. Set read_only= 1 on the new master
# 2. DROP USER so that no app user can establish new connections
# 3. Set read_only= 1 on the current master
# 4. Kill current queries
# * Any database access failure will result in script die.
my $exit_code = 1;
eval {
## Setting read_only=1 on the new master (to avoid accident)
my $new_master_handler = new MHA::DBHelper();
# args: hostname, port, user, password, raise_error(die_on_error)_or_not
$new_master_handler->connect( $new_master_ip, $new_master_port,
$new_master_user, $new_master_password, 1 );
print current_time_us() . " Set read_only on the new master.. ";
$new_master_handler->enable_read_only();
if ( $new_master_handler->is_read_only() ) {
print "ok.\n";
}
else {
die "Failed!\n";
}
$new_master_handler->disconnect();
# Connecting to the orig master, die if any database error happens
my $orig_master_handler = new MHA::DBHelper();
$orig_master_handler->connect( $orig_master_ip, $orig_master_port,
$orig_master_user, $orig_master_password, 1 );
## Drop application user so that nobody can connect. Disabling per-session binlog beforehand
#$orig_master_handler->disable_log_bin_local();
#print current_time_us() . " Drpping app user on the orig master..\n";
#FIXME_xxx_drop_app_user($orig_master_handler);
## Waiting for N * 100 milliseconds so that current connections can exit
my $time_until_read_only = 15;
$_tstart = [gettimeofday];
my @threads = get_threads_util( $orig_master_handler->{dbh},
$orig_master_handler->{connection_id} );
while ( $time_until_read_only > 0 && $#threads >= 0 ) {
if ( $time_until_read_only % 5 == 0 ) {
printf
"%s Waiting all running %d threads are disconnected.. (max %d milliseconds)\n",
current_time_us(), $#threads + 1, $time_until_read_only * 100;
if ( $#threads < 5 ) {
print Data::Dumper->new( [$_] )->Indent(0)->Terse(1)->Dump . "\n"
foreach (@threads);
}
}
sleep_until();
$_tstart = [gettimeofday];
$time_until_read_only--;
@threads = get_threads_util( $orig_master_handler->{dbh},
$orig_master_handler->{connection_id} );
}
## Setting read_only=1 on the current master so that nobody(except SUPER) can write
print current_time_us() . " Set read_only=1 on the orig master.. ";
$orig_master_handler->enable_read_only();
if ( $orig_master_handler->is_read_only() ) {
print "ok.\n";
}
else {
die "Failed!\n";
}
## Waiting for M * 100 milliseconds so that current update queries can complete
my $time_until_kill_threads = 5;
@threads = get_threads_util( $orig_master_handler->{dbh},
$orig_master_handler->{connection_id} );
while ( $time_until_kill_threads > 0 && $#threads >= 0 ) {
if ( $time_until_kill_threads % 5 == 0 ) {
printf
"%s Waiting all running %d queries are disconnected.. (max %d milliseconds)\n",
current_time_us(), $#threads + 1, $time_until_kill_threads * 100;
if ( $#threads < 5 ) {
print Data::Dumper->new( [$_] )->Indent(0)->Terse(1)->Dump . "\n"
foreach (@threads);
}
}
sleep_until();
$_tstart = [gettimeofday];
$time_until_kill_threads--;
@threads = get_threads_util( $orig_master_handler->{dbh},
$orig_master_handler->{connection_id} );
}
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
## Terminating all threads
print current_time_us() . " Killing all application threads..\n";
$orig_master_handler->kill_threads(@threads) if ( $#threads >= 0 );
print current_time_us() . " done.\n";
#$orig_master_handler->enable_log_bin_local();
$orig_master_handler->disconnect();
## After finishing the script, MHA executes FLUSH TABLES WITH READ LOCK
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
## Activating master ip on the new master
# 1. Create app user with write privileges
# 2. Moving backup script if needed
# 3. Register new master's ip to the catalog database
# We don't return error even though activating updatable accounts/ip failed so that we don't interrupt slaves' recovery.
# If exit code is 0 or 10, MHA does not abort
my $exit_code = 10;
eval {
my $new_master_handler = new MHA::DBHelper();
# args: hostname, port, user, password, raise_error_or_not
$new_master_handler->connect( $new_master_ip, $new_master_port,
$new_master_user, $new_master_password, 1 );
## Set read_only=0 on the new master
#$new_master_handler->disable_log_bin_local();
print current_time_us() . " Set read_only=0 on the new master.\n";
$new_master_handler->disable_read_only();
## Creating an app user on the new master
#print current_time_us() . " Creating app user on the new master..\n";
#FIXME_xxx_create_app_user($new_master_handler);
#$new_master_handler->enable_log_bin_local();
$new_master_handler->disconnect();
## Update master ip on the catalog database, etc
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
# do nothing
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 {
print
"Usage: master_ip_online_change --command=start|stop|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";
die;
}
参考文档:https://www.cnblogs.com/xiaoboluo768/p/5135584.html
http://www.cnblogs.com/liang545621/p/7517929.html
https://www.cnblogs.com/xiaoboluo768/p/5984530.html
http://www.cnblogs.com/gomysql/p/3675429.html
https://www.cnblogs.com/yuanermen/p/3735263.html
https://www.cnblogs.com/xuanzhi201111/p/4231412.html