1. 程式人生 > 實用技巧 >MySQL高可用架構——MHA

MySQL高可用架構——MHA

一、認識MHA

1.1 MHA概述

MHA(Master High Availability)目前在MySQL高可用方面是一個相對成熟的解決方案,在MySQL故障切換過程中,MHA能做到在0~30秒之內自動完成資料庫的故障切換操作,並且在進行故障切換的過程中,MHA能在最大程度上保證資料的一致性,以達到真正意義上的高可用。 MHA裡有兩個角色一個是MHA Node(資料節點)另一個是MHA Manager(管理節點)。 MHA Manager可以單獨部署在一臺獨立的機器上管理多個master-slave叢集,也可以部署在一臺slave節點上。MHA Node執行在每臺MySQL伺服器上,MHA Manager會定時探測叢集中的master節點,當master出現故障時,它可以自動將最新資料的slave提升為新的master,然後將所有其他的slave重新指向新的master。整個故障轉移過程對應用程式完全透明。

MHA工作架構示意圖如下:

大概流程如下:
1、從宕機的master儲存二進位制日誌事件;
2、識別含有最新更新的slave;
3、應用差異的中繼日誌(relay log)到其他slave;
4、應用從master儲存的二進位制日誌事件;
5、提升一個slave為新master;
6、使其他的slave連線到新的master進行復制;

1.2 MHA架構工作原理

主庫宕機處理過程:

1)監控節點 (通過配置檔案獲取所有節點資訊)
① 系統,網路,SSH連線性;
② 主從狀態,重點是主庫;
2)選主
① 如果判斷從庫(position或者GTID),資料有差異,最接近於Master的slave,成為備選主;
② 如果判斷從庫(position或者GTID),資料一致,按照配置檔案順序,選主;
③ 如果設定有權重(candidate_master=1),按照權重強制指定備選主;
1)預設情況下如果一個slave落後master 100M的relay logs的話,即使有權重,也會失效;
2)如果check_repl_delay=0的化,即使落後很多日誌,也強制選擇其為備選主;
3)資料補償
① 當SSH能連線,從庫對比主庫GTID 或者position號,立即將二進位制日誌儲存至各個從節點並且應用(save_binary_logs );
② 當SSH不能連線, 對比從庫之間的relaylog的差異(apply_diff_relay_logs) ;
4)Failover
① 將備選主進行身份切換,對外提供服務;
② 其餘從庫和新主庫確認新的主從關係;
5)應用透明(VIP);
6)二次資料補償(binlog_server);

1.3 MHA軟體組成

Manager工具包主要包括以下幾個工具:
masterha_manger             啟動MHA 
masterha_check_ssh      檢查MHA的SSH配置狀況 
masterha_check_repl         檢查MySQL複製狀況 
masterha_master_monitor     檢測master是否宕機 
masterha_check_status       檢測當前MHA執行狀態 
masterha_master_switch  控制故障轉移(自動或者手動)
masterha_conf_host      新增或刪除配置的server資訊

Node工具包主要包括以下幾個工具:
這些工具通常由MHA Manager的指令碼觸發,無需人為操作
save_binary_logs            儲存和複製master的二進位制日誌 
apply_diff_relay_logs       識別差異的中繼日誌事件並將其差異的事件應用於其他的
purge_relay_logs            清除中繼日誌(不會阻塞SQL執行緒)

1.4 MHA特性

1、MHA切換不依賴例項使用儲存引擎和BINLOG格式;
2、MHA不會增加MySQL伺服器效能開銷,除MHA管理節點外無需增加額外伺服器;
3、在MySQL伺服器上部署MHA資料節點不會影響當前例項執行;
4、MHA實現自動故障切換,也可以手動觸發線上切換;
5、MHA可以實現秒級的故障切換;
6、MHA可以將任意slave提升master,也可以在切換時指定master候選節點;
7、MHA提供擴充套件介面,允許在MHA切換過程中的特定時間點執行使用者自定義指令碼。

二、準備環境

2.1 案例環境

OS hostname IP service type
centos 7.5 master 192.168.1.1 mysql 5.7 master
centos 7.5 backup 192.168.1.2 mysql 5.7 backup
centos 7.5 slave 192.168.1.3 mysql 5.7 slave、manager

2.2 配置節點互信

① 配置hosts檔案

只在master節點上完成即可!

[root@master ~]# cat >> /etc/hosts << EOF
> 192.168.1.1 master
> 192.168.1.2 backup
> 192.168.1.3 slave
> EOF
[root@master ~]# for i in master backup slave;do scp /etc/hosts $i:/etc/;done
② 配置免密登入

以下操作需在所有節點上完成!

[root@master ~]# ssh-keygen -t rsa
[root@master ~]# for i in master backup slave;do ssh-copy-id $i;done

所有節點配置完成後,使用以下命令進行檢測:

[root@master ~]# for i in master backup slave;do ssh $i hostname;done
master
backup
slave
#無需輸入密碼,即可顯示正確的結果

三、配置一主兩從(GTID方式)

3.1 清理環境

所有節點都需進行以下操作!

[root@master ~]# systemctl stop mysqld
[root@master ~]# rm -rf /usr/local/mysql/data/*
#使用GTID同步的方式必須保證資料庫是停止的狀態,並且刪除資料庫資料目錄下的所有東西

3.2 準備資料庫配置檔案

master節點:

[root@master ~]# cat > /etc/my.cnf << EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
server_id=1
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/usr/local/mysql/data/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=master[\\d]>
EOF

backup節點:

[root@backup ~]# cat > /etc/my.cnf << EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
server_id=2
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/usr/local/mysql/data/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=backup[\\d]>
EOF

slave節點:

[root@slave ~]# cat > /etc/my.cnf << EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/mysql.sock
server_id=3
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/usr/local/mysql/data/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=slave[\\d]>
EOF

3.3 初始化資料庫、啟動資料庫

所有節點都需進行以下操作:

[root@master ~]# mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql  --datadir=/usr/local/mysql/data
[root@master ~]# systemctl start mysqld

3.4 構建主從關係

master節點:

[root@master ~]# mysql
master[(none)]>grant replication slave on *.* to repl@'192.168.1.%' identified by '123';
#主庫建立專用於主從複製的使用者

backup節點:

[root@backup ~]# mysql
backup[(none)]>change master to
master_host='192.168.1.1',
master_user='repl',
master_password='123',
master_auto_position=1;
backup[(none)]>start slave;

slave節點:

[root@slave ~]# mysql
slave[(none)]>change master to
master_host='192.168.1.1',
master_user='repl',
master_password='123',
master_auto_position=1;
slave[(none)]>start slave;

3.5 驗證主從複製

master[(none)]>show master status;
+------------------+----------+--------------+------------------+----------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                      |
+------------------+----------+--------------+------------------+----------------------------------------+
| mysql-bin.000002 |      447 |              |                  | e6ff02dc-81fd-11ea-a229-000c29667213:1 |
+------------------+----------+--------------+------------------+----------------------------------------+
#檢視主庫資訊,注意GTID號

backup[(none)]>show slave status \G
           Retrieved_Gtid_Set: e6ff02dc-81fd-11ea-a229-000c29667213:1
            Executed_Gtid_Set: e6ff02dc-81fd-11ea-a229-000c29667213:1
			
slave[(none)]>show slave status \G
           Retrieved_Gtid_Set: e6ff02dc-81fd-11ea-a229-000c29667213:1
            Executed_Gtid_Set: e6ff02dc-81fd-11ea-a229-000c29667213:1			
#從庫檢測與主庫的GTID號一致

四、搭建簡易——MHA

4.1 配置關鍵程式軟連線

以下操作所有節點必須都進行操作!

[root@master ~]# ln -s /usr/local/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@master ~]# ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql

4.2 安裝MHA

① 獲取MHA軟體
mha官網:
https://code.google.com/archive/p/mysql-master-ha/ 

github下載地址:
https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads 
也可使用文中的地址進行下載
② 所有節點安裝node軟體及其依賴
[root@master ~]# yum -y install perl-DBD-MySQL
[root@master ~]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@master ~]# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
③ 在master主庫上建立MHA需要的資料庫使用者
master[(none)]>grant all privileges on *.* to mha@'192.168.1.%' identified by 'mha';
④ slave節點安裝manager軟體及其依賴
[root@slave ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@slave ~]# yum makecache
[root@slave ~]# yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
[root@slave ~]# wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
[root@slave ~]# rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

4.3 slave節點準備MHA的配置檔案

[root@slave ~]# mkdir -p /etc/mha
#建立配置檔案目錄
[root@slave ~]# mkdir -p /var/log/mha/app1
#建立日誌檔案目錄
[root@slave ~]# vim /etc/mha/app1.cnf
#編寫MHA的配置檔案
[server default]
manager_log=/var/log/mha/app1/manager       #MHA日誌檔案
manager_workdir=/var/log/mha/app1           #MHA工作目錄
master_binlog_dir=/usr/local/mysql/data/       #主庫的binlog日誌位置
user=mha
password=mha                               #MHA專用使用者
ping_interval=2                         #監控間隔(秒數)每兩秒監控一次,監控兩次
repl_password=123
repl_user=repl          #主從複製專用使用者
ssh_user=root           #配置互信使用者名稱
[server1]
hostname=192.168.1.1
port=3306
[server2]
hostname=192.168.1.2
port=3306
[server3]
hostname=192.168.1.3
port=3306
#注意配置檔案中不允許有註釋內容

4.4 slave節點監測MHA狀態

① 互信檢測
[root@slave ~]# masterha_check_ssh  --conf=/etc/mha/app1.cnf 

② 主從狀態監測
[root@slave ~]# masterha_check_repl  --conf=/etc/mha/app1.cnf

4.5 slave節點啟動MHA

[root@slave ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
#如果有多個MySQL主從複製例項可以啟動多次,當然需要指定不同的配置檔案

4.6 slave節點監測MHA的狀態

[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:3123) is running(0:PING_OK), master:192.168.1.1

至此一個簡單的MHA架構已經完成!

五、完善MHA——新增VIP

5.1 slave節點準備指令碼檔案

[root@slave ~]# vim /usr/local/bin/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';    #指定虛擬IP地址
my $key = '0';            #指定網絡卡編號
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";  #啟動VIP
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";   #停止VIP
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";
 #`ssh $ssh_user\@cluster1 \" $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 $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
# A simple system call that disable the VIP on the old_master
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";
}
[root@slave ~]# chmod +x /usr/local/bin/master_ip_failover

5.2 master節點配置虛擬IP

[root@master ~]# ifconfig ens33:1 192.168.1.100/24

5.3 slave節點新增配置引數

[root@slave ~]# vim /etc/mha/app1.cnf
master_ip_failover_script=/usr/local/bin/master_ip_failover
注意:/usr/local/bin/master_ip_failover,必須事先準備好

5.4 重啟MHA,檢視狀態

[root@slave ~]# masterha_stop --conf=/etc/mha/app1.cnf
[root@slave ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:3625) is running(0:PING_OK), master:192.168.1.1

可以正常檢視MHA的狀態,表示沒有問題!

注意:

  • MHA自帶的VIP功能,只能在同機房,不可跨機房、網路,如果需要跨機房、網路應該使用Keepalived實現;
  • 配置Keepalived時注意優先順序切換的問題;
  • 配置Keepalived的情況MHA需要新增一些額外引數,否則切換VIP時,可能會出現意想不到的錯誤;
主庫宕機誰來接管?
1. 所有從節點日誌都是一致的,預設會以配置檔案的順序去選擇一個新主。
2. 從節點日誌不一致,自動選擇最接近於主庫的從庫
3. 如果對於某節點設定了權重(candidate_master=1),權重節點會優先選擇。
但是此節點日誌量落後主庫100M日誌的話,也不會被選擇。可以配合check_repl_delay=0,關閉日誌量的檢查,強制選擇候選節點。
(1)  ping_interval=1
#設定監控主庫,傳送ping包的時間間隔,嘗試三次沒有迴應的時候自動進行failover
(2) candidate_master=1
#設定為候選master,如果設定該引數以後,發生主從切換以後將會將此從庫提升為主庫,即使這個主庫不是叢集中事件最新的slave
(3)check_repl_delay=0
#預設情況下如果一個slave落後master 100M的relay logs的話,MHA將不會選擇該slave作為一個新的master,因為對於這個slave的恢復需要花費很長時間,通過設定check_repl_delay=0,MHA觸發切換在選擇一個新的master的時候將會忽略複製延時,這個引數對於設定了candidate_master=1的主機非常有用,因為這個候選主在切換的過程中一定是新的master;

六、完善MHA——資料補償binlogserver

binlogserver配置:找一臺額外的機器,必須要有5.6以上的版本,支援gtid並開啟,我們直接使用用的slave節點!

6.1 slave節點配置MHA配置檔案

[root@slave ~]# vim /etc/mha/app1.cnf
[binlog1]
no_master=1    #不參與選主
hostname=192.168.1.3
master_binlog_dir=/data/mysql/binlog

6.2 slave節點建立必要的目錄

[root@slave ~]# mkdir -p /data/mysql/binlog
[root@slave ~]# chown -R mysql.mysql /data/*

6.3 節點拉取主庫的binlog日誌

[root@slave ~]# cd /data/mysql/binlog
#必須進入指定的目錄進行拉取日誌資訊
[root@slave binlog]# mysqlbinlog  -R --host=192.168.1.1 --user=mha --password=mha --raw  --stop-never mysql-bin.000001 &
#指定主庫IP地址使用的使用者、密碼,從不停止的拉取、指定起始的日誌檔案,放到後臺執行

注意:拉取日誌的起點,需要按照目前從庫的已經獲取到的二進位制日誌點為起點!

6.4 slave節點重啟MHA

[root@slave ~]# masterha_stop --conf=/etc/mha/app1.cnf
[root@slave ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &
[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:4147) is running(0:PING_OK), master:192.168.1.1

七、測試MHA

7.1 master節點模擬故障

[root@master ~]# systemctl stop mysqld

7.2 slave節點排查manager程序

[root@slave ~]# ps -ef | grep manager
root       4472   2705  0 14:32 pts/0    00:00:00 grep --color=auto manager
#manager程序已經退出
[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
#MHA已經停止工作

7.3 backup節點檢視VIP

[root@backup ~]# ip a

7.4 slave節點檢視MHA狀態

[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
#MHA已經停止工作

7.5 slave節點檢視切換日誌

[root@slave ~]# tail /var/log/mha/app1/manager

7.6 slave節點檢視MHA配置檔案

[root@slave ~]# cat /etc/mha/app1.cnf

如果節點已經消失,說明切換過程是成功的;
如果節點還存在,,證明切換過程中出現問題;

7.7 slave節點確認當前主從關係

[root@slave ~]# mysql
slave[(none)]>show slave status \G

八、修復MHA故障

8.1 修復故障庫

[root@master ~]# systemctl start mysqld

8.2 故障庫修復主從關係

[root@master ~]# mysql
master[(none)]>change master to
master_host='192.168.1.2',
master_user='repl',
master_password='123',
master_auto_position=1;
master[(none)]>start slave;

8.3 slave節點修復配置檔案

[root@slave ~]# vim /etc/mha/app1.cnf
#新增以下內容
[server1]
hostname=192.168.1.1
port=3306

8.4 slave節點檢查ssh互信和repl的主從關係

[root@slave ~]# masterha_check_ssh  --conf=/etc/mha/app1.cnf 
[root@slave ~]# masterha_check_repl  --conf=/etc/mha/app1.cnf


8.5 slave節點修復binlogserver

主節點檢視二進位制日誌

backup[(none)]>show master status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000002 |      736 |              |                  | e6ff02dc-81fd-11ea-a229-000c29667213:1-2 |
+------------------+----------+--------------+------------------+------------------------------------------+
#檢視當前二進位制日誌


[root@slave ~]# cd /data/mysql/binlog/
[root@slave binlog]# rm -rf *
[root@slave binlog]# mysqlbinlog  -R --host=192.168.1.2 --user=mha --password=mha --raw  --stop-never mysql-bin.000002 &
#檢視主庫當前日誌進行拉取

檢查VIP,如果切換過程中VIP發生故障,手工生成!

8.6 slave節點啟動MHA

[root@slave ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &
[root@slave ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:63142) is running(0:PING_OK), master:192.168.1.2