天天看點

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

實驗環境:

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中插入資料,

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

在server2中檢視

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

說明半同步複制操作已經配置好。

在進行綿密登陸的配置

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)
 
 指令行:
 [[email protected] ~]# 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

           

跟server1 2 3做免密登陸

我們用到了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的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

但是在測試複制時就報錯了,因為我們最開始安裝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)
           

再次測試:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

然後我們就可以測試在server4中進行切換了。

測試切換

手動切換master結點

我們先測試手動切換 master 結點:

要注意每次切換都會生成/etc /masterha/masterha.failover.error|complete 檔案,下次切換前必須删除這個檔案才可以進行新的切換,
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

目前我們的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
           
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

可以看出重置了master結點,切換到了server2。

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

此時server4的目錄中就出現了 .complete .這個檔案,這就是切換的資料,代表切換成功,下次手動切換前需要删除這個檔案。

而且在server2中已經沒有slave的資訊,而且server3 的master已經切換:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

剛才的是離線切換,現在我們嘗試線上切換:

先開啟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
           
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

就切換成功了。

server1:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

server2:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

server3:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

這就是我們手動切換的兩種方式。

自動切換

删除 /etc/masterha/masterha.failover.complete 剛剛轉換完成産生的檔案。

自動切換的工具為: masterha_manager ,它會檢測資料庫的master結點的狀态,如果出現故障,會自動進行切換。

它隻能執行一次,因為每次執行都回生成我們上面删除的檔案,它自帶守護程序,不能kill -9 殺掉。

我們啟動:

在server4中:

nohup 靜默輸出,& 背景運作。

測試:

這時我們挂掉目前的master主機 server1 ,

systemctl stop mysqld.service 
           

這時我們發現server4 中的manager程序消失, 說明它隻執行一次

然後我們在server2 和server3 中檢視:

server2:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

server3:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

就切換成功了。

我們可以檢視日志看看發生了神什麼動作:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

還是執行了changermaster的動作,和我們手動切換執行的指令相同,隻不過自動執行。

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

并且這時manager程序自動結束了,這就是manager的自動切換.

VIP故障切換

在實際情況下,客戶的通路都有一個固定的ip ,這個ip是對外的,我們不能告訴使用者通路的位址變了,是以應做一個固定的接口,不論後端的資料庫怎樣改變,都讓客戶使用這個IP進行通路,是以我們應該設定VIP進行故障切換。

  1. 我們先将上面關閉的server1打開,在将其加入到叢集中:
mysql> change master to master_host='172.25.254.2',master_user='repl',master_password='Cc990718-+',master_auto_position=1;
mysql> start slave;
           

VIP切換腳本

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";
}
           

把他們放到配置檔案中寫的位置,并給與執行權限:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換
[[email protected] ~]# cp master_ip_* /usr/local/bin/
[[email protected] ~]# chmod +x /usr/local/bin/master_ip_*
[[email protected] ~]# 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

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換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
           

執行成功:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

并且vip已經添加到了server1上:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

且server2的ip消失:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

此時的主結點已經切換為塞server1:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

模拟故障全自動切換

我們還需要開啟 masterha_manager 程序

我們挂掉server1的msyqld服務

此時;

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換
MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

vip 又回到了server2上,而且master結點也已經切換。

server3:

MySql的叢集與高可用 -- MHA的幾種切換方式簡介配置測試切換VIP故障切換

這樣對于使用者來說隻需要一直通路100 這個vip就可以持續通路了。