高可用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
相关文章
相关标签/搜索