在讲MHA选择 master的代码中,我们必须把维护的四个数组的来龙去脉讲清楚
成都创新互联公司始终坚持【策划先行,效果至上】的经营理念,通过多达十余年累计超上千家客户的网站建设总结了一套系统有效的推广解决方案,现已广泛运用于各行各业的客户,其中包括:成都玻璃钢坐凳等企业,备受客户赞许。
server不是 master,且从库正常, latest数组中的 server有足够的中继日志恢复这个落后的从库 (追上主库 ),则放入这个 Alive_slaves的数组中 (此段代码在 ServerManager.pm: init_servers函数 )
if ( $server->{dead} ) { $self->add_dead_server($server); } elsif ( $server->{unmanaged} ) { $self->add_unmanaged_slave($server); } #不是dead或者unmanaged就加入alive_server数组,如果show slave status 不是返回0E0,且这个server不是原来的主库,并且sql线程无误且可以用中继日志来恢复,就加入alive_slave数据,否则加入failed——slave数组 else { $self->add_alive_server($server); if ( $server->{not_slave} eq '0' && !$server->{orig_master} ) { if ( !$server->is_sql_thread_error() && !$server->{lack_relay_log} ) { $self->add_alive_slave($server); } else { $self->add_failed_slave($server); } } }
在 alive_slaves数组中选取 relaylog最新的 server,这个数组如果有多个 server,则 server的 Read_master_log_pos,master_log_file一定相等(此段代码在 ServerManager.pm: identify_latest_slaves函数)
my @slaves = $self->get_alive_slaves(); my @latest = (); foreach (@slaves) { my $a = $latest[0]{Master_Log_File}; my $b = $latest[0]{Read_Master_Log_Pos}; if ( #find_oldest=0,即我们取的最全relaylog的slave,至于这里为什么是数组,是因为有最新的relaylog的不只有一个,可能有多个((即数组里边边的slave,具有一样的Read_Master_Log_ Pos位置)) !$find_oldest && ( ( !$a && !defined($b) ) || ( $_->{Master_Log_File} gt $latest[0]{Master_Log_File} ) || ( ( $_->{Master_Log_File} ge $latest[0]{Master_Log_File} ) && $_->{Read_Master_Log_Pos} > $latest[0]{Read_Master_Log_Pos} ) ) ) { @latest = (); push( @latest, $_ ); }
这个无需多解释,就是MHA配置文件中配置了 candidate_master的值,这个可以大于 1哦
1) 检测有故障的server
2) MHA 配置文件设置了 no_master 的 server
3)log_bin 没有打开的server
4) 版本不兼容的server (高版本复制到低版本是没问题的,但是如果低版本的选为为主库,嘿嘿)
5) 复制落后太多的server
(1) 指定主库切换的,优先级最高(通常这是在手动切换)
(2) 如果server 在 latest 数组中,且在 perf 数组中,则优先返回
(3) 如果server 在 alive_servers 数组中,且在 perf 数组中,则优先返回
(4) 如果server 在 lastest 中,则优先返回
(5) 如果server 在 alive_servers 中,则返回
(6) 否则选举失败
这里优先级为1->6,具体实现在 (ServerManager.pm: select_new_master)
sub select_new_master { my $self = shift; my $prio_new_master_host = shift; my $prio_new_master_port = shift; my $check_replication_delay = shift; $check_replication_delay = 1 if ( !defined($check_replication_delay) ); my $log = $self->{logger}; my @latest = $self->get_latest_slaves(); my @slaves = $self->get_alive_slaves(); my @pref = $self->get_candidate_masters(); my @bad = $self->get_bad_candidate_masters( $latest[0], $check_replication_delay ); #切换指定了master,即优先级最高的 if ( $prio_new_master_host && $prio_new_master_port ) { my $new_master = $self->get_alive_server_by_hostport( $prio_new_master_host, $prio_new_master_port ); if ($new_master) { my $a = $self->get_server_from_by_id( \@bad, $new_master->{id} ); unless ($a) { $log->info("$prio_new_master_host can be new master."); return $new_master; } else { $log->error("$prio_new_master_host is bad as a new master!"); return; } } else { $log->error("$prio_new_master_host is not alive!"); return; } } $log->info("Searching new master from slaves.."); $log->info(" Candidate masters from the configuration file:"); $self->print_servers( \@pref ); $log->info(" Non-candidate masters:"); $self->print_servers( \@bad ); #如果perf(candidate_master没设置)以及没有不符合(主从延迟,版本等)的slave,并且lastest[0]设置有优先级的话,就返回 return $latest[0] if ( $#pref < 0 && $#bad < 0 && $latest[0]->{latest_priority} ); #如果设置了优先级,则从lastest数组中选择是canidate_master的,有就返回(隐含lastest[0]优先,如果lastest[0]同时是canidate_master,那肯定是优先返回的) #latest_priority默认设置为1 if ( $latest[0]->{latest_priority} ) { $log->info( " Searching from candidate_master slaves which have received the latest relay log events.." ) if ( $#pref >= 0 ); foreach my $h (@latest) { foreach my $p (@pref) { if ( $h->{id} eq $p->{id} ) { return $h if ( !$self->get_server_from_by_id( \@bad, $p->{id} ) ); } } } $log->info(" Not found.") if ( $#pref >= 0 ); } #new master is not latest #这里选择的是candidate_master,单不是latest数组中的master $log->info(" Searching from all candidate_master slaves..") if ( $#pref >= 0 ); foreach my $s (@slaves) { foreach my $p (@pref) { if ( $s->{id} eq $p->{id} ) { my $a = $self->get_server_from_by_id( \@bad, $p->{id} ); return $s unless ($a); } } } $log->info(" Not found.") if ( $#pref >= 0 ); #其次是优先在lastest数组中,但不在candidate_master中的 if ( $latest[0]->{latest_priority} ) { $log->info( " Searching from all slaves which have received the latest relay log events.." ); foreach my $h (@latest) { my $a = $self->get_server_from_by_id( \@bad, $h->{id} ); return $h unless ($a); } $log->info(" Not found."); } # none of latest servers can not be a master $log->info(" Searching from all slaves.."); foreach my $s (@slaves) { my $a = $self->get_server_from_by_id( \@bad, $s->{id} ); return $s unless ($a); } $log->info(" Not found."); return; }