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以前的版本。
