高可用mysql之MHA源碼剖析

* 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
相關文章
相關標籤/搜索