mysql高可用架構MHA搭建(centos7+mysql5.7.28)

七星6609發表於2020-07-05

無論是傳統行業,還是網際網路行業,資料可用性都是至關重要的,雖然現在已經步入大資料時代,nosql比較流行,但是作為資料持久化及事務性的關係型資料庫依然是專案首選,比如mysql。

現在幾乎所有的公司專案,不說可用性必須達到5個9,至少也要要求,資料庫出現問題,不能丟失資料,能夠快速響應異常處理,下面使用mha來搭建mysql高可用叢集(基於centos7+mysql5.7):

一、MHA簡介

MHA(Master HA)是一款開源的 MySQL 的高可用程式,它為 MySQL 主從複製架構提供了 automating master failover 功能。MHA 在監控到 master 節點故障時,會提升其中擁有最新資料的 slave 節點成為新的master 節點,在此期間,MHA 會通過於其它從節點獲取額外資訊來避免一致性方面的問題。MHA 還提供了 master 節點的線上切換功能,即按需切換 master/slave 節點。MHA 能夠在30秒內實現故障切換,並能在故障切換中,最大可能的保證資料一致性。

MHA由兩部分組成:MHA Manager(管理節點)和MHA Node(資料節點)。管理節點可以單獨部署在一臺獨立的機器上來管理多個master-slave叢集,也可以部署在一臺slave節點上。資料節點執行在每臺mysql伺服器上。Manager會定期檢查master,若出現故障時,會自動將最新資料的slave提升為新的master,然後將其他的slave指向新的master。整個故障轉移程式完全透明。

目前MHA主要支援一主多從的架構。要搭建MHA,要求一個複製叢集中必須最少有三臺資料庫伺服器,一主二從,即一臺充當master,一臺充當備用master,另外一臺充當從庫。


二、搭建環境架構

1.環境配置:

  作業系統版本:CentOS7

  MySQL版本:5.7.28

  VIP(虛IP):192.168.3.140

  機器列表及功能:

IP hostname server_id 角色及功能
192.168.3.142 s142 142 Monitor Host(監控複製組)/ Master(響應寫請求)
192.168.3.143 s143 143 Candidate Master(響應讀請求)
192.168.3.144 s144 144 Slave(響應讀請求)

 

 

 

 

 

 

三、MHA搭建步驟

1.在s142、s143、s144機器上安裝mysql5.7

詳細安裝可以參照另一篇文章:centos7安裝mysql-5.7.28 在此不再詳述

s142 my.cnf配置資訊:

[mysqld]
log-bin=/usr/local/mysql/logs/mysql-bin.log
expire-logs-days=1
max-binlog-size=500M
innodb_log_file_size=256M
binlog_format=row server
-id=142 gtid_mode=on enforce_gtid_consistency=1 log_slave_updates=1

 relay_log_recovery=ON
 relay_log=/usr/local/mysql/logs/mysql-relay-bin
 relay_log_index=/usr/local/mysql/logs/mysql-relay-bin.index
 log_error=/usr/local/mysql/logs/mysql-error.log

 #### replication ####
 log_slave_updates=1
 replicate_wild_ignore_table=information_schema.%,performance_schema.%,sys.%

plugin_load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
loose_rpl_semi_sync_master_enabled=1
loose_rpl_semi_sync_slave_enabled=1
loose_rpl_semi_sync_master_timeout=5000

basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
user=mysql
default-storage-engine=InnoDB
character-set-server=utf8
lower_case_table_names = 1
explicit_defaults_for_timestamp=true
[mysqld_safe]
log-error=/usr/local/mysql/mysql-error.log
pid-file=/usr/local/mysql/mysqld.pid
[client]
socket=/usr/local/mysql/mysql.sock
[mysql]
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock

s143 my.cnf配置資訊:

[mysqld]
log-bin=/usr/local/mysql/logs/mysql-bin.log
expire-logs-days=1
max-binlog-size=500M
innodb_log_file_size=256M
binlog_format=row server
-id=143 gtid_mode=on enforce_gtid_consistency=1 log_slave_updates=1

 relay_log_recovery=ON
 relay_log=/usr/local/mysql/logs/mysql-relay-bin
 relay_log_index=/usr/local/mysql/logs/mysql-relay-bin.index
 log_error=/usr/local/mysql/logs/mysql-error.log

 #### replication ####
 log_slave_updates=1
 replicate_wild_ignore_table=information_schema.%,performance_schema.%,sys.%

 read_only=1
 relay_log_purge=0

plugin_load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
loose_rpl_semi_sync_master_enabled=1
loose_rpl_semi_sync_slave_enabled=1
loose_rpl_semi_sync_master_timeout=5000

basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
user=mysql
default-storage-engine=InnoDB
character-set-server=utf8
lower_case_table_names = 1
explicit_defaults_for_timestamp=true
[mysqld_safe]
log-error=/usr/local/mysql/mysql-error.log
pid-file=/usr/local/mysql/mysqld.pid
[client]
socket=/usr/local/mysql/mysql.sock
[mysql]
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock

s144 my.cnf 配置資訊:

[mysqld]
log-bin=/usr/local/mysql/logs/mysql-bin.log
expire-logs-days=1
max-binlog-size=500M
innodb_log_file_size=256M
binlog_format=row server
-id=144 gtid_mode=on enforce_gtid_consistency=1 log_slave_updates=1

 relay_log_recovery=ON
 relay_log=/usr/local/mysql/logs/mysql-relay-bin
 relay_log_index=/usr/local/mysql/logs/mysql-relay-bin.index
 log_error=/usr/local/mysql/logs/mysql-error.log

 #### replication ####
 log_slave_updates=1
 replicate_wild_ignore_table=information_schema.%,performance_schema.%,sys.%

 read_only=1
 relay_log_purge=0

basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
user=mysql
default-storage-engine=InnoDB
character-set-server=utf8
lower_case_table_names = 1
explicit_defaults_for_timestamp=true
[mysqld_safe]
log-error=/usr/local/mysql/mysql-error.log
pid-file=/usr/local/mysql/mysqld.pid
[client]
socket=/usr/local/mysql/mysql.sock
[mysql]
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock

2.建立複製使用者及複製配置

在主節點上配置複製使用者:

create user canal_repl_user;
grant replication slave on *.*  to canal_repl_user identified by '111111';
flush privileges;
grant all on *.* to root identified by '111111'; 

在從節點上執行主從複製命令:

CHANGE MASTER TO
MASTER_HOST='192.168.30.142',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1,
MASTER_USER='canal_repl_user',
MASTER_PASSWORD='111111';

#master_log_file='master-bin.000001',#5.6後不需要指定
#master_log_pos=189;

#啟動主從複製
START SLAVE

#檢視主從複製資訊
SHOW SLAVE STATUS

 說明主從複製成功,可以在主庫中建立一個庫,看看從庫是否同步

 3.在每臺機器上安裝yum源頭及MHA依賴的perl包

wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

  rpm -ivh epel-release-latest-7.noarch.rpm

yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager

如圖安裝成功:

 4.配置ssh免密登入

分別在s142/s143/s144機器上生成ssh祕鑰:

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa

將各自公鑰id_rsa.pub傳送到另外兩臺機器,並追加到 ~/.ssh/authorized_keys中:

s142:
mv id_rsa.pub id_rsa_142.pub
scp id_rsa_142.pub s143:~/.ssh/
scp id_rsa_142.pub s144:~/.ssh/

s143:
mv id_rsa.pub id_rsa_143.pub
scp id_rsa_143.pub s142:~/.ssh/
scp id_rsa_143.pub s144:~/.ssh/

s144:
mv id_rsa.pub id_rsa_144.pub
scp id_rsa_144.pub s142:~/.ssh/
scp id_rsa_144.pub s143:~/.ssh/
s142:
cat id_rsa_143.pub >> authorized_keys
cat id_rsa_144.pub >> authorized_keys

s143:
cat id_rsa_142.pub >> authorized_keys
cat id_rsa_144.pub >> authorized_keys

s144:
cat id_rsa_143.pub >> authorized_keys
cat id_rsa_142.pub >> authorized_keys

5.安裝MHA 

分別在s142、s143、s144上下載node安裝包並安裝:

wget https://qiniu.wsfnk.com/mha4mysql-node-0.58-0.el7.centos.noarch.rpm
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm

 

 在s142上安裝manager

wget https://qiniu.wsfnk.com/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

 

 6.配置MHA Manager

6.1配置全域性配置檔案

新建 /etc/masterha_default.cnf (一定要是這個路徑,不然後期masterha_check_ssh會提示未找到全域性檔案)

vim /etc/masterha_default.cnf

[server default]
    user=root
    password=111111
    ssh_user=root
    repl_user=canal_repl_user
    repl_password=111111
    ping_interval=1
    #master_binlog_dir=/usr/local/mysql/logs
    secondary_check_script=masterha_secondary_check -s s142 -s s143 -s s144 
    master_ip_failover_script="/opt/soft/mha/scripts/master_ip_failover"
    master_ip_online_change_script="/opt/soft/mha/scripts/master_ip_online_change"
    report_script="/opt/soft/mha/scripts/send_report"
        

6.2 配置主配置檔案

新建/opt/soft/mha/app1/app1.cnf檔案,並配置如下資訊:

[server default]
manager_workdir=/opt/soft/mha
manager_log=/opt/soft/mha/manager.log

password=111111
user=root

ping_interval=1

repl_password=111111
repl_user=canal_repl_user

#master_binlog_dir=/usr/local/mysql/logs
#secondary_check_script=masterha_secondary_check -s s142 -s s143 -s s144
#master_ip_failover_script="/opt/soft/mha/scripts/master_ip_failover"
#master_ip_online_change_script="/opt/soft/mha/scripts/master_ip_online_change"
#report_script="/opt/soft/mha/scripts/send_report"

#ssh使用者
ssh_user=root

[server1]
hostname=s142
port=3306
master_binlog_dir=/usr/local/mysql/logs
candidate_master=1
check_repl_delay=0

[server2]
hostname=s143
port=3306
master_binlog_dir=/usr/local/mysql/logs
candidate_master=1
check_repl_delay=0

[server3] 
hostname=s144
port=3306
master_binlog_dir=/usr/local/mysql/logs
ignore_fail=1
no_master=1

6.4 配置VIP切換

為了防止腦裂發生,推薦生產環境採用指令碼的方式來管理虛擬 ip,而不是使用 keepalived來完成。

vim /opt/soft/mha/scripts/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
    );

    #定義VIP變數
    my $vip = '192.168.30.140/24';
    my $key = '1';
    my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
    my $ssh_stop_vip = "/sbin/ifconfig ens33:$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 \"`;
    }
    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";
    }

6.5 配置VIP指令碼

vim /opt/soft/mha/scripts/master_ip_online_change

    #!/bin/bash
    source /root/.bash_profile

    vip=`echo '192.168.30.140/24'`  #設定VIP
    key=`echo '1'`

    command=`echo "$1" | awk -F = '{print $2}'`
    orig_master_host=`echo "$2" | awk -F = '{print $2}'`
    new_master_host=`echo "$7" | awk -F = '{print $2}'`
    orig_master_ssh_user=`echo "${12}" | awk -F = '{print $2}'`
    new_master_ssh_user=`echo "${13}" | awk -F = '{print $2}'`

    #要求服務的網路卡識別名一樣,都為ens33(這裡是)
    stop_vip=`echo "ssh root@$orig_master_host /usr/sbin/ifconfig ens33:$key down"`
    start_vip=`echo "ssh root@$new_master_host /usr/sbin/ifconfig ens33:$key $vip"`

    if [ $command = 'stop' ]
      then
        echo -e "\n\n\n****************************\n"
        echo -e "Disabled thi VIP - $vip on old master: $orig_master_host \n"
        $stop_vip
        if [ $? -eq 0 ]
          then
        echo "Disabled the VIP successfully"
          else
        echo "Disabled the VIP failed"
        fi
        echo -e "***************************\n\n\n"
      fi

    if [ $command = 'start' -o $command = 'status' ]
      then
        echo -e "\n\n\n*************************\n"
        echo -e "Enabling the VIP - $vip on new master: $new_master_host \n"
        $start_vip
        if [ $? -eq 0 ]
          then
        echo "Enabled the VIP successfully"
          else
        echo "Enabled the VIP failed"
        fi
        echo -e "***************************\n\n\n"
    fi

6.6.配置報警郵件指令碼

首先配置郵件傳送設定資訊

#mail郵件傳送程式,需要先配置好傳送這資訊
    vim /etc/mail.rc

    set from=qixing@163.com
    set smtp=smtp.163.com
    set smtp-auth-user=qixing
    #拿163郵箱來說這個不是密碼,而是授權碼
    set smtp-auth-password=qixing
    set smtp-auth=login

編寫郵件傳送指令碼:

   vim /opt/soft/mha/script/send_report


    #!/bin/bash
    source /root/.bash_profile
    # 解析變數
    orig_master_host=`echo "$1" | awk -F = '{print $2}'`
    new_master_host=`echo "$2" | awk -F = '{print $2}'`
    new_slave_hosts=`echo "$3" | awk -F = '{print $2}'`
    subject=`echo "$4" | awk -F = '{print $2}'`
    body=`echo "$5" | awk -F = '{print $2}'`
    #定義收件人地址
    email="qixing@163.com"

    tac /var/log/mha/app1/manager.log | sed -n 2p | grep 'successfully' > /dev/null
    if [ $? -eq 0 ]
        then
        messages=`echo -e "MHA $subject 主從切換成功\n master:$orig_master_host --> $new_master_host \n $body \n 當前從庫:$new_slave_hosts"` 
        echo "$messages" | mail -s "Mysql 例項宕掉,MHA $subject 切換成功" $email >>/tmp/mailx.log 2>&1 
        else
        messages=`echo -e "MHA $subject 主從切換失敗\n master:$orig_master_host --> $new_master_host \n $body" `
        echo "$messages" | mail -s ""Mysql 例項宕掉,MHA $subject 切換失敗"" $email >>/tmp/mailx.log 2>&1  
    fi

6.7 將指令碼賦予可執行許可權

    chmod +x /opt/soft/mha/scripts/master_ip_failover 
    chmod +x /opt/soft/mha/scripts/master_ip_online_change 
    chmod +x /opt/soft/mha/scripts/send_report

7.驗證MHA配置資訊是否正常

7.1 檢查ssh配置:

masterha_check_ssh --conf=/opt/soft/mha/app1/app1.cnf

成功!!!

7.2 檢查主從複製情況:

masterha_check_repl --conf=/opt/soft/mha/app1/app1.cnf

  健康!!!

8.在master節點上繫結VIP,只需繫結一次,後續會隨主備切換而自動切換

ifconfig ens33:1 192.168.30.140/24

如過遇到問題,需手動刪除,可執行如下命令:

ifconfig ens33:1 del 192.168.30.140

ifconfig ens33:1 down #關閉vip

可以檢視繫結VIP是否成功:

ip addr

 說明繫結成功!

9.在MHA的manager節點上啟動MHA管理程式

nohup masterha_manager --conf=/opt/soft/mha/app1/app1.cnf --ignore_last_failover /opt/soft/mha/app1/manager.log 2>&1 &

命令引數:
--remove_dead_master_conf 該引數代表當發生主從切換後,老的主庫的ip將會從配置檔案中移除。 --manger_log 日誌存放位置 --ignore_last_failover 在預設情況下,如果MHA檢測到連續發生當機,且兩次當機間隔不足8小時的話,則不會進行Failover,之所以這樣限制是為了避免ping-pong效應。該引數代表忽略上次MHA觸發切換產生的檔案,預設情況下,MHA發生切換後會在日誌目錄,也就是上面設定的manager_workdir目錄中產生app1.failover.complete檔案,下次再次切換的時候如果發現該目錄下存在該檔案將不允許觸發切換,除非在第一次切換後收到刪除該檔案,為了方便,這裡設定為--ignore_last_failover。

觀察manager.log日誌,檢視是否有成功,一般最後列印如下日誌,說明成功:

Thu Jul  2 15:00:05 2020 - [info] Ping(SELECT) succeeded, waiting until MySQL doesn't respond..

10.檢視MHA狀態

masterha_check_status --conf=/opt/soft/mha/app1/app1.cnf 

 說明MHA正在執行中,主節點是s142

11.停止MHA管理程式

masterha_stop --conf=/opt/soft/mha/app1/app1.cnf

manager.log日誌會列印終止日誌:

12.手動進行主備切換(在進行手動切換前要先停值manager程式)

masterha_master_switch --conf=/opt/soft/mha/app1/app1.cnf --master_state=alive --new_master_host=s143 --orig_master_is_new_slave --running_updates_limit=10000 --interactive=0

命令引數:

--master_state=dead
強制引數. 可選有: "dead" or "alive". 如果設定為 alive,將執行線上切主操作。
--dead_master_host=(hostname)
強制引數,--dead_master_ip 和 --dead_master_port 可選。
--interactive=(0|1)
1為互動模式(預設),會輸入幾個yes;0為非互動。
--ssh_reachable=(0|1|2)
否通過SSH可達。0表示不可達;2表示未知(預設)。
--skip_change_master
跳過CHANGE MASTER TO 操作
--skip_disable_read_only
跳過在新主上 SET GLOBAL read_only=0的操作。以便稍後手動操作。
--last_failover_minute=(minutes)
最近故障轉移時間間隔(預設480),如果之前的故障轉移是最近完成的(預設情況下是8小時),MHA Manager不會執行故障轉移,因為問題很可能無法通過執行故障轉移來解決。此引數的目的是避免乒乓故障轉移問題。您可以通過更改此引數來更改時間標準
--ignore_last_failover
如果前面的故障轉移失敗,MHA不會啟動故障轉移,因為問題可能會再次發生。啟動故障轉移的正常步驟是手動刪除在(manager_workdir)/(app_name).failover下建立的故障轉移錯誤檔案。如果設定該引數,將忽略這個錯誤檔案,直接進行故障轉移。
--remove_dead_master_conf
設定此選項後,如果故障轉移成功完成,MHA Manager將自動從配置檔案中刪除失效主伺服器的部分。
--wait_until_gtid_in_sync(0|1)
適用於GTID模式,設定為1表示MHA將等待所有slave追上新master的GTID,預設;0表示不等。
--orig_master_is_new_slave
如果原主庫alive,設定該引數,將會使原master作為新主庫的slave

 說明切換成功!

13.常用的命令

SHOW SLAVE STATUS;          #檢視從庫複製狀態
SHOW MASTER STATUS;         #檢視當前binlog位點
SHOW SLAVE HOSTS;           #檢視從庫列表

 

相關文章