一、MHA在Binlog模式下切换过程解析
Phase 1: Configuration Check Phase
- init_config():初始化配置
 - MHA::ServerManager::init_binlog_server:初始化binlog server
 - check_settings():检查相关配置
 
| 
					 1 2 3 4 5 6 7 8  | 
						a. check_node_version()                                                        #查看MHA的版本; b. connect_all_and_read_server_status()                                        #检测确认各个Node节点MySQL是否可以连接; c. get_dead_servers(),get_alive_servers(),get_alive_slaves()                   #再次检测一次node节点的状态; d. print_dead_servers()                                                        #挂掉的master是否是当前的master; e. MHA::DBHelper::check_connection_fast_util                                   #快速判断dead server,是否真的挂了,如果ping_type=insert,不会double check; f. MHA::NodeUtil::drop_file_if($_failover_error_file|$_failover_complete_file) #检测上次的failover文件; g. ....                                                                        #如果上次failover的时间在8小时以内,那么这次就不会failover,除非配置了额外的参数; h. start_sql_threads_if()                                                      #查看所有slave的Slave_SQL_Running是否为Yes,若不是则启动SQL thread;  | 
					
- is_gtid_auto_pos_enabled():判断是否是GTID模式
 
Phase 2: Dead Master Shutdown Phase..
- force_shutdown($dead_master)
 
| 
					 1 2 3 4  | 
						a. stop_io_thread()                        #停止所有slave的IO_thread; b. force_shutdown_internal($dead_master)   b_1. master_ip_failover_script           #如果有这个脚本,则执行里面的逻辑(比如:切换vip);   b_2. shutdown_script                     #如果有这个脚本,则执行里面的逻辑(比如:强制Master shutdown);  | 
					
Phase 3: Master Recovery Phase..
- Phase 3.1: Getting Latest Slaves Phase..
 
| 
					 1 2 3 4  | 
						* check_set_latest_slaves()   a. read_slave_status()                #获取所有show slave status信息;   b. identify_latest_slaves()           #找到延迟最小的slave是哪个,并且会记录复制到主二进制日志的文件和位置;   c. identify_oldest_slaves()           #找到延迟最大的slave是哪个;  | 
					
- Phase 3.2: Saving Dead Master’s Binlog Phase..
 
| 
					 1 2 3 4 5 6  | 
						* save_master_binlog($dead_master);   -> 如果dead master可以ssh,那么;     b_1_1. save_master_binlog_internal  #用node节点save_binary_logs脚本拷贝相应binlog到manager;       diff_binary_log                   #根据Phase3.1获取的最新slave信息,在Master上利用mysqlbinlog生产差异binlog日志;     b_1_2. file_copy                    #将差异binlog拷贝到manager节点的manager_workdir目录下;   -> 如果dead master不可以ssh,那么差异日志就会丢失;  | 
					
- Phase 3.3: Determining New Master Phase..
 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  | 
						b. 如果GTID auto_pos没有打开,调用find_latest_base_slave()   b_1. find_latest_base_slave_internal: 寻找拥有所有relay-log的最新slave,如果没有,则failover失败;   b_1_1. find_slave_with_all_relay_logs:   b_1_1_1. apply_diff_relay_logs: 查看最新的slave是否有其他slave缺失的relay-log; c. select_new_master: 选举new master   c_1. MHA::ServerManager::select_new_master     get_candidate_masters(): 获取配置中候选节点;     get_bad_candidate_masters(): 以下条件不能成为候选master;     # dead server     # no_master >= 1     # log_bin=0     # oldest_major_version=0     # check_slave_delay: 检查是否延迟非常厉害(可以通过设置no_check_delay忽略)   {Exec_Master_Log_Pos} + 100000000只要binlog position不超过100000000就行;   # 选举流程:先看candidate_master,然后找latest slave, 然后再随机挑选;  | 
					
- Phase 3.3: New Master Diff Log Generation Phase..
 
| 
					 1 2 3  | 
						* recover_master_internal recover_relay_logs       #判断new master是否为最新的slave,如果不是,则跟laste slave生产差异relay logs,然后manager使用scp发送给new master; recover_master_internal  #manager将之前生产的dead master上的binlog传送给new master;  | 
					
- Phase 3.4: Master Log Apply Phase..
 
| 
					 1 2 3 4 5 6 7 8 9 10 11  | 
						* apply_diff   a. wait_until_relay_log_applied: 直到new master完成所有relay log,否则一直等待;   b. 判断Exec_Master_Log_Pos == Read_Master_Log_Pos,如果不等,那么生产差异binlog日志;   save_binary_logs --command=save   c. apply_diff_relay_logs --command=apply:对new master进行恢复。     c_1. exec_diff:Exec_Master_Log_Pos和Read_Master_Log_Pos的差异日志。     c_2. read_diff:new master与lastest slave的relay log的差异日志。     c_3. binlog_diff:lastest slave与daed master之间的binlog差异日志。 * 获取new master binlog的文件和位置; * 如果设置了master_ip_failover_script脚本,那么会执行这里面的脚本(一般用来漂移vip); * disable_read_only(): 允许new master可写;  | 
					
Phase 4: Slaves Recovery Phase..
- Phase 4.1: Starting Parallel Slave Diff Log Generation Phase..
 
| 
					 1  | 
						* recover_all_slaves_relay_logs     #生成Slave与New Slave之间的差异日志,并将该日志拷贝到各Slave的工作目录下;  | 
					
- Phase 4.2: Starting Parallel Slave Log Apply Phase..
 
| 
					 1 2  | 
						* recover_slave                     #对每个slave进行恢复,跟以上Phase 3.4: Master Log Apply Phase中的apply_diff一样; * change_master_and_start_slave     #各个slave执行reset slave并重新change master到new master,并且start slave;  | 
					
Phase 5: New master cleanup phase..
| 
					 1  | 
						reset_slave_on_new_master           #在new master上执行reset slave all;  | 
					
整个过程核心切换逻辑简化后如下描述:
Phase 1:配置文件检查
Phase 2:非存活Master关闭服务
Phase 3:Master恢复
Phase 3.1:获取与Master延迟最小的Slave节点和延迟最大的Slave节点
Phase 3.2:生成Master与延迟最小的Slave节点的差异binlog并保存到manager节点
Phase 3.3:找出新的New Master,并且在延迟最小的Slave的Relay log中寻找延迟最小Slave与延迟最大Slave之间差异的binlog日志是否存在
Phase 3.3:如果New Master不是最新的Slave节点,那么需要从最新Slave的Relay log中生成它们之间的差异Relay log
Phase 3.4:New Master恢复差异Relay log和差异binlog日志,随后获取Master binlog位点信息
Phase 4:Slaves恢复
Phase 4.1:多线程生成延迟最小的Slave节点与其他一个或多个Slave差异Relay log
Phase 4.2:多线程恢复Slave节点与延迟最小的Slave之间的差异Relay log,并且恢复manager节点保存的差异binlog,然后change master到NEW MASTER节点
Phase 5:New Master清理Slave信息,并删除掉MHA配置文件中的选主信息防止误操作等
二、MHA在GTID模式下切换过程解析
Phase 1: Configuration Check Phase
- init_config(): 初始化配置。
 - MHA::ServerManager::init_binlog_server: 初始化binlog server。
 - check_settings()
 
| 
					 1 2 3 4 5 6 7 8  | 
						a. check_node_version()                                                        #查看MHA的版本; b. connect_all_and_read_server_status()                                        #检测确认各个Node节点MySQL是否可以连接; c. get_dead_servers(),get_alive_servers(),get_alive_slaves()                   #再次检测一次node节点的状态; d. print_dead_servers()                                                        #是否挂掉的master是否是当前的master; e. MHA::DBHelper::check_connection_fast_util                                   #快速判断dead server,是否真的挂了,如果ping_type=insert,不会double check; f. MHA::NodeUtil::drop_file_if($_failover_error_file|$_failover_complete_file) #检测上次的failover文件; g. ...                                                                         #如果上次failover的时间在8小时以内,那么这次就不会failover,除非配置了额外的参数; h. start_sql_threads_if()                                                      #查看所有slave的Slave_SQL_Running是否为Yes,若不是则启动SQL thread;  | 
					
- is_gtid_auto_pos_enabled():判断是否是GTID模式。
 
Phase 2: Dead Master Shutdown Phase completed.
- force_shutdown($dead_master):
 
| 
					 1 2 3 4  | 
						a. stop_io_thread()                         #stop所有slave的IO_thread; b. force_shutdown_internal($dead_master):   b_1. master_ip_failover_script            #如果有这个脚本,则执行里面的逻辑(比如:切换vip);   b_2. shutdown_script                      #如果有这个脚本,则执行里面的逻辑(比如:Power off服务器);  | 
					
Phase 3: Master Recovery Phase..
- Phase 3.1: Getting Latest Slaves Phase..
 
| 
					 1 2 3 4  | 
						* check_set_latest_slaves()   a. read_slave_status()       #获取所有show slave status信息;   b. identify_latest_slaves()  #找到延迟最小的slave是哪个;   c. identify_oldest_slaves()  #找到延迟最大的slave是哪个;  | 
					
- Phase 3.2: Saving Dead Master’s Binlog Phase.. (GTID 模式下没有这一步)
 - Phase 3.3: Determining New Master Phase..
 
| 
					 1 2 3 4 5 6 7 8 9 10 11  | 
						get_most_advanced_latest_slave()     #获取最新的slave; c. select_new_master                 #选举new master;     c_1. MHA::ServerManager::select_new_master:         get_candidate_masters()       #获取配置中候选节点;        get_bad_candidate_masters()   #以下条件不能成为候选master;            # dead server            # no_master >= 1            # log_bin=0            # oldest_major_version=0            # check_slave_delay       #检查是否延迟非常厉害(可以通过设置no_check_delay忽略);{Exec_Master_Log_Pos} + 100000000只要binlog position不超过100000000就行;        # 选举流程:先看candidate_master,然后找latest slave,然后再随机挑选;  | 
					
- Phase 3.3: New Master Recovery Phase..
 
| 
					 1 2 3 4 5 6 7 8 9 10  | 
						* recover_master_gtid_internal:   wait_until_relay_log_applied                            #候选master等待所有relay-log都应用完;       # 如果候选master不是最新的slave:       $latest_slave->wait_until_relay_log_applied($log)   #最新的slave应用完所有的relay-log;       change_master_and_start_slave                       #让候选master同步到latest master,追上latest slave;                                                           #获取候选master此时此刻的日志信息,以便后面切换;       # 如果候选master是最新的slave:       # 获取候选master此时此刻的日志信息,以便后面切换;   save_from_binlog_server:                                #如果配置了binlog server,那么在binlogsever能连的情况下,将binlog拷贝到Manager,并生成差异日志diff_binlog(save_binary_logs --command=save);   apply_binlog_to_master(Applying differential binlog):   #应用差异的binlog到new master;  | 
					
Phase 4: Slaves Recovery Phase..
- Phase 4.1: Starting Slaves in parallel..
 
| 
					 1 2 3  | 
						* recover_slaves_gtid_internal:   change_master_and_start_slave  #因为master已经恢复,那么slave直接change master auto_pos=1的模式就可以恢复;   gtid_wait                      #用此等待同步全部追上;  | 
					
Phase 5: New master cleanup phase..
| 
					 1  | 
						* reset_slave_on_new_master      #在new master上执行reset slave all;  | 
					
转载(有修改)
http://keithlan.github.io/2016/08/18/mha_source
https://github.com/yoshinorim/mha4mysql-manager/blob/master/lib/MHA/MasterFailover.pm


