IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    MHA 自定义脚本 更新:当KEEPALIVE不能跨网段的时候,怎么办?

    Adamhuan发表于 2017-03-06 16:39:03
    love 0

    有时候,可能出现这样的情况:
    1. MySQL复制的主从机器位于不同的网段

    这种情况下,如果使用Keepalive做VIP资源,则可能出现主从两边VIP都启动的情况,正确的情况下VIP应该只能在其中一端活跃。

    这种情况下,就可以通过自定义脚本去解决该场景下的问题。

    这一次的代码更新,也发布到了Github上:
    https://github.com/adamhuan/linux-script/tree/master/MySQL/MySQL%20MasterHA_%E5%A2%9E%E5%BC%BA

    以下是我对之前自己写的 针对MHA架构的 自定义脚本变更后的样子:
    文件:do_mha.sh

    #!/bin/bash
    
    # Script Name: MySQL_MHA_Enhance_shell.sh
    # About: auto register in MySQL Replication
    # Script Type: Bash Shell
    # OS: RHEL6 / CentOS6
    # Architecture: MySQL MasterHA
    
    # Auther: adamhuan
    # Blog: d-prototype.com
    
    # --------------------------
    # variable and file path
    
    # Part:: this script
    str_mha_application=$1
    
    # Part:: Linux
    # Account info
    str_linux_username="root"       #不同的环境,一定要注意的参数
    
    # Part:: MySQL
    # Account info
    str_mysql_username="root"       #不同的环境,一定要注意的参数
    str_mysql_password=Abcd1@34     #不同的环境,一定要注意的参数
    
    str_repl_username="replme"      #不同的环境,一定要注意的参数
    str_repl_password=Or@cle123     #不同的环境,一定要注意的参数
    
    # Part:: MHA
    # pid
    #str_pid_masterha_manager=`ps -ef | grep masterha_manager | grep perl | awk '{print $2}'`
    
    str_pid_masterha_manager=`ps -ef | grep masterha_manager | grep "$str_mha_application" | grep perl | awk '{print $2}'`
    
    # file
    file_conf_mha_global="/etc/masterha_default.cnf"
    
    path_conf_mha_application="/etc"    #不同的环境,一定要注意的参数
    
    #file_conf_mha_application="/etc/masterha_application_1.cnf"
    file_conf_mha_application="$path_conf_mha_application/$str_mha_application.cnf"   #不同的环境,一定要注意的参数
    
    # file: relation / by computed
    file_log_mha_manager=`cat $file_conf_mha_application | grep --color manager_log | cut -d'=' -f2`
    
    # variable: ip info
    # 如果MHA中MySQL主库的候选服务器数量超过了两台,也许下面这个list参数,就会排上用场
    list_ip_candicate=`cat $file_conf_mha_application | grep -B 2 "^candidate" | grep "hostname" | cut -d'=' -f2`
    
    str_ip_orig_master=`cat $file_log_mha_manager | grep --color "MySQL Master failover" | cut -d'(' -f2 | cut -d':' -f1 | tail -n 1`
    str_ip_new_master=`cat $file_log_mha_manager | grep --color "MySQL Master failover" | cut -d'(' -f3 | cut -d':' -f1 | tail -n 1`
    
    str_ip_mha_manager="10.158.1.94"    #不同的环境,一定要注意的参数
    str_mysql_port="3306"               #不同的环境,一定要注意的参数
    
    path_file_mha_application_log_dir="/script/log"     #不同的环境,一定要注意的参数
    path_file_mha_application_log_file="$path_file_mha_application_log_dir/$str_mha_application.log"
    
    # 为[change master]准备的参数
    str_log_file_new_master=""
    str_log_pos_new_master=""
    
    # Part:: String SQL
    str_sql_mysql_change_master=""
    
    # --------------------------
    # function
    
    function do_sql() {
      # variable
      func_str_ip="$1"
      func_str_sql="$2"
    
      # action
      # 本场景中不涉及到对MySQL某个库的操作,所以没有选择[db]
      # mysql -u $user -p"$password" $db -N -e "$f_sql_str"
      mysql -u $str_mysql_username -h $func_str_ip -p"$str_mysql_password" -P$str_mysql_port -N -e "$func_str_sql"
    }
    
    # 获取主库状态信息
    #function get_info_mysql_master_new_master() {
      # version ONE
      #str_log_file_new_master=`do_sql "$str_ip_new_master" "show master status" | awk '{print $1}'`
      #str_log_pos_new_master=`do_sql "$str_ip_new_master" "show master status" | awk '{print $2}'`
    
    #}
    
    # 生成orig_master作为slave加入new_master的[change master]SQL命令
    function gen_sql_mysql_change_master() {
      #if [[ "$str_log_file_new_master" == "" || $str_log_pos_new_master == "" ]]
      #then
      #  get_info_mysql_master_new_master
      #fi
      #str_sql_mysql_change_master="CHANGE MASTER TO MASTER_HOST='$str_ip_new_master',MASTER_USER='$str_repl_username',MASTER_PASSWORD='$str_repl_password',MASTER_LOG_FILE='$str_log_file_new_master',MASTER_LOG_POS=$str_log_pos_new_master;"
    
      # version TWO
      func_temp_master_host_sed=`cat $file_log_mha_manager | grep --color "All other slaves should start" | tail -n 1 | cut -d',' -f1 | cut -d'=' -f2 | cut -d\' -f2`
      func_temp_repl_password_sed=`cat $file_log_mha_manager | grep --color "All other slaves should start" | tail -n 1 | rev | cut -d\' -f2`
    
      func_temp_master_binlog_file=`cat $file_log_mha_manager | grep --color "All other slaves should start" | tail -n 1 | cut -d',' -f3 | cut -d'=' -f2 | cut -d\' -f2`
      func_temp_master_binlog_pos=`cat $file_log_mha_manager | grep --color "All other slaves should start" | tail -n 1 | cut -d',' -f4 | cut -d'=' -f2 | cut -d\' -f2`
    
      echo "======================"
      echo "@@ func variable: func_temp_master_host_sed = $func_temp_master_host_sed"
      echo "@@ func variable: func_temp_repl_password_sed = $func_temp_repl_password_sed"
    
      echo "@@ func variable: func_temp_master_binlog_file = $func_temp_master_binlog_file"
      echo "@@ func variable: func_temp_master_binlog_pos = $func_temp_master_binlog_pos"
      echo "======================"
    
      str_log_file_new_master=$func_temp_master_binlog_file
      str_log_pos_new_master=$func_temp_master_binlog_pos
    
      str_sql_mysql_change_master=`cat $file_log_mha_manager | grep --color "All other slaves should start" | tail -n 1 | sed "s/'$func_temp_repl_password_sed'/'$str_repl_password'/g" | cut -d':' -f4`
      str_sql_mysql_change_master=`echo $str_sql_mysql_change_master | sed "s/'$func_temp_master_host_sed'/'$str_ip_new_master'/g"`
    }
    
    # 对指定主机执行Linux命令
    # 前提:
    # 1. IP可达
    # 2. SSH等价关系
    function do_linux_by_ssh() {
      # variable
      func_str_ip="$1"
      func_str_user="$2"
      func_str_command="$3"
    
      # action
      ssh -t $func_str_user@$func_str_ip "$func_str_command"
    }
    
    # 处理VIP的事宜
    function do_part_vip() {
      do_linux_by_ssh "$str_ip_new_master" "root" "service keepalived start"
      do_linux_by_ssh "$str_ip_orig_master" "root" "service keepalived stop"
    }
    
    function do_part_orig_master_is_new_slave() {
      do_linux_by_ssh "$str_ip_orig_master" "root" "service mysql start"
      do_sql "$str_ip_orig_master" "set global read_only=1;"
      do_sql "$str_ip_orig_master" "$str_sql_mysql_change_master"
      do_sql "$str_ip_orig_master" "start slave;"
    }
    
    function do_part_mha_master_manager_start() {
      echo "func: do_part_mha_master_manager_start --->"
      echo "Special log file is: $path_file_mha_application_log_file"
      do_linux_by_ssh "$str_ip_mha_manager" "root" "nohup masterha_manager --conf=$file_conf_mha_application --ignore_last_failover < /dev/null > $path_file_mha_application_log_file 2>&1 &"
    }
    
    function check_repl() {
      # variable
      func_str_block_status=""
    
      # version 1
      #func_str_block_status=`masterha_check_repl --conf=$file_conf_mha_application`
    
      # version 2
      #masterha_check_repl --conf=$file_conf_mha_application > $func_str_block_status
    
      # version 3
      func_str_block_status=$(masterha_check_repl --conf=$file_conf_mha_application)
    
      repl_status=`echo "$func_str_block_status" | grep --color "(current master)"`
    
      echo "------------------"
      echo "fun: check_repl"
      echo ""
      echo "$func_str_block_status"
      echo ""
    }
    
    # 如果PID不存在,则执行该脚本,否则,退出
    function runable_by_mha_manager_pid() {
      echo "-----------------"
      echo "Script for MySQL Master HA"
      echo "-----------------"
      echo "Begin:: "`date "+|%Y-%m-%d|%H:%M:%S|"`
    
      #echo "========================"
      #echo "current MySQL REPL is::"
      #check_repl
      #echo "========================"
    
      if [[ "$str_pid_masterha_manager" == "" ]]
      then
        echo "## masterha_manager is [NOT ALIVED]."
      else
        echo "## masterha_manager is [ALIVED]."
        echo "[masterha_manager] PID is:: $str_pid_masterha_manager"
    
        # do something.
        echo "## Exit Script"
        exit 0
      fi
    }
    
    # --------------------------
    # action
    
    # 如果PID不存在,则执行该脚本,否则,退出
    echo "------------------"
    echo "app: runable_by_mha_manager_pid"
    runable_by_mha_manager_pid
    echo ""
    
    echo "------------------"
    echo "app: gen_sql_mysql_change_master"
    gen_sql_mysql_change_master
    echo ""
    #echo "------------------"
    #echo "app: do_part_vip"
    #do_part_vip
    #echo ""
    
    echo "------------------"
    echo "app: do_part_orig_master_is_new_slave"
    do_part_orig_master_is_new_slave
    echo ""
    
    echo "------------------"
    echo "app: do_part_mha_master_manager_start"
    #do_part_mha_master_manager_start
    # version 1
    #nohup masterha_manager --conf=$file_conf_mha_application --ignore_last_failover &
    
    # version 2
    echo "Special log file is: $path_file_mha_application_log_file"
    nohup masterha_manager --conf=$file_conf_mha_application --ignore_last_failover < /dev/null >> $path_file_mha_application_log_file 2>&1 &
    
    echo ""
    
    # --------------------------
    # Show time
    
    # ---------
    # version one
    # ---------
    #echo "new master is:: $str_ip_new_master"
    #echo "Master log file is:: $str_log_file_new_master"
    #echo "Master log POS is:: $str_log_pos_new_master"
    #echo "orig master --> new master ## SQL: CHANGE MASTER ## is:: $str_sql_mysql_change_master"
    
    # ---------
    # version two
    # ---------
    echo "================="
    echo "MySQL info:"
    
    echo "## Account and Password"
    echo "username @ $str_mysql_username"
    echo "password @ $str_mysql_password"
    echo ""
    echo "--- for REPLICATION ---"
    echo "repl @ username ## $str_repl_username"
    echo "repl @ password ## $str_repl_password"
    echo ""
    echo "## Master Server info"
    
    #version 1
    #echo "log file @ Master ## $str_log_file_new_master"
    #echo "log pos  @ Master ## $str_log_pos_new_master"
    
    #version 2
    echo "log file @ Master ## $str_log_file_new_master"
    echo "log pos  @ Master ## $str_log_pos_new_master"
    
    echo ""
    
    echo "================="
    echo "SQL statement:"
    echo "[CHANGE MASTER] -->"
    echo "$str_sql_mysql_change_master"
    echo ""
    
    echo "================="
    echo "MasterHA info:"
    
    echo "## File and Path"
    echo "MHA Global config file @ $file_conf_mha_global"
    echo "MHA Application config file @ $file_conf_mha_application"
    echo "MHA Log file:: masterha_manager @ $file_log_mha_manager"
    echo ""
    echo "## Architecture"
    echo "Candicate Server list::"
    echo "$list_ip_candicate"
    echo ""
    echo "## IP"
    echo "MHA Manager Server:: $str_ip_mha_manager"
    echo "Last:: new master:: $str_ip_new_master"
    echo "Last:: orig master:: $str_ip_orig_master"
    echo ""
    
    # --------------------------
    echo "-----------------"
    echo "Finished:: "`date "+|%Y-%m-%d|%H:%M:%S|"`
    # Done

    文件:call_do_mha.sh
    该脚本没有变动,和之前一样。

    文件:master_ip_online_change
    该脚本之前依赖KEEPALIVE,在当前的版本中,已经改为依赖专门处理VIP资源的启停脚本了。

    #!/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_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 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,
            "root", "Abcd1\@34", 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} );
          }
    
          ## 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,
            "root", "Abcd1\@34", 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
          # version 1
          #`/usr/bin/ssh -t root\@${orig_master_ip} "service keepalived stop"`;
          #`/usr/bin/ssh -t root\@${new_master_ip} "service keepalived start"`;
    
          # version 2
          `/usr/bin/ssh -t root\@${orig_master_ip} "/script/shell/do_vip_crontab.sh 1 0"`;
          `/usr/bin/ssh -t root\@${new_master_ip} "/script/shell/do_vip_crontab.sh 0 1"`;
    
          $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;
      }
    }
    
    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;
    }

    文件:master_ip_failover

    #!/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;
    
    my (
      $command,        $ssh_user,         $orig_master_host,
      $orig_master_ip, $orig_master_port, $new_master_host,
      $new_master_ip,  $new_master_port,  $new_master_user,
      $new_master_password
    );
    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,
      'new_master_user=s'     => \$new_master_user,
      'new_master_password=s' => \$new_master_password,
    );
    
    exit &main();
    
    sub main {
      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 {
    
          # updating global catalog, etc
          $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 {
          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,
            "mhame", "Or\@cle123", 1 );
    
          ## Set read_only=0 on the new master
          $new_master_handler->disable_log_bin_local();
          print "Set read_only=0 on the new master.\n";
          $new_master_handler->disable_read_only();
    
          ## Creating an app user on the new master
          print "Creating app user on the new master..\n";
          #FIXME_xxx_create_user( $new_master_handler->{dbh} );
          $new_master_handler->enable_log_bin_local();
          $new_master_handler->disconnect();
    
          ## Update master ip on the catalog database, etc
          #FIXME_xxx;
    
          `echo "script begin running..." > /work_dir/mha_manager/test_me/master_ip_failover_run_shell`;
    
          # version 1
          #`/usr/bin/ssh -t root\@${orig_master_ip} "service keepalived stop" > /work_dir/mha_manager/test_me/orig_master.log`;
          #`/usr/bin/ssh -t root\@${new_master_ip} "service keepalived start" > /work_dir/mha_manager/test_me/new_master.log`;
    
          #version 2
          `/usr/bin/ssh -t root\@${orig_master_ip} "/script/shell/do_vip_crontab.sh 1 0" > /work_dir/mha_manager/test_me/orig_master.log`;
          `/usr/bin/ssh -t root\@${new_master_ip} "/script/shell/do_vip_crontab.sh 0 1" > /work_dir/mha_manager/test_me/new_master.log`;
    
          `sh /script/shell/do_mha.sh > /work_dir/mha_manager/test_me/do_mha.log`;
    
          $exit_code = 0;
        };
        if ($@) {
          warn $@;
    
          # If you want to continue failover, exit 10.
          exit $exit_code;
        }
        exit $exit_code;
      }
      elsif ( $command eq "status" ) {
    
        # do nothing
        exit 0;
      }
      else {
        &usage();
        exit 1;
      }
    }
    
    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";
    }

    文件:do_vip_and_cron.sh
    用来处理VIP资源,以及只希望在【从主】节点上执行计划任务的诉求。

    # file: do_vip_and_crontab.sh
    
    # 职能:
    # --> 1. 启动或停止:虚拟IP
    # --> 2. 启用或禁用:crontab策略
    
    # variable
    
    # ---> 信号量
    # 对于所有信号而言:
    # 0,启用
    # 1,禁用
    
    #是否启用:VIP
    #sign_vip=0
    sign_vip="$1"
    
    # 是否启用:crontab
    #sign_crontab=0
    sign_crontab="$2"
    
    # 对于VIP而言
    str_vip="10.158.1.111"
    str_mask="255.255.255.0"
    str_nic_name="eth0:0"
    
    # 对于CRONTAB而言
    
    # for RHEL6
    # 如果是root用户,就会在:/var/spool/cron/root
    file_crontab_dir="/var/spool/cron"
    file_crontab_conf="$file_crontab_dir/root"
    
    str_crontab_command="data +%Y-%m-%d"
    str_crontab_date="10 11 * * *"
    
    str_crontab_date_sed=`echo "$str_crontab_date" | sed 's/*/\\\*/g'`
    
    str_crontab_full="$str_crontab_date $str_crontab_command"
    str_crontab_full_sed="$str_crontab_date_sed $str_crontab_command"
    
    str_block_crontab_content=`cat $file_crontab_conf | grep -v '#'`
    
    # disable
    
    echo "Crontab content:"
    echo "$str_block_crontab_content"
    echo ""
    
    echo "var: str_crontab_full --> $str_crontab_full"
    echo "var: str_crontab_date_sed --> $str_crontab_date_sed"
    echo "var: str_crontab_full_sed --> $str_crontab_full_sed"
    echo ""
    
    # running
    
    if [ $sign_vip -eq "0" ]
    then
      echo "------------"
      echo "VIP:: enable."
      ifconfig $str_nic_name $str_vip netmask $str_mask up
      echo ""
    else
      echo "------------"
      echo "VIP:: disable."
      ifconfig $str_nic_name $str_vip netmask $str_mask down
      echo ""
    fi
    
    if [ $sign_crontab -eq "0" ]
    then
      echo "------------"
      echo "CRONTAB:: enable."
    
      if [[ $str_block_crontab_content =~ "$str_crontab_full" ]]
      then
        echo "CRONTAB Policy is in [$file_crontab_conf]"
    
      else
        echo "CRONTAB Policy is not in [$file_crontab_conf]"
        echo "Put it in, ..."
        echo "$str_crontab_full" >> $file_crontab_conf
        echo "Done."
      fi
    
      echo ""
    else
      echo "------------"
      echo "CRONTAB:: disable."
    
      if [[ $str_block_crontab_content =~ "$str_crontab_full" ]]
      then
        echo "CRONTAB Policy is in [$file_crontab_conf]"
        echo "change it, ..."
        sed -i "s/$str_crontab_full_sed/#$str_crontab_full_sed/g" $file_crontab_conf
        echo "Done."
    
      else
        echo "CRONTAB Policy is not in [$file_crontab_conf]"
    
      fi
    
      echo ""
    fi
    
    # Finished

    启动方式还是和之前一样,但是VIP的资源部分已经完全不一样了。
    上述脚本的参数可以根据自己的环境的不同做出相应的修改。

    ——————————————————————————
    Done。



沪ICP备19023445号-2号
友情链接