您好,登錄后才能下訂單哦!
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工作架構示意圖如下:
在MHA架構中,可以采用半同步復制的方式,來最大限度的保證數據的一致性,MySQL的主從復制中,默認是采用異步來做主從復制的,但是異步有些弊端,下面是對異步、半同步的一個簡單介紹:
- 異步與半同步:默認情況下MySQL的復制是異步的,Master上所有的更新操作寫入Binlog之后并不確保所有的更新都被復制到Slave之上。異步操作雖然效率高,但是在Master/Slave出現問題的時候,存在很高數據不同步的風險,甚至可能丟失數據。 MySQL5.5引入半同步復制功能的目的是為了保證在master出問題的時候,至少有一臺Slave的數據是完整的。在超時的情況下也可以臨時轉入異步復制,保障業務的正常使用,直到一臺salve追趕上之后,繼續切換到半同步模式。
MHA相比較于其他HA軟件,MHA的目的在于維持MySQL replication中master庫的高可用性,其最大的特點是可以修復多個slave之間的差異日志,最終使所有slave保持數據一致,然后從中選擇一個充當新的master,并將其他slave指向它。
大概流程如下:
1、從宕機的master保存二進制日志事件;
2、識別含有最新更新的slave;
3、應用差異的中繼日志(relay log)到其他slave;
4、應用從master保存的二進制日志事件;
5、提升一個slave為新master;
6、使其他的slave連接到新的master進行復制。
目前MHA主要支持一主多從的架構,要搭建MHA,一般MySQL集群中最少有三臺數據庫節點,一主二從,即:一臺充當master,一臺充當備用master,另外一臺充當slave。
1、MHA切換不依賴實例使用存儲引擎和BINLOG格式;
2、MHA不會增加MySQL服務器性能開銷,除MHA管理節點外無需增加額外服務器;
3、在MySQL服務器上部署MHA數據節點不會影響當前實例運行;
4、MHA實現自動故障切換,也可以手動觸發在線切換;
5、MHA可以實現秒級的故障切換;
6、MHA可以將任意slave提升master,也可以在切換時指定master候選節點;
7、MHA提供擴展接口,允許在MHA切換過程中的特定時間點執行用戶自定義腳本。
1、只支持BINLOG V4版本,要求MySQL 5.0或更高版本。
2、候選master節點必須開啟log-bin參數,如果所有從節點都為開啟,則不進行故障轉移。
3、在MHA 0.52版本前不支持多master模式
4、MHA默認不支持多級主從復制,通過修改配置文件和設置multi_tier_slave參數
OS | IP地址 | 主機名&角色 | 類型 |
---|---|---|---|
Centos 7.5 | 192.168.20.2 | master | 主master(寫操作) |
Centos 7.5 | 192.168.20.3 | slave1 | 從(備主)mysql(讀操作) |
Centos 7.5 | 192.168.20.4 | slave2 | 從mysql(讀操作) |
Centos 7.5 | 192.168.20.5 | manager | 管理節點 |
在上述環境中,master對外提供寫服務,slave提供讀操作,一旦master宕機,將會把其中一臺slave(我這里將指定的是備主)提升為新的master,slave同時也指向新的master,manager作為管理服務器。
以下操作在其中一個節點執行即可。
#編寫host文件
[root@master ~]# cat >> /etc/hosts << EOF
> 192.168.20.2 master
> 192.168.20.3 slave1
> 192.168.20.4 slave2
> 192.168.20.5 manager
> EOF
> #將編寫好的hosts文件分發到其他節點
[root@master ~]# for i in master slave1 slave2 manager;do scp /etc/hosts $i:/etc/;done
注:集群中的所有主機都需要保證互相可以免密登錄。
將以下兩條命令在所有節點上執行一次,即可完成主機間的免密登錄
# 創建密鑰對
[root@master ~]# ssh-keygen -t rsa
#將公鑰分發到其他節點
[root@master ~]# for i in master slave1 slave2 manager;do ssh-copy-id $i;done
當所有節點都執行上面的兩條命令,即可使用以下命令來驗證,免密登錄是否成功:
#如果每臺主機上執行以下指令不用輸入密碼就可以獲取所有主機的主機名,說明免密登錄配置無誤
[root@master ~]# for i in master slave1 slave2 manager;do ssh $i hostname;done
master
slave1
slave2
manager
注:以下命令需要在所有節點執行。
#配置阿里的epel源(為加快安裝速度),若非國內環境,執行yum -y install epel-release進行配置即可
[root@master ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@master ~]# yum makecache #建立元數據緩存
# 安裝所需依賴
[root@master ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-ParallelForkManager perl-Config-IniFiles ncftp perl-Params-Validate perl-CPAN perl-TestMock-LWP.noarch perl-LWP-Authen-Negotiate.noarch perl-devel perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
注:接下來所有操作,如果沒有特別說明,是需要在所有數據庫服務器上進行執行的。
mysql> show variables like '%plugin_dir%'; #查找插件所在目錄(每臺DB服務器可能不一樣)
+---------------+------------------------------+
| Variable_name | Value |
+---------------+------------------------------+
| plugin_dir | /usr/local/mysql/lib/plugin/ |
+---------------+------------------------------+
1 row in set (0.01 sec)
mysql> show variables like '%have_dynamic%'; #檢查是否支持動態檢測
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| have_dynamic_loading | YES |
+----------------------+-------+
1 row in set (0.01 sec)
[root@master ~]# ls /usr/local/mysql/lib/plugin/ | egrep 'master|slave'
#確定插件的目錄下有以下兩個文件(默認安裝數據庫后就有這些的)
semisync_master.so
semisync_slave.so
# semisync_master.so和semisync_slave.so為上面查詢到的插件名字
mysql> install plugin rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> show plugins;
# 或者
mysql> select * from information_schema.plugins;
show plugins執行后返回如下結果,表示沒有問題:
mysql> show variables like '%rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+-------------------------------------------+------------+
可以看到半同步插件還是未啟用的off狀態,所以需要修改my.cnf配置文件,如下:
master主機完整配置文件如下:
[root@master ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=1
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin=mysql-bin
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
注:
- rpl_semi_sync_master_enabled=1:1表是啟用,0表示關閉
- rpl_semi_sync_master_timeout=1000:毫秒單位 ,該參數主服務器等待確認消息10秒后,不再等待,變為異步方式。
slave1主機完整配置文件如下:
[root@slave1 ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=2
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin=mysql-bin
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
slave2主機的完整配置文件如下:
[root@slave2 ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=3
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin = mysql-bin
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
read_only = 1
rpl_semi_sync_slave_enabled=1
#由于slave2只是用來做一個slave主機,所以無需開啟master的半同步
在配置主從復制中,由于主和備主這兩臺主機上設置了參數relay_log_purge=0(表示不自動清除中繼日志),所以slave節點需要定期刪除中繼日志,建議每個slave節點刪除中繼日志的時間錯開。
crontab -e
0 5 * * * /usr/local/bin/purge_relay_logs - -user=root --password=pwd123 --port=3306 --disable_relay_log_purge >> /var/log/purge_relay.log 2>&1
更改配置文件后,需要執行以下命令進行重啟MySQL。
[root@master ~]# systemctl restart mysqld
查看半同步狀態,確認已開啟:
mysql> show variables like '%rpl_semi_sync%'; #查看半同步是否開啟
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON | #這個值要為ON
| rpl_semi_sync_master_timeout | 1000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
| rpl_semi_sync_slave_enabled | ON | #這個值也要為ON。
| rpl_semi_sync_slave_trace_level | 32 |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)
mysql> show status like '%rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
| Rpl_semi_sync_slave_status | OFF |
+--------------------------------------------+-------+
15 rows in set (0.00 sec)
#關于上個命令查看到的信息,有幾個狀態值得關注,將在下面寫下來。
- rpl_semi_sync_master_status :顯示主服務是異步復制模式還是半同步復制模式,ON為半同步;
- rpl_semi_sync_master_clients :顯示有多少個從服務器配置為半同步復制模式;
- rpl_semi_sync_master_yes_tx :顯示從服務器確認成功提交的數量
- rpl_semi_sync_master_no_tx :顯示從服務器確認不成功提交的數量
- rpl_semi_sync_master_tx_avg_wait_time :事務因開啟 semi_sync ,平均需要額外等待的時間
- rpl_semi_sync_master_net_avg_wait_time :事務進入等待隊列后,到網絡平均等待時間
1)master主機操作如下:
# 創建用于同步的用戶
mysql> grant replication slave on *.* to mharep@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (1.00 sec)
# 創建用戶mha的manager監控的用戶
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
# 查看master二進制相關的信息
mysql> show master status\G
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 744
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
2)slave1主機操作如下:
# 創建用于同步的用戶
mysql> grant replication slave on *.* to mharep@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (1.00 sec)
# 創建用戶mha的manager監控的用戶
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
3)slave2主機操作如下:
由于slave2無需做備主,所以不用創建用于同步數據的賬戶
#創建manager監控賬號
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
以下操作需要在slave1和slave2主機上分別執行一次,以便同步master主機的數據。
#指定master主機的相關信息
mysql> change master to
-> master_host='192.168.20.2',
-> master_port=3306,
-> master_user='mharep',
-> master_password='123.com',
-> master_log_file = 'mysql-bin.000001', #這是在master主機上查看到的二進制日志名
-> master_log_pos=744; #同上,這是查看到的二進制日志的position
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave; #啟動slave
Query OK, 0 rows affected (0.00 sec)
最后查看slave主機的狀態:
在master主機上查看半同步相關信息,會發現同步的client已經變成了2,如下:
注:需要MHA-node需要在所有節點安裝(包括manager主機節點)
#下載包
[root@master src]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58.tar.gz
#安裝
[root@master src]# tar zxf mha4mysql-node-0.58.tar.gz
[root@master src]# cd mha4mysql-node-0.58/
[root@master mha4mysql-node-0.58]# perl Makefile.PL
[root@master mha4mysql-node-0.58]# make && make install
注:接下來的所有操作,如果沒有特別標注,則只需要在manager主機節點上執行即可。
#下載包
[root@manager src]# wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
#安裝
[root@manager src]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@manager src]# cd mha4mysql-manager-0.58/
[root@manager mha4mysql-manager-0.58]# perl Makefile.PL
[root@manager mha4mysql-manager-0.58]# make && make install
[root@manager mha4mysql-manager-0.58]# mkdir /etc/masterha
[root@manager mha4mysql-manager-0.58]# mkdir -p /masterha/app1
[root@manager mha4mysql-manager-0.58]# mkdir /scripts
[root@manager mha4mysql-manager-0.58]# pwd
/usr/src/mha4mysql-manager-0.58 #確定當前所在目錄
[root@manager mha4mysql-manager-0.58]# cp samples/conf/* /etc/masterha/
[root@manager mha4mysql-manager-0.58]# cp samples/scripts/* /scripts/
注:manager共有兩個主要的配置文件,一個是通用默認的,一個是單獨的。需要將默認通用的配置文件的內容清空,如下:
#清空默認的配置文件
[root@manager masterha]# > /etc/masterha/masterha_default.cnf
然后修改單獨的配置文件:
[root@manager ~]# cat /etc/masterha/app1.cnf #修改如下:
[server default]
manager_workdir=/masterha/app1 #指定工作目錄
manager_log=/masterha/app1/manager.log #指定日志文件
user=manager #指定manager管理數據庫節點所使用的用戶名
password=123.com #對應的是上面用戶的密碼
ssh_user=root #指定配置了ssh免密登錄的系統用戶
repl_user=mharep #指定用于同步數據的用戶名
repl_password=123.com #對應的是上面同步用戶的 密碼
ping_interval=1 #設置監控主庫,發送ping包的時間間隔,默認是3秒,嘗試三次沒有回應時自動進行切換
[server1]
hostname=192.168.20.2
port=3306
master_binlog_dir=/usr/local/mysql/data #指定master保存二進制日志的路徑,以便MHA可以找到master的日志
candidate_master=1 #設置為候選master,設置該參數后,發生主從切換以后將會將此庫提升為主庫
[server2]
hostname=192.168.20.3
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1 #設置為候選master
[server3]
hostname=192.168.20.4
port=3306
master_binlog_dir=/usr/local/mysql/data
no_master=1 #設置的不為備選主庫
完整無注釋的配置文件如下:
[root@manager ~]# cat /etc/masterha/app1.cnf
[server default]
manager_workdir=/masterha/app1
manager_log=/masterha/app1/manager.log
user=manager
password=123.com
ssh_user=root
repl_user=mharep
repl_password=123.com
ping_interval=1
[server1]
hostname=192.168.20.2
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1
[server2]
hostname=192.168.20.3
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1
[server3]
hostname=192.168.20.4
port=3306
master_binlog_dir=/usr/local/mysql/data
no_master=1
驗證SSH有效性:
驗證集群復制的有效性(MySQL必須都啟動),如下:
[root@manager masterha]# masterha_check_repl --global_conf=/etc/masterha/masterha_default.cnf --conf=/etc/masterha/app1.cnf
執行上述命令可能會報錯如下:
這是因為沒有在mysql節點上找到mysqlbinlog這個命令,只需要在所有MySQL主機節點上執行以下命令創建軟連接即可,如下:
#注:以下命令是在所有數據庫服務節點執行
[root@master ~]# ln -s /usr/local/mysql/bin/* /usr/local/bin/
我這里再次執行命令,還報錯如下:
解決辦法:
[root@master ~]# rpm -qa |grep -i dbd #查找下面的軟件包
perl-DBD-MySQL-4.023-6.el7.x86_64
perl-DBD-SQLite-1.39-3.el7.x86_64
#卸載下面的軟件包
[root@master ~]# rpm -e --nodeps perl-DBD-MySQL-4.023-6.el7.x86_64
[root@master ~]# yum -y install perl-DBD-MySQL #再次yum安裝即可解決報錯
最后檢查命令執行成功,如下:
[root@manager ~]# masterha_check_repl --global_conf=/etc/masterha/masterha_default.cnf --conf=/etc/masterha/app1.cnf
返回以下信息,表示無誤:
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &> /var/log/mha_manager.log &
注:可以多次執行上述命令,指定不同的app.cnf配置文件,以便監控多個MySQL集群,我這里就一個MySQL集群,所以只需要執行上述一條命令即可。
可以自行查看當前MySQL集群中目前的主是哪臺服務器,我這里MySQL集群中的主是master主機,如下:
現在模擬master主機故障,然后再查看集群中的master是哪臺,如下:
# 在master主機停止MySQL服務
[root@master ~]# systemctl stop mysqld
# 再次在slave2主機上查看當前的主是哪臺?
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.20.3 # 可以看到當前的主是slave1這臺備主
Master_User: mharep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 744
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 320
MHA Manager服務發生主從切換后,MHA manager服務會自動停止,且在manager_workdir(/masterha/app1/)目錄下面生成app1.failover.complete文件,若要再次啟動MHA,必須先確保沒有這個文件,如果有app1.failover.complete或者app1.failover.error這個文件,則會報錯如下:
只需要刪除這個文件在將master主機指向新的master(也就是slave1)即可成功啟動manager服務,如下:
# 刪除
[root@manager app1]# rm -rf /masterha/app1/app1.failover.complete
# 在manager服務的日志中查看指定master的信息,如下:
[root@manager app1]# cat /masterha/app1/manager.log | grep MASTER
#如果服務已運行很久,那么肯定是看最后一條信息,日志里已經把指向新的master需要執行的指令記錄了下來
#但是需要自己手動寫密碼
Fri Feb 21 17:57:37 2020 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='192.168.20.3', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=744, MASTER_USER='mharep', MASTER_PASSWORD='xxx';
Fri Feb 21 17:57:38 2020 - [info] Executed CHANGE MASTER.
# 在master主機上執行下面命令,以便指定slave2為主:
mysql> CHANGE MASTER TO MASTER_HOST='192.168.20.3', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=744, MASTER_USER='mharep', MASTER_PASSWORD='123.com';
#啟動slave功能
mysql> start slave;
#再次啟動manager服務
[root@manager app1]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &> /var/log/mha_manager.log &
[1] 16130
# 通過jobs -l查看到狀態為“運行中”,即說明manager重新運行成功
[root@manager app1]# jobs -l
[1]+ 16130 運行中 nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/var/log/mha_manager.log &
[root@manager ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
[root@manager ~]# masterha_stop --conf=/etc/masterha/app1.cnf
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/tmp/mha_manager.log &
當有slave節點宕機時,manager服務是無法啟動的,建議在配置文件中暫時注釋掉宕機節點的信息,待修復后再取消注釋。
[root@manager ~]# masterha_check_status --conf=/etc/masterha/app1.cnf #manager沒有啟動時的狀態如下
app1 is stopped(2:NOT_RUNNING).
#啟動manager服務再進行檢查如下
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/tmp/mha_manager.log &
[1] 19651
[root@manager ~]# masterha_check_status --conf=/etc/masterha/app1.cnf
app1 (pid:19651) is running(0:PING_OK), master:192.168.20.3
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。