MySQL高可用架构之 MHA 一主一从

环境:

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

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值