* MHA的整個故障(離線)切換過程 - 檢測主庫的狀態,確認是否崩潰。 - 確認服務崩潰,保存binlog,推送到主控機,並能夠強制關閉主庫避免腦裂。 - 找出數據最新的從庫(也就是read_master_log_pos最大的),肯定下新主庫。 - 從最新從庫上生成差別的relaylog,再加上未讀取的binlog,應用到新主庫,記下偏移。 - (併發)的爲其餘從庫生成差別的relaylog和binlog,應用到各個從庫。 - 從庫指向新主庫的偏移處,開始複製。 * 源碼部分關鍵邏輯 ** 讀取配置 ** 檢查配置 - 檢查apply_diff_relay_log的版本號 - 鏈接全部服務器並讀取狀態(得知老主庫) - 檢查參數傳進來的崩潰主庫是否與老主庫地址一致,不然終止切換 - 檢查老主庫是否在離線主機列表中,不在的話就終止切換 - 檢查是否真的鏈接不上mysql服務 - 檢查全部在線從庫,是否都指向老主庫 - 檢查是否有些不應忽略失敗的從庫已經離線 - 檢查上次切換是否失敗 - 檢查上次切換髮生時間與本次切換的時間間隔,過短則終止 - 從全部從庫獲取「切換鎖」 - 保證全部從庫的slave sql線程已經啓動 ** 若是支持gtid自動定位但未啓用,那麼應該強制apply_diff_relay_log禁用log_bin?? ** 強制關閉 - (併發)強制中止全部從庫的slave io線程 - 探測從主控機到崩潰主庫所在主機的ssh可達性 - 執行master_ip_failover_script,保證崩潰主庫所在主機的ip失活防腦裂,不然終止切換 - 只要有一個在線從庫的salve io線程中止失敗,那麼就終止切換 ** 探測出複製延遲最小的從庫、複製延遲最大的從庫 ** 根據最新從庫的slave io線程的讀頭,保存老主庫的binlog。 - 若是崩潰主庫所在主機不可達,那麼就會丟失binlog(Read_Master_Log_Pos to the tail) - 若是可達,ssh鏈接上去,而後執行save_binary_logs --command=save,將保存後的binlog拷貝到主控機,這步稱呼read_to_tail。 ** 根據最新、最老從庫的讀頭以及某些從庫的可忽略失敗,來決定哪一個從庫做爲relaylog、binlog補償的基準 - 若是全部從庫的讀頭一致,跳過 - ssh逐一鏈接最新從庫,執行apply_diff_relay_logs --command=find,看是否realylog包含了最老從庫的讀頭。 - 若是沒有用來補償的基準從庫,終止切換 ** 選擇新主庫(新主庫不必定是最新從庫,參照「在線切換」中的描述) ** 恢復新主庫 - 若果新主庫的讀頭落後於最新從庫,那麼ssh鏈接上最新從庫,執行apply_diff_relay_logs --command=generate_and_send, 從最新從庫的relaylog中提取新主庫讀頭直到最新從庫讀頭處的二進制日誌,這步稱呼爲read_to_latest, $latest_slave->{Master_Log_File}:$latest_slave->{Read_Master_Log_Pos} - 將主控機保存好的最新從庫讀頭到主庫binlog尾部的日誌(read_to_tail),拷貝到新主庫 - 若是不是最新從庫或者有保存過read_to_tail,那麼就應用差別日誌。 -- 首先等待新主庫上已經有的relaylog都重放完畢,中止slave sql線程 -- 讀取最新複製狀態 -- ssh執行save_binary_logs --command=save, 從自身relaylog中恢復exec_to_read -- ssh執行apply_diff_relay_logs --command=apply,將前面生成的3部分補償日誌所有導入。 - 執行主控機上的master_ip_failover --command=start腳本,激活新主庫的ip。 - 關閉新主庫的只讀,開啓可寫模式。 ** 恢復全部從庫(相似單獨恢復主庫的過程) - (併發)中繼補償,生成read_to_latest - (併發)將早生成的read_to_tail部分,拷貝到各個從庫,應用差別日誌,指向新主庫,啓動複製 - 新主庫執行reset slave * MHA(在線)主庫切換過程 sudo /usr/bin/masterha_master_switch --master_state=alive --conf=/etc/masterha/app1.cnf --new_master_host=192.168.128.130 --new_master_port=3309 --orig_mast\ er_is_new_slave ** 識別老主庫。 - 讀取配置MHA配置文件; - 鏈接並讀取全部的數據庫服務狀態; - (併發)鏈接全部從庫,看mysql服務是否在運行,若是機器都宕機了,那就終止本次切換。 - 遍歷每臺從庫,獲取全部能獲取的信息,好比:msyql服務版本號、是否開啓了gtid、是否開啓了log-bin、 是否只讀、複製相關係統變量和狀態變量。 - 統計服務器信息:離線服務器、在線服務器、在線從庫、失敗從庫等。 - 比較全部從庫的mysql服務版本,找出最老和最新的版本。 - 驗證當前真正的主庫是誰? - 統計在線服務器中的「非從庫」(not_slave)標記,只能爲1,不然終止本次切換過程。 - 根據從庫的指向來找出存在哪些主庫(支持3層複製結構(主-從-從的從))。 真正的主庫必須是在「線而且可寫」,若是沒有一臺主庫可寫或者存在兩臺可寫,那麼終止切換。 - 判斷本次切換是否支持gtid。 - 檢查全部在線從庫上是否有複製帳戶並有相應的REPLICATION SLAVE權限; - 必要時在老主庫上進行flush tables操做; - 從老主庫獲取「監視鎖」; - 從全部從庫獲取「切換鎖」; - 檢查全部在線從庫的複製健康情況; - 讀取當前的複製狀態; - 判斷是否有問題(IO、SQL線程是否在運行,數據延遲多久) ** 識別新主庫。 - 識別數據最新的從庫; - 比較master_log_file:read_master_log_pos。 - 選擇新主庫; - 識別優先從庫,在線的並帶有candidate_master標記。 - 識別應該忽略的從庫,帶有no_master標記、或者未開啓log_bin、或者mysql服務版本不是最老、與最新從庫相比數據延遲比較大。 - 選擇優先級依次爲:優先列表、最新從庫列表、全部從庫列表,但必定要排除忽略列表。 - 檢查新老主庫的複製過濾規則是否一致; - Binlog_Do_DB、Binlog_Ignore_DB、Replicate_Do_Table等。 ** 拒絕更新,防止腦裂。 - 調用master_ip_online_change腳本,stop子命令。新主庫上,設置爲只讀; 老主庫上,禁止會話級別的log_bin、優雅等待全部sql線程退出、設置爲只讀、 - 必要時,在老主庫,鎖住全部表,並檢查binlog是否已經中止前進。 binlog中止前進後,記下偏移位置。 ** 從新讀取全部在線從庫的運行狀態。 ** 新主庫從老主庫應用完全部的事件日誌。 - 新主庫上,執行master_pos_wait,而後記下新主庫binlog的file:pos。 - 調用master_ip_online_change腳本,start。新主庫上,設置爲只讀。 ** (併發)從庫應用完老主庫全部的事件日誌並指向新主庫。 - master_pos_wait - change_master_and_start_slave