Yoshinori Matsunobu是个大神 现在在Facebook,直接看官方的介绍: 这里就不过多描述了,大家感兴趣可以直接去作者Github的wiki查看。github
https://github.com/yoshinorim/mha4mysql-manager
二、MHA的Failover原理
这里直接引用 “兰春”的部分文章内容,在此感谢作者分享MySQL Master High Available 源码篇
https://developer.aliyun.com/article/59233
2.1 非GTID复制模式Failover原理
Phase 1: Configuration Check Phaseinit_config(): 初始化配置MHA::ServerManager::init_binlog_server: 初始化binlog servercheck_settings() 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): 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.. * 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.. * save_master_binlog($dead_master); -> 如果dead master可以ssh,那么 b_1_1. save_master_binlog_internal: 用node节点save_binary_logs脚本拷贝相应binlog到manager diff_binary_log 生产差异binlog日志 b_1_2. file_copy: 将差异binlog拷贝到manager节点的 manager_workdir目录下 -> 如果dead master不可以ssh b_1_3. 那么差异日志就会丢失 Phase 3.3: Determining New Master Phase.. 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: #If preferred node is specified, one of active preferred nodes will be new master. #If the latest server behinds too much (i.e. stopping sql thread for online backups), we should not use it as a new master, but we should fetch relay log there #Even though preferred master is configured, it does not become a master if it's far behind 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(3.4): New Master Diff Log Generation Phase.. * recover_master_internal recover_relay_logs: 判断new master是否为最新的slave,如果不是,则生产差异relay logs,并发送给新master recover_master_internal: 将之前生产的dead master上的binlog传送给new master Phase 3.4: Master Log Apply Phase.. * apply_diff: a. wait_until_relay_log_applied: 直到new master完成所有relay log,否则一直等待 b. 判断Exec_Master_Log_Pos == Read_Master_Log_Pos, 如果不等,那么生产差异日志: 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差异日志 * 如果设置了master_ip_failover_script脚本,那么会执行这里面的脚本(一般用来漂移vip) * disable_read_only(): 允许new master可写Phase 4: Slaves Recovery Phase.. recover_slaves_internal Phase 4.1: Starting Parallel Slave Diff Log Generation Phase.. recover_all_slaves_relay_logs: 生成Slave与New Slave之间的差异日志,并将该日志拷贝到各Slave的工作目录下 Phase 4.2: Starting Parallel Slave Log Apply Phase.. * recover_slave: 对每个slave进行恢复,跟以上Phase 3.4: Master Log Apply Phase中的 apply_diff一样 * change_master_and_start_slave: 重新指向到new master,并且start slavePhase 5: New master cleanup phase.. reset_slave_on_new_master 在new master上执行reset slave all;
2.2 非GTID复制模式Failover原理
Phase 1: Configuration Check Phase init_config(): 初始化配置 MHA::ServerManager::init_binlog_server: 初始化binlog server check_settings() 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): 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.. * 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.. get_most_advanced_latest_slave(): 获取最新的slave c. select_new_master: 选举new master c_1. MHA::ServerManager::select_new_master: #If preferred node is specified, one of active preferred nodes will be new master. #If the latest server behinds too much (i.e. stopping sql thread for online backups), we should not use it as a new master, but we should fetch relay log there #Even though preferred master is configured, it does not become a master if it's far behind 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.. * 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 masterPhase 4: Slaves Recovery Phase.. Phase 4.1: Starting Slaves in parallel.. * recover_slaves_gtid_internal: change_master_and_start_slave: 因为master已经恢复,那么slave直接change master auto_pos=1 的模式就可以恢复 gtid_wait:用此等待同步全部追上Phase 5: New master cleanup phase.. reset_slave_on_new_master 在new master上执行reset slave all;
三、MHA安装
3.1MHA安装包简介
MHA由perl编写,分为两部分组件
一个是MHA Node,里面的组件: save_binary_logs 保存和复制master的二进制日志 apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的slave filter_mysqlbinlog 去除不必要的ROLLBACK事件(MHA已不再使用这个工具) purge_relay_logs 清除中继日志(不会阻塞SQL线程)一个是MHA Manager,里面包含很多组件: masterha_check_ssh 检查MHA的SSH配置状况 masterha_check_repl 检查MySQL复制状况 masterha_manger 启动MHA masterha_check_status 检测当前MHA运行状态 masterha_master_monitor 检测master是否宕机 masterha_master_switch 控制故障转移(自动或者手动) masterha_conf_host 添加或删除配置的server信息
MHA Node是要在每一个mysql复制组内的服务器上都要安装的,而MHA Manage可以安装在任意能和复制组通信的服务器上,当然也包括复制组内的某个机器。
3.2安装方式 RPM Or Source
RHEL/CentOS 使用rpm安装:
yum install perl-DBD-MySQLyum install perl-Config-Tinyyum install perl-Log-Dispatchyum install perl-Parallel-ForkManagerrpm -ivh mha4mysql-node-X.Y-0.noarch.rpmrpm -ivh mha4mysql-manager-X.Y-0.noarch.rpm
源码编译安装:
## Install DBD::mysql if not installed## Install dependent Perl modules# MHA Node (See above)# Config::Tiny## perl -MCPAN -e "install Config::Tiny"# Log::Dispatch## perl -MCPAN -e "install Log::Dispatch"# Parallel::ForkManager ## perl -MCPAN -e "install Parallel::ForkManager"## Installing MHA Node$ tar -zxf mha4mysql-node-X.Y.tar.gz$ perl Makefile.PL$ make$ sudo make install## Installing MHA Manager$ tar -zxf mha4mysql-manager-X.Y.tar.gz$ perl Makefile.PL$ make$ sudo make install
四、MHA脚本详解和定制开发4.1 脚本及配置简介
MHA配置分为三个等级:
Local/App/Global,参数作用域越来越大,masterha_default.conf中为Global级别配置,app*.conf为App级配置,app*.conf中的[server*]为Local级别配置,先有个大体概念,下面详细讲解每个文件。
masterha_default.conf说明:
masterha_default.conf是MHA的全局配置文件,所有公共配置都可以写到这里面 比如机器的账户 失败检测的心跳时间 master_ip_failover_script的路径等等,也就是所有的MHA进程都会共用这里的配置。
[server default]#监控ping_interval=3 #心跳检测时间间隔#shutdown_script="" #发生失败切换执行的关机脚本report_script=/home/SendEmail.sh #失败切换后实现消息通知的脚本#切换调用的脚本master_ip_failover_script= /etc/masterha/master_ip_failovermaster_ip_online_change_script= /etc/masterha/master_ip_online_change
App1.conf说明:
App1.conf,看了都会疑问,为啥是App1.conf呢?因为一个mha可以管理多个复制组,每个复制组都有自己独立的app.conf文件,所以是app1,app2,app3等
[server default]manager_log=/var/log/masterha/app1/app1.log #MHa log 日志文件位置manager_workdir=/var/log/masterha/app1 #MHA的工作空间master_binlog_dir=/data/mysql/mysql3306/logs # master的mysqlbinlog的位置user=mysqluser #mysql超级账户 为了切换过程中对mysql进行一些配置password=123456repl_password=123456 #mysql复制账户repl_user=repl_userssh_user=root #ssh的账户名[server1]check_repl_delay=0 #如果候选master有延迟的话,relay日志超过100m,failover切换不能成功,加上此参数后会忽略延迟日志大小。hostname=192.168.* #当前库的机器IPignore_fail=1 #如果这个节点挂了,mha将不可用,加上这个参数,slave挂了一样可以用[server2]check_repl_delay=0hostname=192.168.*ignore_fail=1[server3]check_repl_delay=0hostname=192.168.*ignore_fail=1[binlog1]hostname=192.168.* #binlog server服务器的ipmaster_binlog_dir=/data/mysql/mysql3306/logs/ #binlog文件所在的路径no_master=1 #从不将这台主机转换为master
这里重点说下这个[binlog1]节点,使用0.56之前的版本是没有这个参数的,这个是为了支持GTID的,具体可以参考mysql5.6基于GTID模式之高可用架构搭建-MHA(mha0.56),MHA failover GTID 专题等,这里说下,gtid的补偿日志机制跟非gtid是有所不同的,所以配置[binlog1]是必须的,我这里直接配置的主服务的ip并且binlog存放的物理目录直接指向了实际msater mysql的binlog文件所在的目录下了,即将master当做了binlog server,这种配置方式是可行的,但是一旦主库所在的服务器down机或者无法通过ssh连接了,差异日志是获取不到也就是无法补偿到新的master上的。
还有很多可配置的参数,具体可以参考作者Github的wiki:
MHA Parameters
https://github.com/yoshinorim/mha4mysql-manager/wiki/Parameters
master_ip_failover失败切换脚本:
MHA做高可用需要用到虚拟vip,以实现主库宕机后自动切换到新主上,而业务无感知,vip的管理方案有两种:一种是脚本管理vip,也就是mha推荐的;另一种是Keepalived,看了很多文章和根据实践,推荐使用脚本管理vip,避免发生脑裂。#!/usr/bin/env perluse strict;use warnings FATAL => 'all';use Getopt::Long;my ( $command, $ssh_user, $orig_master_host, $orig_master_ip, $orig_master_port, $new_master_host, $new_master_ip, $new_master_port);my $gateway = '192.168.11.1'; ---这个是网关地址my $vip = '192.168.11.251/24'; ---vip地址my $onlyvip = '192.168.11.251'; vipmy $key = '0'; ---网卡的别名编号my $eth = 'ens32'; --网卡名称my $ssh_start_vip = "/sbin/ifconfig $eth:$key $vip up;/sbin/arping -I $eth -c 3 -s $onlyvip $gateway";my $ssh_stop_vip = "/sbin/ifconfig $eth:$key down";GetOptions( 'command=s' => \$command, 'ssh_user=s' => \$ssh_user, 'orig_master_host=s' => \$orig_master_host, 'orig_master_ip=s' => \$orig_master_ip, 'orig_master_port=i' => \$orig_master_port, 'new_master_host=s' => \$new_master_host, 'new_master_ip=s' => \$new_master_ip, 'new_master_port=i' => \$new_master_port,);exit &main();sub main { print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n"; print "\n\nIN Master_ip_failover_command:====$command===\n\n"; if ( $command eq "stop" || $command eq "stopssh" ) { my $exit_code = 1; eval { print "Disabling the VIP on old master: $orig_master_host \n"; &stop_vip(); $exit_code = 0; }; if ($@) { warn "Got Error: $@\n"; exit $exit_code; } exit $exit_code; } elsif ( $command eq "start" ) { my $exit_code = 10; eval { print "Enabling the VIP - $vip on the new master - $new_master_host \n"; &start_vip(); $exit_code = 0; }; if ($@) { warn $@; exit $exit_code; } exit $exit_code; } elsif ( $command eq "status" ) { print "Checking the Status of the script.. OK \n"; exit 0; } else { &usage(); exit 1; }}sub start_vip() { `ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;}sub stop_vip() { return 0 unless ($ssh_user); `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;}sub usage { print "Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";}
重点关注下这部分参数:
my $gateway = '192.168.11.1'; ---这个是网关地址my $vip = '192.168.11.251/24'; ---vip地址,带网络号my $onlyvip = '192.168.11.251'; vipmy $key = '0'; ---网卡的别名编号my $eth = 'ens32'; --网卡名称my $ssh_start_vip = "/sbin/ifconfig $eth:$key $vip up;/sbin/arping -I $eth -c 3 -s $onlyvip $gateway";my $ssh_stop_vip = "/sbin/ifconfig $eth:$key down";
gateway及eth : 这里网关和网卡名字不用说了, 直接用 ip addr就可以查询到本地网卡的名称是啥,直接看下网卡配置就知道网关地址是啥,vip这个就是在同一个网段。
onlyvip ,vip:192.168.11.251/24后面的24是啥呢?直接去用ip addr,原始的ip后面是多少,vip后面就保持一致就可以了
具体想深入了解的可以参考:
ip addr详解
https://www.cnblogs.com/wqbin/p/11065587.html
/sbin/arping -I $eth -c 3 -s $onlyvip $gateway":再说下这里 这句话很多网上的脚本都没有,为啥要有?啥作用?是广播vip的 ,切换完成后vip在被绑定的机器上是立刻生效的,但是同局域网内的其他的机器是不会立刻被告知VIP发生了切换了的,所以就需要用arping广播出去,其他机器会立刻感知到VIP执向了新的机器。
五、运行MHA 5.1 检测ssh[root@nn ~]# masterha_check_ssh --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.confFri Jan 11 10:11:16 2019 - [info] Reading default configuration from /etc/masterha/masterha_default.conf..Fri Jan 11 10:11:16 2019 - [info] Reading application default configuration from /etc/masterha/app1.conf..Fri Jan 11 10:11:16 2019 - [info] Reading server configuration from /etc/masterha/app1.conf..Fri Jan 11 10:11:16 2019 - [info] Starting SSH connection tests.....#出现一下文本即为检测结果为健康状态Fri Jan 11 10:11:18 2019 - [info] All SSH connection tests passed successfully.You have new mail in /var/spool/mail/root
5.2 检测复制组健康状态
[root@nn ~]# masterha_check_ssh --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.confSun Apr 20 18:46:08 2014 - [info] Checking replication health on 192.168.0.60..Sun Apr 20 18:46:08 2014 - [info] ok.Sun Apr 20 18:46:08 2014 - [info] Checking replication health on 192.168.0.70..Sun Apr 20 18:46:08 2014 - [info] ok.Sun Apr 20 18:46:08 2014 - [warning] master_ip_failover_script is not defined.Sun Apr 20 18:46:08 2014 - [warning] shutdown_script is not defined.Sun Apr 20 18:46:08 2014 - [info] Got exit code 0 (Not master dead).#出现一下文本即为检测结果为健康状态MySQL Replication Health is OK.
5.3启动 masterha_manager
masterha_manager --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf --remove_dead_master_conf --ignore_last_failover --ignore_binlog_server_error > /var/log/masterha/app1/app1.log 2>&1 &
说明:
--globa
l_
conf 为全局配置文件路径
--conf 当前复制组对应的配置文件
--remove_dead_master_conf 失败切换后移除原master配置
--ignore_last_failover 忽略上次失败切换结果
--ignore_binlog_server_error 忽略binlog server错误
5.4 检测masterha_manager运行状态
[root@libothree ~]# masterha_check_status --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
5.5 停止masterha_manager
masterha_stop --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf
六、MHA运行监控脚本
loghost='10.1.1.1' #日志存储机器loguser='mysqluser'logpwd='pwd'host='10.2.2.2' #MHA所在的机器statuss=($(masterha_check_status --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1.conf))strs=''for data in ${statuss[@]}do strs=${strs}" "${data}done echo ${strs} mysql -h${loghost} -P3306 -u${loguser} -p${logpwd} slaveinfo -e "INSERT INTO mhaststus(mark,host) VALUES ('${strs}','${host}')"