本次實驗基于【MHA+keepalive 高可用MYSQL集群】(續)
一、恢復背景
二、修復故障節點及MHA集群
三、提升已修復的節點為master
四、注意事項
一、恢復背景
1、設備清單
2、:percona-xtrabackup-2.3.2
(注:生產環境應定時備份;不應等到數據庫DOWN后才備份,以免加劇集群的壓力)
備份數據庫操作:
[root@jev72 ~]#innobackupex --user=root --password=centos /data/ 。 。 。 xtrabackup: innodb_log_file_size = 5242880 #注意記錄該日志文件大小值 。 。 。
以上為故障前,數據庫備份操作,這里寫出來是為了便于說明后面調節日志大小操作;
二、修復故障節點及MHA集群
1、恢復前備份文件準備:
將備份文件拷貝到jev1(故障master)上:
[root@jev72 ~]#scp -r /data/2017-02-27_21-23-44 172.16.250.131:/data/
模擬生產環境,在備份后,對數據庫進行寫操作:
[root@jev6 ~]#mysql -umhaadmin -h172.16.250.188 -pmhapass mysql> show databases ; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | | test2 | +--------------------+ 5 rows in set (0.00 sec) #新建test3數據庫 mysql> create database test3; Query OK, 1 row affected (0.00 sec)
2、修改日志大小配置,及清空數據庫
此處用直接在故障master操作,如果用新主機需要重新搭建系統環境,注意停止mariadb服務;
將日志大小配置為xtrabackup備份時使用的大小5242880
[root@jev71 ~]#vim /etc/my.cnf.d/server.cnf [mysqld] nnodb_log_file_size=5242880 #清空原數據庫文件(生成環境,建議先挪走再刪除,以防誤刪) [root@jev71 ~]#rm -rf /var/lib/mysql/
3、恢復數據
[root@jev71 ~]#innobackupex --copy-back /data/2017-02-27_21-23-44/ 。 。 。 170227 22:07:12 completed OK!
4、予mysql權限,啟動mariadb,并查看數據庫狀態
[root@jev71 ~]#chown -R mysql:mysql /var/lib/mysql [root@jev71 ~]#systemctl start mariadb [root@jev71 ~]#mysql MariaDB [(none)]> show databases ; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | | test2 | +--------------------+ 5 rows in set (0.00 sec)
5、查看時二進制文件位置并進行事務回放重寫
(注,如果備份點之后服務器的寫操作比較少,可以在恢復節點(jev1)直接指定master日志復制位置直接復制(合并到集群),如果期間產生的二進制文件較大,需要先拷貝備份點之后的所有二進制文件,進行日志重寫再合并到集群)
[root@jev71 ~]#cat /data/2017-02-27_21-23-44/xtrabackup_binlog_info master-log.000004 245
備份點之后的所有二進制文件拷貝到恢復節點上(jev1)
[root@jev73 ~]#scp /var/lib/mysql/master-log.000004 172.16.250.131:/tmp/
將備份備份點之后的二進制文件保存到文件中(如果是誤刪的話,需要將其中的誤刪的語句刪除)
[root@jev71 ~]#mysqlbinlog /tmp/master-log.000004 --start-position=245 >/tmp/myqlsbinlog.001 [root@jev71 ~]#mysql #關閉二進制日志; MariaDB [(none)]> set @@session.sql_log_bin=0 ; #事務回放重寫 MariaDB [(none)]> source /tmp/myqlsbinlog.001 ;
6、故障節點修復后以slave的身份并入集群;
將/etc/my.cnf.d/repl.cnf配置為slave:
[root@jev71 ~]#vim /etc/my.cnf.d/repl.cnf [mysqld] server-id=1 log-bin=master-log relay-log=relay-log relay_log_purge=0 read_only=1 innodb_file_per_table=1 skip_name_resolve=1 #重啟mariadb服務; [root@jev71 ~]#systemctl restart mariadb && systemctl status mariadb
確定二進制文件最后復制位置,查看用于恢復節點(jev1)的二進制日志最后一個end_log_pos 的值,確定復制起點;
[root@jev71 ~]# mysqlbinlog /tmp/master-log.000004 --start-position=245 。 。 。 #170227 21:34:17 server id 2 end_log_pos 415 Query thread_id=39 exec_time=0 error_code 。 。 。 [root@jev71 ~]#mysql #設置復制起點 MariaDB [(none)]> change master to master_host='172.16.250.132',master_user='repluser',master_password='replpass',master_log_file='master-log.000004',master_log_pos=415; #開啟從節點復制線程 MariaDB [(none)]> start slave ; #查看slave狀態,確保slave工作正常,關鍵項如下狀態為正常; MariaDB [(none)]> show slave status G Slave_IO_State: Waiting for master to send event Slave_IO_Running: Yes Slave_SQL_Running: Yes #再次查看數據庫狀態 MariaDB [(none)]> show databases ; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | | test2 | | test3 | +--------------------+ 6 rows in set (0.00 sec)
7、manager上查看MHA集群狀態
[root@jev74 ~]#masterha_check_repl --conf=/etc/masterha/app1.cnf 。 。 。 172.16.250.132(172.16.250.132:3306) (current master) +--172.16.250.131(172.16.250.131:3306) +--172.16.250.133(172.16.250.133:3306) 。 。 。 MySQL Replication Health is OK.
可以看到修復節點已經成功并入集群;
此時應該對數據庫進行一次全庫備份(建議在備用master,即剛剛恢復的數據庫);
8、配置keepalived,完善MHA集群
啟動masterha_manager
[root@jev74 ~]# masterha_manager --conf=/etc/masterha/app1.cnf
配置keepalived;(注,權重需要低于現在運行中的master,并開啟搶占模式)
[root@jev71 ~]#cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id mysql vrrp_mcast_group4 224.0.88.88 } vrrp_script chk_mysqld { script "killall -0 mysqld && exit 0 || exit 1" interval 1 weight -5 fall 2 } vrrp_instance VI_1 { state BACKUP interface eno16777736 virtual_router_id 8 priority 98 advert_int 1 authentication { auth_type PASS auth_pass mysqlvipass } track_script { chk_mysqld } virtual_ipaddress { 172.16.250.188/16 dev eno16777736 #高可用的VIP地址 } } #啟動keepalived [root@jev71 ~]#systemctl start keepalived && systemctl status keepalived
到此MHA集群已經完全修復
三、提升已修復的節點為master
【注意】:下面環節,除非迫不得已,不建議在生產環境做
如果目前主節點一修復節點(就master)的性能相當,那么就沒必要將master切換回去;如需切換,只需關閉當前master上mariadb服務,重復MHA自動遷移master(應在業務低谷期進行)
1、確保masterha_manager正常運行
[root@jev74 ~]#masterha_check_status --conf=/etc/masterha/app1.cnf app1 (pid:6416) is running(0:PING_OK), master:172.16.250.132
2、關閉當前master(jev2)上的mariadb跟keepalived服務,觸發masterha_manager進行master轉移
[root@jev72 ~]#systemctl stop mariadb && systemctl stop keepalived
3、將(jev2)keepalived的權重降低,比(jev1)
[root@jev72 ~]#vim /etc/keepalived/keepalived.conf
4、重新開啟jev2的mariadb進程
[root@jev72 ~]#systemctl start mariadb && systemctl status mariadb
5、此時在manager上檢查MHA集群狀態的話,會報錯提示目前集群有兩的非slave節點:
[root@jev74 ~]#masterha_check_repl --conf=/etc/masterha/app1.cnf [error][/usr/share/perl5/vendor_perl/MHA/ServerManager.pm, ln653] There are 2 non-slave servers! MHA manages at most one non-slave server. Check configurations.
6、配置jev2為slave節點
此時查看新master(jev1)上的二進制日志與從庫對比,在relay log文尾的end_log_pos表示最后讀到binlog的位置,通過最新的relay_log中的binlog file和end_log_pos位置來對比還有哪些events缺失,以及舊master(jev2)需要重新并入集群的復制起點;
[root@jev72 ~]#mysql MariaDB [(none)]> change master to master_host='172.16.250.131',master_user='repluser',master_password='replpass',master_log_file='master-log.000001',master_log_pos=245; #開啟從節點復制線程 MariaDB [(none)]> start slave ; #查看slave狀態,確保slave工作正常,關鍵項如下狀態為正常; MariaDB [(none)]> show slave status G Slave_IO_State: Waiting for master to send event Slave_IO_Running: Yes Slave_SQL_Running: Yes
7、此時在manager上檢查MHA集群狀態,已顯示為健康狀態:
[root@jev74 ~]#masterha_check_repl --conf=/etc/masterha/app1.cnf 172.16.250.131(172.16.250.131:3306) (current master) +--172.16.250.132(172.16.250.132:3306) +--172.16.250.133(172.16.250.133:3306) MySQL Replication Health is OK.
四、注意事項:
本文試驗基于測試環境操作,雖然力求模擬生產環境,但跟生產環境還是有區別的;
對于數據庫的VIP高可用,本文為了方便使用keepalived,但生產環境應該用corosync等重量級應用;
生產環境應該在MHA中配置相關VIP轉移腳本,進一步確保VIP正常轉移;
生產環境中需要將數據跟二進制日志放在獨立磁盤上;
每次主從切換后都必須對比二進制文件,確認是否有事務缺失;
每次主從切換,都不能確保沒有事務丟失,故在關鍵業務還需要增加操作日志;
由于MHA集群要求保留足夠中繼日志,故需要手動定期清理,目前常用的做法為創建軟連接再刪除;
[root@jev71 ~]#mysqlbinlog /var/lib/mysql/master-log.000001
2.切換之后需要刪除手工刪除/data/masterha/app1/app1.failover.complete,才能進行第二次測試
(鎖定8小時)
MHA工作原理
主庫掛了,但是主庫的binlog都被全部從庫接收,此時會選中應用binlog最全的一臺從庫作為新的主庫,其他從主只需要重新指定一下主庫即可(因為此時,所有從庫都是一致的,所以只需要重新指定一下從庫即可)。
主庫掛了,所有的binlog都已經被從庫接收了,但是,主庫上有幾條記錄還沒有sync到binlog中,所以從庫也沒有接收到這個event,如果此時做切換,會丟失這個event。此時,如果主庫還可以通過ssh訪問到,binlog文件可以查看,那么先copy該event到所有的從庫上,最后再切換主庫。如果使用半同步復制,可以極大的減少此類風險。
主庫掛了,從庫上有部分從庫沒有接收到所有的events,選擇出最新的slave,從中拷貝其他從所缺少的events。
問題1、
如何確定哪些event沒有成功接收。
問題2、
如何讓所有從庫保持一致。
導致復制問題的原因是因為MySQL采用異步復制,并不保證所有事件被從庫接收,對于此類問題的解決方案:
1、Heartbeat + DRBD
代價:額外的被動master,并且不處理任何流量。
性能:為了保證事件被及時寫入,innodb_flush_log_at_trx_commit=1,sync_binlog=1. 這樣就會導致性能急速下降。
2、MySQL Cluster
真正的高可用,但是只支持InnoDB。
3、Semi_synchronous Replication (5.5+)
半同步復制極大減少了”binlog事件只存在于master上”的風險。保證至少有一臺從庫接收到了提交的binlog事件。其他的從可能沒有接收,但是不影響提交了。
4、Global Transaction ID
由谷歌開發的插件。
MHA的切換步驟
1、從down的主上面獲取到binlog事件。
2、確定最新(最全)的從庫。
3、分別應用不同的relay log事件到其他從庫。
4、應用從主庫上獲取的binlog事件(發生故障時的事件)。
5、提升一個從庫為新的主庫(此時從庫已經一致)。
6、將其他從庫的主庫重新指定,同時,自動檢測主庫故障。
如何確定最近從庫以及丟失的events
1、Master_Log_File,Read_Master_Log_Pos 可以確定(從庫的IO線程)讀取主庫的binlog的最新進度。
2、Relay_Log_File,Relay_Log_Pos 確定SQL線程執行本地Relay_Log的最新進度。
3、由于Relay_Log的進度和binlog是不一樣的。所以如果只看Relay_Log的信息無法確定執行事件的實際位置,Relay_Master_Log_File,Exec_Master_Log_Pos 本地SQL線程實際上執行binlog位置(用于計算seconds_behind_master)。
4、各個從庫之間,比較Master_Log_File,Read_Master_Log_Pos可以確定哪臺從庫接收到的日志是最完整的。
5、當找出最新最全的從庫之后,應用diff到其他從庫。
僅僅比較上面2個參數是不夠確定具體缺失的events,在relay log中日志開頭會指定是讀哪個binlog,文尾的end_log_pos表示最后讀到binlog的位置。通過對比不同從庫上,最新的relay_log中的binlog file和end_log_pos位置來對比還有哪些events缺失(每個at xxx就是一個event)。如果是一個很大的事務,產生了很多日志信息(事務只會保存在一個binlog文件中,但是會出現在2個relay_log中。)面對這種情形,如果只接受到了部分的events信息。從庫是不會重做這些relay_log。此時的Master_Log_File,Read_Master_Log_Pos 會指向讀取到的binlog的最新位置(這是IO線程負責的),而Relay_Master_Log_File,Exec_Master_Log_Pos只會指向最后執行的commit事務。這樣就保證了不會使數據庫進入不一致狀態。那么在接受到其他從庫最新日志的時候,也是完整的執行一次該事務(即使自己的Relay log已經有部分記錄了)。
MHA需要考慮的注意事項
1、如果使用mysqlbinlog打開binlog和relaylog,會自動在文本里面添加rollback關鍵字所以要在日志中清理掉由mysqlbinlog添加的rollback。
ROLLBACK /* added by mysqlbinlog */
2、由于mha默認關閉relay_log_purge。所以要手動定期清理。為了保證在發生故障時,能有足夠多的relay log用戶恢復,所以不應該自動清理。關閉這個參數之后,SQL線程不會定期清理Relay_log,所以很快會填滿磁盤空間。Relay_log沒有像binlog一樣有自動過期參數expire_logs_days。
定期清理的方式:
set global relay_log_purge=1;
flush logs;/* SQL線程會自動清理多余的Relay_Log_File */
set global relay_log_purge=0;
如果有較大的日志,讓SQL線程自動刪,會導致SQL線程鎖住,從庫落后主庫。
ln relay-log.* /tmp/archive_dir/
mysql -e”set global relay_log_purge=1;flush logs;set global relay_log_purge=0;”
rm -rf /tmp/archive_dir/* */
這樣就不會占用寶貴的SQL線程了。即便如此也不要在所有的從庫上同一時間執行一個計劃任務(清除Relay_Log),否則會導致沒有Relay_Log用戶恢復的情形出現。
3、要確定SQL線程是否執行完所有的events。
(1)、等待事物執行。
(2)、select MASTER_POS_WAIT(master_log_file,read_master_log_pos);如果所有從庫已經與主庫一致了,上面的命令失效,如果只有部分事物日志傳送到從庫,SQL線程也不會同步到Read_Master_Log_Pos。
(3)、show processlist查看輸出。提示:”Has read all relay log;waiting for the slave I/O thread to update it”
(4)、要處理惡意查詢,惡意查詢:insert into t1 values(0,0,”ROLLBACK”);
(5)、有多個從庫時,并行恢復。
(6)、采用ROW FORMAT,對于采用row格式記錄的日志,可能出現多個”#at”條目+相同的”end_log_pos”條目。Table_map+Write_rows+STMT_END
故障自動轉移的內容
1、檢測master failure。
2、Node Fencing(通過干掉故障master 避免腦裂)。
3、更新寫入IP(VIP)。
通過腳本完成自動轉移,同時在故障發生時要自動調用腳本。
(1)、確保文件和對應的目錄存在,SSH互信成功—-避免因為低級錯誤導致轉移失敗。
(2)、如果有從庫服務器掛掉,或者SQL線程掛掉,或者在8個小時內發生過轉移了—-都不再執行故障轉移。
如果發生故障:發送郵件報警,停掉新主庫上的備份任務,更新內部工具的管理地址(從舊庫指向新庫)。
MHA工具介紹
在manager上
master_monitor:檢測master狀態。
master_switch:執行故障轉移(手動執行,如果自動則要使用masterha_manager)。
masterha_manager:啟動mha,執行mha的管理操作。
在node上
save_binary_logs:復制主庫二進制日志。
apply_diff_relay_logs:從最全的slave上生成diff Relay log,應用所有從主庫copy來的的binlog中的events。
filter_mysqlbinlog:清理掉有mysqlbinlog工具帶來的ROLLBACK events。
purge_relay_logs:在不停止SQL線程的前提下刪除Relay_log。
MHA處理案例
master上內核崩潰,10內檢查master狀態,確定master不可用之后power off,選擇新的master,recovery,并行恢復其他從庫。
MHA的限制
不支持多級復制 M->M->S。且不支持日志為statment級別(SBR)的load data infile和MySQL5.0以前的版本。
試驗清單 (linux版本centos7.2) |
||||||
節點 |
角色 |
mysql |
keeplived |
MHA |
IP |
目前狀態 |
jev4 |
manager |
— |
—- |
manager-0.56 |
172.16.250.134 |
manager |
jev1 |
master |
V5.5 |
V1.2 |
node-0.56 |
172.16.250.131 |
故障 |
jev2 |
slave |
V5.5 |
V1.2 |
node-0.56 |
172.16.250.132 |
master |
jev3 |
slave |
V5.5 |
—- |
node-0.56 |
172.16.250.134 |
slave |
VIP地址:172.16.250.188 (用于主MYSQL主節點,保障前端讀寫分離正常調度) |
2.切換之后需要刪除手工刪除/data/masterha/app1/app1.failover.complete,才能進行第二次測試
mamy—-從節點沒裝好:
[root@jev74 ~]#masterha_check_repl –conf=/etc/masterha/app1.cnf
Sun Feb 26 04:44:14 2017 – [warning] Global configuration file /etc/masterha_default.cnf not foun
d. Skipping.Sun Feb 26 04:44:14 2017 – [info] Reading application default configuration from /etc/masterha/ap
p1.cnf..Sun Feb 26 04:44:14 2017 – [info] Reading server configuration from /etc/masterha/app1.cnf..
Sun Feb 26 04:44:14 2017 – [info] MHA::MasterMonitor version 0.56.
Sun Feb 26 04:44:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/ServerManager.pm, ln193] Ther
e is no alive slave. We can’t do failoverSun Feb 26 04:44:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln424] Erro
r happened on checking configurations. at /usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm line 326.Sun Feb 26 04:44:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln523] Erro
r happened on monitoring servers.Sun Feb 26 04:44:14 2017 – [info] Got exit code 1 (Not master dead).
MySQL Replication Health is NOT OK!
從節點沒裝好:
Sun Feb 26 17:03:13 2017 – [info] Checking SSH publickey authentication settings on the current m
aster..Sun Feb 26 17:03:13 2017 – [info] HealthCheck: SSH to jev71.com is reachable.
Sun Feb 26 17:03:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/ManagerUtil.pm, ln122] Got er
ror when getting node version. Error:Sun Feb 26 17:03:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/ManagerUtil.pm, ln123]
bash: apply_diff_relay_logs: command not found
Sun Feb 26 17:03:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln132] Fail
ed to get MHA node version on the current master even though current master is reachable via SSH!Sun Feb 26 17:03:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln424] Erro
r happened on checking configurations. at /usr/bin/masterha_check_repl line 48.Sun Feb 26 17:03:14 2017 – [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln523] Erro
r happened on monitoring servers.Sun Feb 26 17:03:14 2017 – [info] Got exit code 1 (Not master dead).
MySQL Replication Health is NOT OK!
在MHA自動故障切換過程中,MHA試圖從宕機的主服務器上保存二進制日志,最大程度的保證數據的不丟失,但這并不總是可行的。例如,如果主服務器硬件故障或無法通過ssh訪問,MHA沒法保存二進制日志,只進行故障轉移而丟失了最新的數據。使用MySQL 5.5的半同步復制,可以大大降低數據丟失的風險。MHA可以與半同步復制結合起來。如果只有一個slave已經收到了最新的二進制日志,MHA可以將最新的二進制日志應用于其他所有的slave服務器上,因此可以保證所有節點的數據一致性,有時候可故意設置從節點慢于主節點,當發生意外刪除數據庫倒是數據丟失時可從從節點二進制日志中恢復。
[root@jev71 ~]#chown -R mysql:mysql /var/lib/mysql
[root@jev71 ~]#systemctl status mariadb
● mariadb.service – MariaDB database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Mon 2017-02-27 22:11:37 CST; 2min 0s ago
Process: 4831 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=1/FAI
LURE) Process: 4830 ExecStart=/usr/bin/mysqld_safe –basedir=/usr (code=exited, status=0/SUCCESS)
Process: 4803 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCES
S) Main PID: 4830 (code=exited, status=0/SUCCESS)
Feb 27 22:11:35 jev71.com systemd[1]: Starting MariaDB database server…
Feb 27 22:11:36 jev71.com mysqld_safe[4830]: 170227 22:11:36 mysqld_safe Logging to ‘/var/l…g’.
Feb 27 22:11:36 jev71.com mysqld_safe[4830]: 170227 22:11:36 mysqld_safe Starting mysqld da…sql
Feb 27 22:11:37 jev71.com systemd[1]: mariadb.service: control process exited, code=exited …s=1
Feb 27 22:11:37 jev71.com systemd[1]: Failed to start MariaDB database server.
Feb 27 22:11:37 jev71.com systemd[1]: Unit mariadb.service entered failed state.
Feb 27 22:11:37 jev71.com systemd[1]: mariadb.service failed.
Hint: Some lines were ellipsized, use -l to show in full.
[root@jev71 ~]#tail /var/log/mariadb/mariadb.log
170227 22:11:36 InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files…
170227 22:11:36 InnoDB: Operating system error number 13 in a file operation.
InnoDB: The error means mysqld does not have the access rights to
InnoDB: the directory.
InnoDB: File name .
InnoDB: File operation call: ‘opendir’.
InnoDB: Cannot continue operation.
170227 22:11:36 mysqld_safe mysqld from pid file /var/run/mariadb/mariadb.pid ended
[root@jev71 ~]#systemctl stop mariadb
[root@jev71 ~]#systemctl start mariadb
Job for mariadb.service failed because the control process exited with error code. See “systemctl
status mariadb.service” and “journalctl -xe” for details.
刪庫重裝
[root@jev71 ~]#chcon -R -u system_u -r object_r -t mysqld_db_t /var/lib/mysql
source test.sql
ERROR:
ASCII ” appeared in the statement, but this is not allowed unless option
–binary-mode is enabled and mysql is run in non-interactive mode. Set –bin
ary-mode to 1 if ASCII ” is expected. Query: ”.
日格式不對,沒有通過mysql
原創文章,作者:Jev Tse,如若轉載,請注明出處:http://www.www58058.com/70305