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