當前位置:網站首頁>lnmp 九之mysql數據庫MHA高可用

lnmp 九之mysql數據庫MHA高可用

2022-01-27 14:59:23 L*YUEYUE

MHA集群

MHA簡介

傳統的主從複制如果主庫宕機,其餘從庫不會自動的代替主庫繼續工作,這樣就不能保證業務的高可用,而MHA就是一個mysql主從複制高可用的解决方案,當主庫宕機後,MHA能在1-30秒實現故障檢測和故障自動轉移,選擇一個最優的從庫作為主庫,同時新的主庫還繼續與其他從庫保持數據一致的狀態。
在這裏插入圖片描述

MHA與MGR

MHA是外部的基於mysql主從半同步開發的一套高可用切換方案,它並不屬於mysql內核,獨立於mysql存在於外圍,MHA重點在切換,可以理解為一套切換工具。而MGR存在於mysql內核層面,是內核層面數據强一致方案,它的重點在高可用强一致,如果將MGR用在生產環境中,那麼針對MGR,還需要開發一套監控及切換方案,而MHA將這一整套切換方案vip之類的都考慮進去了。

MHA組成

MHA 服務有兩種角色, MHA Manager(管理節點)和 MHA Node(數據節點)。

  • MHA Manager:通常單獨部署在一臺獨立機器上管理多個 master/slave 集群(組),每個 master/slave 集群稱作一個 application,用來管理統籌整個集群。
  • MHA Node:運行在每臺 MySQL 服務器上(master/slave/manager),它通過監控具備解析和清理logs功能的脚本來加快故障轉移。

MHA Manager服務器會定時通過主庫上的MHA Node檢測主庫的運行狀態,當主庫出現故障時他可以將最優從庫(可以提前指定或者由MHA判定)提昇為新的主庫,然後其他從庫和新的主庫重新保持新的複制狀態。

MHA工作原理

  • 主庫實例掛掉但是ssh還能連接
    (1)監控到主庫宕機,選擇一個新主,被選擇的新主會取消從庫的角色( reset slave)
    選擇標准:
    一是根據其他從庫的binlog日志的比特置選擇最新的從庫作為新的主庫
    二是如果設置了半同步從庫,直接選擇半同步從庫作為新的主庫
    (2)從庫通過MHA自帶的脚本程序,通過ssh向主庫索取缺失部分的binlog
    (3)其他從庫與新的主庫重新構建主從,繼續提供服務
    (4)如果由vip機制,將vip從原來的主庫漂移到新的主庫,讓應用無感知
  • 主節點服務器宕機(ssh已經連接不上了)
    (1)監控到主機宕機後,嘗試ssh連接,連接失敗
    (2)通過上邊所講的選擇標准選擇新的主庫
    (3)計算從庫之間的relay-log的差异,補償到新的其他從庫
    (4)其他從庫重新與新主構建主從關系,繼續提供服務
    (5)如果由VIP機制,將VIP從原主漂移到新主,讓應用無感知
    (6)如果有binlog server機制,會繼續將binlog server中缺失的事物,補償到新的主庫

MHA實現

四臺虛擬機,三臺做node(一主二從),一臺做manager。
server1:主
server2、server3:從
server4:manager

MHA工具包介紹
Manager工具包主要包括以下幾個工具:
	masterha_check_ssh           #檢查MHA的SSH配置狀况
    masterha_check_repl          #檢查MySQL複制狀况 
    masterha_manger              #啟動MHA
    masterha_check_status        #檢測當前MHA運行狀態
    masterha_master_monitor      #檢測master是否宕機
    masterha_master_switch       #控制故障轉移(自動或者手動)
    masterha_conf_host           #添加或删除配置的server信息

Node工具包(由MHA Manager的脚本觸發,無需人為操作)主要包括以下幾個工具:
	save_binary_logs             #保存和複制master的二進制日志
	apply_diff_relay_logs        #識別差异的中繼日志事件並將其差异的事件應用於其他的slave
	filter_mysqlbinlog           #去除不必要的ROLLBACK事件(MHA已不再使用這個工具)
	purge_relay_logs             #清除中繼日志(不會阻塞SQL線程)

主(server1)的配置

/etc/init.d/mysqld stop
rm -fr /data/mysql/*
vim /etc/my.cnf
[mysqld]
 basedir=/usr/local/mysql
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock

 server-id=1                    #實現功能的重要參數
 default_authentication_plugin=mysql_native_password
 gtid_mode=ON
 enforce-gtid-consistency=ON
 master_info_repository=TABLE
 relay_log_info_repository=TABLE  
 log_slave_updates=ON
 log_bin=binlog                 #實現功能的重要參數
 binlog_format=ROW 

mysqld --initialize --user=mysql
/etc/init.d/mysqld start 
mysql -p
mysql> alter user [email protected] identified by '123456';
mysql> CREATE USER [email protected]'%' IDENTIFIED BY '123456';  #在mysql8中grant語句要分為兩句
mysql> GRANT REPLICATION SLAVE ON *.* TO [email protected]'%';   #在mysql8中grant語句要分為兩句
mysql> show master status; 

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

node從(server2、3)的設置

和server1配置類似,這裏以server2為例子

/etc/init.d/mysqld stop
rm -fr /data/mysql/*
vim /etc/my.cnf
[mysqld]
 basedir=/usr/local/mysql
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock

 server-id=2                    #實現功能的重要參數
 default_authentication_plugin=mysql_native_password
 gtid_mode=ON
 enforce-gtid-consistency=ON
 master_info_repository=TABLE
 relay_log_info_repository=TABLE  
 log_slave_updates=ON
 log_bin=binlog                 #實現功能的重要參數
 binlog_format=ROW 

mysqld --initialize --user=mysql
/etc/init.d/mysqld start 
mysql -p
mysql> alter user [email protected] identified by '123456';
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

以同樣的方式配置server3

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
開始配置server3
在這裏插入圖片描述

MHA Manager(server4)部署

centos軟件包下載官網
rpm軟件包下載官網

1.首先停止server4之前安裝的mysql路由服務
systemctl stop mysqlrouter.service

2.配置4個節點間的免密
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:

3.在server4上下載軟件並將node包發送給其他節點(如果在線下載的話如下,其實我這裏離線包都全部准備好了)
wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server1:
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server2:
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server3:

4.server1、2、3安裝node rpm包
yum install -y mha4mysql-node-0.58-0.el7.centos.noarch.rpm

5.server4安裝軟件包及依賴
cd MHA-7
ls
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-manager-0.58.tar.gz
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Net-Telnet-3.03-19.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm
yum install -y *.rpm

注意:需要有這個repo文件
vim CentOS-Base.repo
[base]
name=CentOS-7 - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#released updates 
[updates]
name=CentOS-7 - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-7 - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-7 - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#contrib - packages by Centos Users
[contrib]
name=CentOS-7 - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

6.解壓MHA並新建目錄(如果在線下載的話如下,其實我這裏離線包都全部准備好了)
wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
tar zxf mha4mysql-manager-0.58.tar.gz
cd mha4mysql-manager-0.58
mkdir /etc/masterha 
cd samples/conf
cp app1.cnf /etc/masterha

7.修改配置文件
cd /etc/masterha
vim app1.cnf 
[server default]
user=root
password=123456
ssh_user=root
master_binlog_dir= /data/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 192.168.1.10 -s 192.168.1.11
ping_interval=3
# master_ip_failover_script= /script/masterha/master_ip_failover
# shutdown_script= /script/masterha/power_manager
# report_script= /script/masterha/send_report
# master_ip_online_change_script= /script/masterha/master_ip_online_change

manager_workdir=/etc/masterha/app1
manager_log=/var/log/masterha/app1/manager.log

repl_user=repl
repl_password=123456

[server1]
hostname=192.168.1.10

[server2]
hostname=192.168.1.11
candidate_master=1
check_repl_delay=0

[server3]
hostname=192.168.1.12

8.創建工作目錄
mkdir app1      

9.測試SSH連接
masterha_check_ssh --conf=/etc/masterha/app1.cnf

10.在server1上創建root用戶並授權
CREATE USER [email protected]'%' IDENTIFIED BY '123456';
GRANT ALL ON *.* TO [email protected]'%';
flush privileges;

11.測試主從複制情况
masterha_check_repl --conf=/etc/masterha/app1.cnf

配置免密,server2和server3類似
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在server4上安裝
在這裏插入圖片描述
在這裏插入圖片描述
解壓tar包並修改配置文件
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
測試ssh連接發現正常
在這裏插入圖片描述
在server1上創建用戶並授權
在這裏插入圖片描述
檢測主從複制情况
在這裏插入圖片描述
在這裏插入圖片描述
MHA部署成功
在這裏插入圖片描述

MHA高可用切換

MHA的故障切換過程,共包括以下的步驟:
1.配置文件檢查階段,這個階段會檢查整個集群配置文件配置
2.宕機的master處理,這個階段包括虛擬ip摘除操作,主機關機操作
3.複制dead maste和最新slave相差的relay log,並保存到MHA Manger具體的目錄下
4.識別含有最新更新的slave
5.應用從master保存的二進制日志事件(binlog events)
6.提昇一個slave為新的master進行複制
7.使其他的slave連接新的master進行複制

MHA手動切換

具體實驗步驟如下:

1.第一種:master存活狀態下切換
在server4上執行
masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=192.168.1.11 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
詢問一路yes即可

2.第二種:master宕機狀態下切換
將server2 mysql服務關閉
/etc/init.d/mysqld stop

在server4上執行下列語句
masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=192.168.1.11 --dead_master_port=3306 --new_master_host=192.168.1.10 --new_master_port=3306 --ignore_last_failover
# --ignore_last_failover 忽略最後一次的切換文件(在/etc/masterha/app目錄下)
詢問一路yes即可

將server2 mysql服務啟動並加入服務
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

第一種方式
在這裏插入圖片描述
切換成功
在這裏插入圖片描述
第二種方式
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
將server2重新加入服務
在這裏插入圖片描述
在這裏插入圖片描述

MHA自動切換

為了保證數據完全一致性,在最快的時間內完成切換,MHA的在線切換必須滿足以下條件才會切換成功,否則會切換失敗。
1.所有slave的IO線程都在運行
2.所有slave的SQL線程都在運行
3.所有的show slave status的輸出中Seconds_Behind_Master參數小於或者等於running_updates_limit秒,如果在切換過程中不指定running_updates_limit,那麼默認情况下running_updates_limit為1秒。
4.在master端,通過show processlist輸出,沒有一個更新花費的時間大於running_updates_limit秒。

具體實驗步驟如下:

1.將進程打入後臺執行
mkdir -p /var/log/masterha/app1     #還需要新建日志目錄(前面忘記了)
masterha_manager --conf=/etc/masterha/app1.cnf & 

2.關閉當前server1上master,自動切換到server2。
/etc/init.d/mysqld stop

3.將server1 mysql服務啟動並加入服務
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.11',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

在這裏插入圖片描述
在這裏插入圖片描述
在server3上發現成功切換
在這裏插入圖片描述
將server1 mysql服務啟動並加入服務
在這裏插入圖片描述
在這裏插入圖片描述

MHA的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 = '192.168.1.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens33";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens33";

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 ([email protected]) {
    
            warn "Got Error: [email protected]\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 ([email protected]) {
    
            warn [email protected];
            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 = '192.168.1.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens33";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens33";

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 ([email protected]) {
      
            warn "Got Error: [email protected]\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 ([email protected]) {
      
            warn [email protected];  
            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";  
}

具體實驗步驟如下

1.修改/etc/masterha/app1.cnf
vim /etc/masterha/app1.cnf
master_ip_failover_script= /etc/masterha/master_ip_failover       #手動切換脚本
master_ip_online_change_script= /etc/masterha/master_ip_online_change  #自動切換脚本

2.添加上述兩個配置文件
看上面兩個代碼文件
vim master_ip_failover
vim master_ip_online_change

3.給兩個配置文件加可執行權限
chmod +x master_ip_failover master_ip_online_change

4.測試
給master主機添加vip
ip addr add 192.168.1.100/24 dev ens33
ip addr show ens33

將進程打入後臺執行
masterha_manager --conf=/etc/masterha/app1.cnf &

關閉當前server2上master,在server3上查看自動切換到server1上
/etc/init.d/mysqld stop
server3上
mysql> show slave status\G;

在server1上發現vip
ip addr show ens33

5.最後將server2手動加到集群中即可
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

修改 /etc/masterha/app1.cnf
在這裏插入圖片描述
在這裏插入圖片描述
添加上述兩個配置文件
在這裏插入圖片描述
開始測試
在master上添加vip
在這裏插入圖片描述
在這裏插入圖片描述
關閉master
在這裏插入圖片描述
在server3上查看master已切換
在這裏插入圖片描述
在server1上發現vip
在這裏插入圖片描述
將server2手工加入集群
在這裏插入圖片描述

版權聲明
本文為[L*YUEYUE]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201271459228899.html

隨機推薦