简介

大家都知道,任何线上环境,都必须搭载高可用架构,是web的,也要是数据库的,严格来说更是整个架构的高可用.

mysql作为时下比较热的数据库,高可用架构更加需求大.不过,以前老旧那一套已经不合时宜,现在用的比较多的就是MHA和PXC了.

PXC的优势是做到同写同回滚,达到数据高度一致性,通过一些程序和代码来做第三方分发,可以做到一定程度的读写分离,是个相当不错的高可用解决方案,不过对网络要求比较高,配置也略复杂一些,最好是同一个机房里面做,不过这并不是本文重点,后面找时间再写相关的文章.

本文要说的就是MHA,版本是0.56,先介绍一下,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。

该软件由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。MHA Manager可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave节点上。MHA Node运行在每台MySQL服务器上,MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他的slave重新指向新的master。整个故障转移过程对应用程序完全透明。

在MHA自动故障切换过程中,MHA试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过ssh访问,MHA没法保存二进制日志,只进行故障转移而丢失了最新的数据。使用MySQL 5.5版本以上的半同步复制功能,可以大大降低数据丢失的风险。MHA可以与半同步复制结合起来。如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性,还有一种方法就是binlog server,因为binlog server不用回写mysql数据库,速度往往比较快,丢数据的风险也低很多,怎么搭建binlog server可以看我另一篇文章。

我们来看看mha的工作原理:

(1)从宕机崩溃的master保存二进制日志事件(binlog events)(包括binlog server);

(2)识别含有最新更新的slave;

(3)应用差异的中继日志(relay log)到其他的slave;

(4)应用从master保存的二进制日志事件(binlog events);

(5)提升一个slave为新的master;

(6)使其他的slave连接新的master进行复制;


MHA软件由两部分组成,Manager工具包和Node工具包,具体的说明如下。

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信息

Node工具包(这些工具通常由MHA Manager的脚本触发,无需人为操作)主要包括以下几个工具:

save_binary_logs                    保存和复制master的二进制日志

apply_diff_relay_logs   识别差异的中继日志事件并将其差异的事件应用于其他的slave

filter_mysqlbinlog    去除不必要的ROLLBACK事件(MHA已不再使用这个工具)

purge_relay_logs                    清除中继日志(不会阻塞SQL线程)


然后强调一些可能造成误区的问题:

第一,MHA的核心功能是为了解决数据库集群的数据一致性,原则上不会去做其他故障切换的事情,其他额外功能(例如切换vip和发报警邮件),是要通过第三方软件(例如:keepalived)或者是脚本来实现的,要区分清楚,所以配置上是可以忽略警告来做的,因为不影响MHA核心功能,不是必须的.

第二,MHA每次故障切换完都会退出,原主库起来后还需要手动去补全数据和操作变成从库,然后从新开启MHA来使用,开启后再通过手动切换回原主库,手动切换不会退出MHA,主要看你第三方软件和脚本的定义,不过切换还是需要谨慎一些.


安装

打了那么多字,现在来转回正题,先说怎么安装的问题.

安装前要先做一个主从结构,至于怎么做主从我就不在这里再演示了,有兴趣的可以看我另一篇文章,在线做主从,其实很简单.

装完主从就开始装MHA了,我们把node端装到主库,把Manager装在从库,这样安装的目的也显而易见,当你主库服务器down机了,Manager都被强制关闭了,你还怎么切是吧,所以必须是装在从库.

#我们依然先安装一个epel库
rpm -Uvh http://mirrors.kernel.org/fedora-epel/6/i386/epel-release-6-8.noarch.rpm
#yum一些依赖包
yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-YAML-Tiny perl-PAR-Dist perl-Module-ScanDeps perl-Module-CoreList perl-Module-Build perl-CPAN perl-YAML perl-CPANPLUS perl-File-Remove perl-Module-Install
#ubuntu系统方式
apt-get install -y libdbd-mysql-perl libconfig-tiny-perl liblog-dispatch-perl libparallel-forkmanager-perl libmodule-install-perl

然后下载MHA-0.56,想要原版,那就要去翻 墙下载,

https://code.google.com/p/mysql-master-ha/wiki/Downloads

我已经将MHA-0.56上传到51cto的软件库,也可以在里面下载

http://down.51cto.com/data/2227241

=============分割线开始===================================

与时俱进,下面是MHA-0.57,支持mysql5.7,这是原作者最后一个版本,作者去了美国任职后就宣布不更新了.

http://down.51cto.com/data/2300275

===============分割线结束=================================

有RPM和源码版,看你喜欢,我比较懒,所以我用RPM版,不过要注意,RPM版是rhel和centos专用的.

#安装Manager前还得必须先装node,比较奇葩.那么干脆都装上去.
rpm -ivh mha4mysql-node-0.56-0.el6.noarch.rpm
rpm -ivh mha4mysql-manager-0.56-0.el6.noarch.rpm

只要依赖库没问题,安装就不会有问题,非常简单.如果你是要装源码版,就麻烦一点,功能是一样的,而且还多一些配置文件模板给你用.

如果上述yum安装和apt安装也不能正常安装上perl-Module-Install,则下面的编译mha源码包就会失败,所以我们需要另觅安装方法

#用cpan来安装是万能方法,而且保证是最新版,但是比较慢,因为连去外国服务器了
yum install -y perl-CPAN
#ubuntu系统方式
apt-get install -y perl-modules
#然后输入下面命令就可以安装上perl-Module-Install
cpan Module::Install

------------------------------------------分割线开始--------------------------------------------------

但是有时候,难免很悲催,yum和apt都是闭源,而且连不上外网怎么办?抱歉,只能一个个依赖包安装好,你才能装好perl-Module-Install,然后才能编译mha源码包

不过虽然神关闭了一扇门,但是并没有把我们夹到,庆幸现在很多rpm包公有资源,最出名的莫过于下面这个.

http://rpmfind.net/linux/rpm2html/search.php

我们把有需要的依赖包RPM下载下来,再上传到服务器,就可以正常安装好perl-Module-Install了.

例如,我这边内网yum源就是缺这两个依赖包

perl-File-Remove

perl-Module-ScanDeps

然后我在上面的地址找到了,然后安装完,就可以了

rpm -ivh perl-File-Remove-1.52-6.el7.noarch.rpm
rpm -ivh perl-Module-ScanDeps-1.10-3.el7.noarch.rpm
rpm -ivh perl-Module-Install-1.06-4.el7.noarch.rpm

这就可以了

----------------------------------------分割线结束----------------------------------------------------

最后就可以安装mha了

#安装node端
unzip mha4mysql-node-master-201604.zip
cd mha4mysql-node-master
perl Makefile.PL
make
make install
#安装manger端
unzip mha4mysql-manager-master-201604.zip 
cd mha4mysql-manager-master
perl Makefile.PL
make
make install

然后我们看看安装情况,因为严格来说MHA是一套perl脚本命令操作的,所以安装的本质其实就是把命令执行文件解压,

#ll /usr/local/bin/
-r-xr-xr-x 1 root root 15498 Apr 20 10:58 apply_diff_relay_logs
-r-xr-xr-x 1 root root  4807 Apr 20 10:58 filter_mysqlbinlog
-r-xr-xr-x 1 root root  1995 Apr 20 11:33 masterha_check_repl
-r-xr-xr-x 1 root root  1779 Apr 20 11:33 masterha_check_ssh
-r-xr-xr-x 1 root root  1865 Apr 20 11:33 masterha_check_status
-r-xr-xr-x 1 root root  3201 Apr 20 11:33 masterha_conf_host
-r-xr-xr-x 1 root root  2517 Apr 20 11:33 masterha_manager
-r-xr-xr-x 1 root root  2165 Apr 20 11:33 masterha_master_monitor
-r-xr-xr-x 1 root root  2373 Apr 20 11:33 masterha_master_switch
-r-xr-xr-x 1 root root  3749 Apr 20 11:33 masterha_secondary_check
-r-xr-xr-x 1 root root  1739 Apr 20 11:33 masterha_stop
-r-xr-xr-x 1 root root  7401 Apr 20 10:58 purge_relay_logs
-r-xr-xr-x 1 root root  7263 Apr 20 10:58 save_binary_logs

到这里,MHA就算安装完成了,仅仅只是安装完成.


配置MHA

MHA在配置方面有点坑,为什么这么说了,原因是很多配置并没有明示,需要自己去摸索和借鉴参考,如果你是用rpm安装的,甚至没有配置模板,全部都要自己写,相当蛋疼,而且虽然说支持第三方应用和脚本,也是需要额外配置,例如网上有很多借用keepalived来切换vip的方法的文档,我就不多说了,这里我说的是全部都用脚本来实现的切换,包括vip,不使用其他第三方应用.

首先我们来做些前期工作,先完成一个完整的mysql主从架构并修改一些配置和手动加上vip,还有ssh的免密钥处理(复制binlog或relaylog用),MHA第一次启动不会自己绑定VIP,所以需要自己来做,不用很复杂,一条命令就可以了,当然了,你可以更复杂一些,也更严谨一些.

ifconfig eth1:1 10.0.2.101/24

这个时候你的应用或客户端就可以通过这个vip来连接数据库了,当然了,这是内网IP.


1.一些mysql的前期工作:

怎么完成一个完整的mysql主从架构,大家可以看我另一篇文章,我不想文章篇幅太长就不多说了,这里只说几个重点.

第一,数据库的复制和管理的授权要做好,不只是当前的主从授权,也要考虑到切换后的主从授权,因为故障切换后,现在的主就是切换后的从,如果没有授权,就写不进数据了,特别要注意三台,四台组成的架构.

第二,从库尽量设置成只读,避免某些应用或客户端误写入数据,特别是切换后特别容易出现这种情况.这个可以手动更改,也是比较方便的,切换的时候mha也会自动设置回可写.

mysql -uroot -p'******' -e "set global read_only=1"

第三,把relay log的自动清除设置关闭了,因为在多台数据库实例结合的MHA架构中,MHA会主动校对那一个实例的binlog和relay log比较新,然后把这些最新的数据应用到候选主库上,然后再切换完成.

mysql -uroot -p'******' -e "set global relay_log_purge=0"

    当然了,关闭了之后,随之而来的就是relay log会不断增长,导致最终撑爆硬盘,这是不允许的,所以我们需要有个清理机制,最后就有了利用脚本加上计划任务定期清理的方法.

主要方法是利用MHA的自带命令:

/usr/bin/purge_relay_logs

参数说明:

--user mysql    用户名

--password mysql    密码

--port    端口号

--workdir    指定创建relay log的硬链接的位置,默认是/var/tmp,由于系统不同分区创建硬链接文件会失败,故需要执行硬链接具体位置,成功执行脚本后,硬链接的中继日志文件被删除

--disable_relay_log_purge    默认情况下,如果relay_log_purge=1,脚本会什么都不清理,自动退出,通过设定这个参数,当relay_log_purge=1的情况下会将relay_log_purge设置为0。清理relay log之后,最后将参数设置为OFF。

然后脚本如下:

#新建脚本
vim purge_relay_log.sh
#!/bin/bash
user=root
passwd=123123
port=3306
log_dir='/var/log'
work_dir='/data/mysql/data/'
purge='/usr/local/bin/purge_relay_logs'
if [ ! -d $log_dir ]
then
   mkdir $log_dir -p
fi
$purge --user=$user --password=$passwd --disable_relay_log_purge --port=$port --workdir=$work_dir >> $log_dir/purge_relay_logs.log 2>&1

最后加入到计划任务:

crontab -e
0 4 * * * /bin/bash /root/purge_relay_log.sh

好了,mysql的准备工作完成了,继续走下去.


2.创建服务器免秘钥登陆

设置MHA架构间的SSH密钥,使其免密码登陆,刚才我也有说过了,MHA会通过校对binlog和relay log,将最新的数据放到候选主库,这期间就必然有数据传输的需求,所以也就需要SSH的免密码登陆了.

方法很简单,网上资料多如牛毛,我就简单说一下就算了.

先使用命令:

#进入秘钥目录
cd /root/.ssh/
#输入命令创建秘钥
ssh-keygen

一路回车就好了,不用想太多,然后在/root/.ssh/下面得到两个文件id_rs,id_rsa.pub,

然后生成信任文件:

#进入目录
cd /root/.ssh/
#转件秘钥认证文件
cat id_rsa.pub >authorized_keys
#顺便也设置权限,
chmod 600 ./*
#然后复制到目标机器,所有MHA相关的服务器
scp -P 22 -o StrictHostKeyChecking=no ./* root@10.0.2.6:/root/.ssh/
#注意,其他服务器的秘钥权限也必须是
chmod 600 ./*

然后尝试登陆并成功就完成了.


3.正式转入正题,配置MHA环境

首先要说的是,MHA并没要求配置文件具体放那个位置,所以这个并不固定,然后也正如我一开始说的,如果你用rpm安装,甚至没有配置文件模板,所以下面我会贴出来给大家参考,大家就不用找得那么辛苦了.

然后配置文件有两种:

全局配置文件,名字可以改,我这里是默认模板的:

masterha_default.cnf

还有集群服务器MHA的配置文件,名字可以改,我这里也是默认模板:

app1.cnf

    我估计他这个目的是考虑到manger可能是运行在独立的服务器上,所以这样是允许运行多个manger在服务器上的,不同的配置文件就代表运行不同的manger*.cnf了,也就是控制着不同的MHA架构.

    而不同的MHA架构也可能存在相同的全局配置和不同的集群服务器配置app*.cnf,所以配置文件就这么多样化了,实际上是可以把所有配置都写到app1.cnf这个独立配置文件里面的,并不影响使用.

而我的设置就如下,供大家参考,以下是:

#cat masterha_default.cnf
[server default]
#mysql用户和密码
user=root
password=123123
#系统登陆ssh用户
ssh_user=root
#复制用户
repl_user=root
repl_password=123123
#binlog路径,master 保存binlog的位置,以便MHA可以找到master的日志,
#我这里的也就是mysql的数据目录
master_binlog_dir= /var/lib/mysql,/var/log/mysql,/data/mysql/data
#远端mysql在发生切换时binlog的保存位置
remote_workdir=/data/log/masterha
#监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行frailover.
#如果网络不好,时不时有丢包的话,设大一点好,如果网络非常棒,那设置少一些就有利于故障快速判断并切换
ping_interval=5
#检查MHA健康状态的模式,默认参数是select,即建立一个长连接,不停的对数据库进行"select 1"操作,时间间隔是ping_interval参数决定.
#另外两个参数是CONNECT和INSERT,其中INSERT是0.56新增加的,其方法是在select基础上把"select 1"操作更换成insert写入操作,但还是长连接.
#而CONNECT也是基于select,而且操作没有变,也是"select 1"操作,但是变成短连接,也就是说每一次检查都会新建一个连接来做,时间间隔也是ping_interval参数决定.
ping_type=CONNECT
#通过第三方机器确认目标主库是否存活,不是必须的,就算没有也是能用
#secondary_check_script= masterha_secondary_check -s remote_host1 -s remote_host2
#故障发生后关闭主机的脚本,不是必须的,但是你要设置为空
# shutdown_script= /usr/local/masterha/scripts/power_manager
shutdown_script=""
#故障自动切换VIP调用脚本,不是必须的,就算没有也是能用,
#如果你有keepalived这种来做切换VIP就可以直接不用了
master_ip_failover_script=/usr/local/masterha/scripts/master_ip_failover
#报告发送脚本,不是必须的,就算没有也是能用,发邮件短信什么的就自己配了
# report_script= /usr/local/masterha/scripts/send_report
#手动在线切换VIP脚本,不是必须的,就算没有也是能用,
#如果你有keepalived这种来做切换VIP就可以直接不用了
master_ip_online_change_script=/usr/local/masterha/scripts/master_ip_online_change

然后是另外一个配置文件,我们假设有三个节点,server1是主节点,一个server2是候选节点,一个server3是管理节点.

还2个有binlog_server地址,该功能被MHA 0.56以上版支持(可以用可以不用)。即可以定义[binlogN]选项。在这个部分,可以定义mysqlbinlog streaming servers.如果开启了GTID,则MHA会检查binlog服务器,且binlog服务器日志在其他从节点日志之前,则MHA会在恢复之前从binlog服务器apply差量日志,如果未开启GTID,则MHA 忽略 binlog servers。

#cat app1.cnf
[server default]
#manager的工作目录
manager_workdir=/var/log/masterha/app1
#manager的日志
manager_log=/var/log/masterha/app1/manager.log
#当前主节点
[server1]
#数据库地址
hostname=10.0.2.5
#数据库端口
port=3306
#ssh的端口
ssh_port=22
#当前候选节点
[server2]
hostname=10.0.2.6
port=3306
ssh_port=22
#设置为候选master,如果设置该参数以后,发生主从切换以后将会将优先此从库提升为主库,
#即使这个主库不是集群中事件最新的slave
candidate_master=1
#默认情况下如果一个slave落后master 100M的relay logs的话,
#MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,
#通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,
#这个参数对于设置了candidate_master=1的主机非常有用,
#因为这个候选主在切换的过程中一定是新的master,一定程度上也是可以加快切换的参数
check_repl_delay=0
#当前管理节点
[server3]
hostname=10.0.2.7
port=3306
ssh_port=22
#因为这是管理节点,如果这个节点挂了,那么mha将不可用,加上这个参数后,这个slave挂了之后,
#将不影响其他主从结构,防止误切换
ignore_fail=1
#从不将这台主机转换为master
no_master=1
#binlog_server地址
[binlog1]
hostname=10.0.2.8
[binlog2]
hostname=10.0.2.9

binlog_server功能本身是在mysql5.6开始用mysqlbinlog命令实现的,优势在于他只复制binlog,不执行,所以没有延时.一般的从库需要将binlog转化成relaylog才会继续去拉其他binlog,这样就会造成一定延时.而没有了延时的binlog_server就更能保证binlog的数据完整性,也就让MHA的数据完整性运行得更完美了.

也正如我刚才说的那样,你可以把上面两个配置文件都写到一个文件里面,例如都写进app1.cnf,一样可以正常使用,后面会再详细说说怎么使用.


4.故障切换脚本

然后说说那些用来切换的脚本,

master_ip_failover

master_ip_online_change

send_report

虽然编译安装的MHA也有自带这三个脚本,但是并不能正常使用,所以经过搜索查找到别人的脚本,再改良后使用,下面来一个个看.

这个是master_ip_failover

需要更改的变量参数:

wk:代表网卡名称,可用ip addr和ifconfig来看

key:虚拟网卡代号,无特殊情况可不更改

vip:虚拟IP的地址

ifctrl和arpingd则要whereis ifconfig看看这个命令的路径

cat master_ip_failover

#!/usr/bin/env perl  
use strict; 
use Net::Ping; 
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 $wk =  "eth0";
my $vip = "172.25.33.105";
my $key = "1";
my $ifctrl = "/sbin/ifconfig";
my $arpingd = "/sbin/arping";
my $ssh_start_vip = "$ifctrl $wk:$key $vip/24;$arpingd -q -A -c 1 -I $wk $vip";
my $ssh_stop_vip = "$ifctrl $wk:$key down";
my $ssh_status_vip = "$ifctrl $wk:$key $vip";
my $exit_code = 0;  
   
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";  
   
if ( $command eq "stop" || $command eq "stopssh" ) {  
   
        # $orig_master_host, $orig_master_ip, $orig_master_port are passed.  
        # If you manage master ip address at global catalog database,  
        # invalidate orig_master_ip here.  
        my $exit_code = 1;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Disabling the VIP - $vip on old master: $orig_master_host\n";  
            print "***************************************************************\n\n\n\n"; 
            &ping_check($vip);
            $exit_code = 0;  
        };  
        if ($@) {  
            warn "Got Error: $@\n";  
            exit $exit_code;  
        }  
        exit $exit_code;  
}  
elsif ( $command eq "start" ) {  
   
        # all arguments are passed.  
        # If you manage master ip address at global catalog database,  
        # activate new_master_ip here.  
        # You can also grant write access (create user, set read_only=0, etc) here.  
my $exit_code = 10;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Enabling the VIP - $vip on new master: $new_master_host \n";  
            print "***************************************************************\n\n\n\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";  
        `ssh $ssh_user\@$orig_master_host \" $ssh_status_vip \"`;  
        exit 0;  
}  
else {  
        &usage();  
        exit 1;  
}  
}  
   
# A simple system call that enable the VIP on the new master  
sub start_vip() {  
    `ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}  
# A simple system call that disable the VIP on the old_master  
sub stop_vip() {  
    #return 0  unless  ($ssh_user);
    `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;  
}  
   
sub ping_check{
    my $dest=shift;
    my $mp = Net::Ping->new("icmp");
    if($mp->ping($dest,3)){
        &stop_vip();
    }
    else {
        $exit_code = 0;
    }
    $mp->close;
}   
   
sub usage {  
print  
"Usage: master_ip_failover –command=start|stop|stopssh|status –orig_master_host=host –orig_master_ip=ip –orig_master_port=po  
rt –new_master_host=host –new_master_ip=ip –new_master_port=port\n";  
}

注意:我这个脚本除了参数定义优化了之外,还添加了判断主服务器是否挂掉的函数ping_check,因为我在测试过程中发现,当主服务器彻底关机挂掉之后,脚本连不上主服务器切换VIP就会报错,导致MHA集群切换失败,这是一个bug.所以加上这个ping_check函数之后就能解决,当主机没挂就连上去切换VIP,如果主机挂了就跳过操作,让脚本继续运行下去,这样切换就成功了.也因为功能多了一个,我们就需要添加多一个perl模块Net::Ping了,很不幸,这个功能不能yum和apt,只能用cpan的方式安装

cpan Net::Ping

如果你刚好是内网环境,连不上外网的cpan源,那就请看下面的坑---3,把阿里的cpan源加进去,这样你就能用了.


然后这个是master_ip_online_change

需要更改的变量参数有:

wk:也是网卡名称

key:无特殊情况可不更改

vip:这里和上面类似,只是合在一起改了

ifctrl:和上面一样,是ifconfig的路径

cat master_ip_online_change

#!/usr/bin/env perl  
use strict;  
use warnings FATAL =>'all';  
   
use Getopt::Long;  
   
my $wk =  "eth0";
my $vip = '172.25.33.105';
my $key = "1";
my $ifctrl = "/sbin/ifconfig";
my $arpingd = "/sbin/arping";
my $ssh_start_vip = "$ifctrl $wk:$key $vip/24;$arpingd -q -A -c 1 -I $wk $vip";  
my $ssh_stop_vip = "$ifctrl $wk:$key down";
my $ssh_status_vip = "$ifctrl $wk:$key $vip";
my $exit_code = 0;  
   
my (  
  $command,              $orig_master_is_new_slave, $orig_master_host,  
  $orig_master_ip,       $orig_master_port,         $orig_master_user,  
  $orig_master_password, $orig_master_ssh_user,     $new_master_host,  
  $new_master_ip,        $new_master_port,          $new_master_user,  
  $new_master_password,  $new_master_ssh_user,  
);  
GetOptions(  
  'command=s'                => \$command,  
  'orig_master_is_new_slave' => \$orig_master_is_new_slave,  
  'orig_master_host=s'       => \$orig_master_host,  
  'orig_master_ip=s'         => \$orig_master_ip,  
  'orig_master_port=i'       => \$orig_master_port,  
  'orig_master_user=s'       => \$orig_master_user,  
  'orig_master_password=s'   => \$orig_master_password,  
  'orig_master_ssh_user=s'   => \$orig_master_ssh_user,  
  'new_master_host=s'        => \$new_master_host,  
  'new_master_ip=s'          => \$new_master_ip,  
  'new_master_port=i'        => \$new_master_port,  
  'new_master_user=s'        => \$new_master_user,  
  'new_master_password=s'    => \$new_master_password,  
  'new_master_ssh_user=s'    => \$new_master_ssh_user,  
);  
      
exit &main();  
   
sub main {  
   
#print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";  
   
if ( $command eq "stop" || $command eq "stopssh" ) {  
   
        # $orig_master_host, $orig_master_ip, $orig_master_port are passed.  
        # If you manage master ip address at global catalog database,  
        # invalidate orig_master_ip here.  
        my $exit_code = 1;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Disabling the VIP - $vip on old master: $orig_master_host\n";  
            print "***************************************************************\n\n\n\n";  
&stop_vip();  
            $exit_code = 0;  
        };  
        if ($@) {  
            warn "Got Error: $@\n";  
            exit $exit_code;  
        }  
        exit $exit_code;  
}  
elsif ( $command eq "start" ) {  
   
        # all arguments are passed.  
        # If you manage master ip address at global catalog database,  
        # activate new_master_ip here.  
        # You can also grant write access (create user, set read_only=0, etc) here.  
my $exit_code = 10;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Enabling the VIP - $vip on new master: $new_master_host \n";  
            print "***************************************************************\n\n\n\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";  
        `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_status_vip \"`;  
        exit 0;  
}  
else {  
&usage();  
        exit 1;  
}  
}  
   
# A simple system call that enable the VIP on the new master  
sub start_vip() {  
`ssh $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;  
}  
# A simple system call that disable the VIP on the old_master  
sub stop_vip() {  
`ssh $orig_master_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=po  
rt –new_master_host=host –new_master_ip=ip –new_master_port=port\n";  
}


然后来看send_report,其实系统自带的send_report是能用的,问题是他只能发往服务器系统默认的邮箱,实际上大部分人都不会设那东西,所以就等于没用了.

这个脚本要改的也就是邮箱的信息了,smtp,mail_from,mail_user,mail_pass,mail_to,改完就可以了.

cat send_report

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use Mail::Sender;
use Getopt::Long;

#new_master_host and new_slave_hosts are set only when recovering master succeeded
my ( $dead_master_host, $new_master_host, $new_slave_hosts, $subject, $body );
my $smtp='smtp.163.com';
my $mail_from='xxxx';
my $mail_user='xxxxx';
my $mail_pass='xxxxx';
my $mail_to=['xxxx','xxxx'];
GetOptions(
  'orig_master_host=s' => \$dead_master_host,
  'new_master_host=s'  => \$new_master_host,
  'new_slave_hosts=s'  => \$new_slave_hosts,
  'subject=s'          => \$subject,
  'body=s'             => \$body,
);

mailToContacts($smtp,$mail_from,$mail_user,$mail_pass,$mail_to,$subject,$body);

sub mailToContacts {
    my ( $smtp, $mail_from, $user, $passwd, $mail_to, $subject, $msg ) = @_;
    open my $DEBUG, "> /tmp/monitormail.log"
        or die "Can't open the debug      file:$!\n";
    my $sender = new Mail::Sender {
        ctype       => 'text/plain; charset=utf-8',
        encoding    => 'utf-8',
        smtp        => $smtp,
        from        => $mail_from,
        auth        => 'LOGIN',
        TLS_allowed => '0',
        authid      => $user,
        authpwd     => $passwd,
        to          => $mail_to,
        subject     => $subject,
        debug       => $DEBUG
    };

    $sender->MailMsg(
        {   msg   => $msg,
            debug => $DEBUG
        }
    ) or print $Mail::Sender::Error;
    return 1;
}

# Do whatever you want here

exit 0;

好了,万事俱备只欠东风,剩下的,就是准备启动了.


启动MHA

准备启动前,还是要检测一下,MHA自带了检测命令,非常好用.

其中,global_conf指定全局配置文件,conf指定特定配置文件,如果你全部都写进了app1.cnf,那就不需要写global_conf了.

先检查下服务器之间SSH是否都正常

masterha_check_ssh --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf

看到OK和下面这句

All SSH connection tests passed successfully.

就没问题了.

然后检查一下整个架构的主从是否正常,这将决定这个架构是否能启动MHA成功

masterha_check_repl --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf

这条结果可能有点特别,因为不排除有warning,但是并不影响使用,看到error那才是要解决的,主要就是要看这个就可以了.

MySQL Replication Health is OK.

============分割线开始==========================

坑---1:

在mysql5.7+mha-0.57的环境下,由于系统自带的mysql客户端运行库(libmysqlclient.so)和perl模块DBD(perl-DBD-MySQL)的版本不一定是最新的(即使是epel的yum运行库),会出现无法修复的报错,必须把他们都升级才能解决,现象如下:

mysql数据库高可用架构-MHA-0.56/0.57详解_mysql

mysql数据库高可用架构-MHA-0.56/0.57详解_mysql_02

解决方法如下:

#卸载原本的libmysqlclient.so运行库程序,其本身也会干扰mysql5.7的启动,所以卸载有好处
#先检查是否安装和安装的版本号
rpm -qa |grep -E 'mysql|mariadb'
mariadb-libs-5.5.52-1.el7.x86_64
#按照显示的版本号卸载,在rhel7开始默认安装的是mariadb来替代原本的mysql
rpm -e --nodeps mariadb-libs-5.5.52-1.el7.x86_64
#查看perl运行库DBD的版本号,显示的是旧的版本号,目标版本号应该是DBD-mysql-4.042
rpm -qa |grep perl-DBD
perl-DBD-MySQL-4.023-5.el7.x86_64
#创建新的libmysqlclient.so运行库的软连接
ln -sf /usr/local/mysql/lib/libmysqlclient.so.20 /usr/lib64/
ln -sf /usr/local/mysql/lib/libmysqlclient.so /usr/lib64/
或
ln -sf /usr/local/mysql/lib/libperconaserverclient.so /usr/lib64/
ln -sf /usr/local/mysql/lib/libperconaserverclient.so.20 /usr/lib64/
#然后还要把mysql相关命令做一下软连接,不然有可能装不了
ln -sf /usr/local/mysql/bin/* /usr/local/bin/
#安装相关运行库,不然也是安装不了
yum install -y perl-CPAN perl-YAML
#由于yum安装的perl-DBD-MySQL是旧的,升级也不行,所以只能另觅出路,用cpan安装
cpan DBD::mysql
#一路按回车,然后命令会自动连接服务器检测最新版的DBD-mysql并下载,最后出现下面的就算成功了
    .
    .
    .
MICHIELB/DBD-mysql-4.042.tar.gz
  /usr/bin/make install  -- OK
#再运行一次就不会报错了
masterha_check_repl --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf
#####################################################################################
#额外说明,有时候可能预安装的mysql控件问题,导致安装了也是报DBD/mysql出错,我们就要重新安装一次了
#首先安装perl模块卸载程序
cpan App::pmuninstall
#卸载有问题的perl模块
pm-uninstall DBD::mysql
#最后再重新安装一次
cpan DBD::mysql
#####################################################################################

这样就不会报了.


坑---2:

如果使用centos7.X+mysql5.7的环境,可能会出现TCP连接频繁异常断开的情况,具体原因未知,可能和内核有关,也可能是某些默认网络配置有关,换成用centos6.X或mysql5.6倒是没问题,所以逼于无奈就只能换系统.由于领导说centos6.X太旧了,而ubuntu14.X的内核和centos7.X是一样的3.1版本,所以只能直接上ubuntu16.X(内核是4.4),然而版本太新,软件也很新,造成MHA的一个模块出现了对于perl版本认知错误的bug,问题如下图:

mysql数据库高可用架构-MHA-0.56/0.57详解_mysql_03

在centos系列里面,perl版本比较旧,都不会出现这种情况,在ubuntu里面就不一样了,虽然还是perl5,但是perl5.22似乎是不能好好用的意思-_-!...

还好,github上人才济济,早就有人发现问题,并给出解决方案:

https://github.com/yoshinorim/mha4mysql-node/pull/23/files?diff=split

可以看下面:

#打开报错的模块代码文件
vim /usr/local/share/perl/5.22.1/MHA/NodeUtil.pm
#移动到201行附近,更改函数parse_mysql_major_version原本是这样
sub parse_mysql_major_version($) {
    my $str = shift;
    my $result = sprintf( '%03d%03d', $str =~ m/(\d+)/g );
    return $result;
    }
#改成下面这样
sub parse_mysql_major_version($) {
    my $str = shift;
    $str =~ /(\d+)\.(\d+)/;
    my $strmajor = "$1.$2";
    my $result = sprintf( '%03d%03d', $strmajor =~ m/(\d+)/g );
    return $result;
    }
#保存退出,然后再重新运行就可以了
masterha_check_repl --global_conf=/data/mhamaster/config/masterha_57_1.cnf --conf=/data/mhamaster/config/app57_1.cnf

很不幸,purge_relay_logs也碰导同样的报错,问题也是类似的,所以也是需要修改

#也是同样的文件报错
vim /usr/local/share/perl/5.22.1/MHA/NodeUtil.pm
#这次提示是195行,原本是这样
sub parse_mysql_version($) {
  my $str = shift;
  my $result = sprintf( '%03d%03d%03d', $str =~ m/(\d+)/g );
  return $result;
}
#改成下面这样就可以用了
sub parse_mysql_version($) {
  my $str = shift;
  $str =~ /(\d+)\.(\d+).(\d+)/;
  my $strmajor2 = "$1.$2.$3";
  my $result = sprintf( '%03d%03d%03d', $strmajor2 =~ m/(\d+)/g );
  return $result;
}

然后,再试一试看看.


坑---3:

有朋友反馈安装完成后会出现下面这种错误,然后怎么都无法修复,直接导致MHA不可用,如下图:

mysql数据库高可用架构-MHA-0.56/0.57详解_ mha_04

这个问题的原因其实和坑---1类似,就是perl插件的版本太旧导致的,而刚好你们的yum源或apt源太旧,也就更新不了较新的版本了,最终就是完全搞不下去.而由于我当初那来测试的yum源都比较新,没有碰到此类问题,所以开始也不发觉,现在刚好有台centos6.5的需要安装mha就发现了,下面来看解决方法:

首先从报错来看,其实很直接就返回代码错误,回看此行出错的代码,你就大概知道,

#报错信息如下
"NI_NUMERICHOST" is not exported by the Socket module
 "getaddrinfo" is not exported by the Socket module
 "getnameinfo" is not exported by the Socket module
Can't continue after import errors at /usr/local/share/perl5/MHA/NodeUtil.pm line 29
    .
    .
    .
#查看问题代码
vim /usr/local/share/perl5/MHA/NodeUtil.pm
#定位到第29行
use Socket qw(NI_NUMERICHOST getaddrinfo getnameinfo);

由此可见,是加载SOCKET插件的时候出错了,出错的原因只有两个,要么是没装,要么是太旧,但是解决方法都是一个,就是重新安装最新的,怎么装呢?还是用cpan吧.

#打开cpan
cpan
#查看配置
>o conf
#指定阿里云cpan源,国内还是这个比较稳定,被墙的你懂的
>o conf urllist push http://mirrors.aliyun.com/CPAN/
#提交更改
>o conf commit
#查看是否修改成功
>o conf urllist
#安装相关插件,记得要按yes
>install IO::Socket::INET6
#也是相关插件,记得要按yes
>install ExtUtils::Constant
#还是相关插件,记得要按yes
>install YAML
#安装上本坑的重点,socket插件
>install Socket
#顺便也将坑1的问题也修复一下吧,记得要按yes
>install DBD::mysql

然后,重新试一试就可以了.


坑---4:

其实这个坑,也不能叫坑,只是本身他mha的功能要求是这样.

当有1主多从,例如1主3从的情况下,因为功能上要在从机之间要互相校对binlog和relaylog的先后问题,所以是要求主从所有机器都安装上mha的node端程序脚本,不然就会有下面报错:

mysql数据库高可用架构-MHA-0.56/0.57详解_mysql_05

是不是感觉和坑---3类似,没错,其实就是坑---3的问题,只是这个问题不是出在本地manager端,而是出在远端的其他从机和主机上.

解决方法也就和坑---3是一毛一样了,只是安装的地方,不是本地manager端,是在远端安装一个node端,所以相关perl插件都要安装上.


==================分割线结束=====================

如果是使用keepalived这类来做切换vip的朋友,因为屏蔽了使用

master_ip_failover

master_ip_online_change

所以会出现

[warning] master_ip_failover_script is not defined.

[warning] shutdown_script is not defined

但都是正常的,不代表有问题,可以放心使用.

再然后,我们来检查下当前状态

masterha_check_status --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf

app1 is stopped(2:NOT_RUNNING).

不要紧张,是正常的呢,因为都没启动嘛,所以当然是NOT_RUNNING

现在开始启动MHA的进程

masterha_manager --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf > /tmp/mha_manager.log 2>&1 &

介绍几个比较有用的参数


启动参数介绍:

--remove_dead_master_conf    该参数代表当发生主从切换后,老的主库的ip将会从配置文件中移除。

--manger_log    日志存放位置,想规范化管理日志可以加上

--ignore_last_failover    该参数代表忽略上次MHA触发切换产生的文件,默认情况下,MHA发生切换后会在日志目录,也就是上面我设置的/data产生app1.failover.complete文件,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后收到删除该文件,在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover,之所以这样限制是为了避免ping-pong效应。

===============分割线开始==============================

其他参数介绍

*--conf=(配置文件的全路径)    应用&局部配置文件
* --global_conf=(全局配置文件的全路径)    全局配置文件。默认是: /etc/masterha_default.cnf
* --manager_workdir, --workdir    MHA Manger的工作目录,会产生一系列状态文件在这里面。如果不设置,默认的是: /var/tmp  
* --manager_log, --log_output    MHA Manger会产生日志相关的文件在这个目录中。如果不设置,会打印到STDOUT/STDERR。如果是人工failover(interactive failover),MHA会忽略--manager_log,直接打印到STDOUT/STDERR

* --wait_on_monitor_error=(seconds)    这个功能主要用在自动监控和failover上,如果在监控期间发生了错误,masterha_manager 会等待wait_on_monitor_error=N 秒,然后退出,默认是0.如果遇到错误,在restart 监控前最好还是等等  
* --ignore_fail_on_start    默认情况下,如果一个或者多个slave down掉了,master monitor 进程就会停掉,就算你设置了ignore_fail,如果设置了--ignore_fail_on_start参数,ignore_fail标记了slave挂掉也不会让master monitor进程停掉

* --wait_on_monitor_error=(seconds)    这个功能主要用在自动监控和failover上,如果在监控期间发生了错误,masterha_manager 会等待wait_on_monitor_error=N 秒,然后退出,默认是0.如果遇到错误,在restart 监控前最好还是等等
* --ignore_fail_on_start    默认情况下,如果一个或者多个slave down掉了,master monitor 进程就会停掉,就算你设置了ignore_fail,如果设置了--ignore_fail_on_start参数,ignore_fail标记了slave挂掉也不会让master monitor进程停掉
* --last_failover_minute=(minutes)    如果上一次failover刚刚才完成(默认8小时),那么MHA manager 这次将不会进行failover,这个参数主要是为了避免 ping-pong failover问题,如果设置了 --ignore_last_failover,将忽略这个限制  
* --remove_dead_master_conf    设置了这个参数后,如果MHA failover结束后,MHA Manager会自动在配置文件中删除 dead master的相关项,如果不设置,由于dead master的配置还存在文件中,那么当MHA failover后,当再次restart MHA manager后,会报错(there is a dead slave previous dead master)

===============分割线结束===========================

再用命令检查下当前状态

masterha_check_status --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf

在最后的地方出现下面这一行信息

app1 (pid:20386) is running(0:PING_OK), master:****

也就是说mha启动完毕,并且是正常的.


然后我们再看看mha的日志,还记得我们配置的日志地址吗?

#cat app1.cnf
[server default]
#manager的工作目录
manager_workdir=/var/log/masterha/app1
#manager的日志
manager_log=/var/log/masterha/app1/manager.log

所以我们要看

cat /var/log/masterha/app1/manager.log

我们也可以看到日志的最后,看到

Ping(SELECT) succeeded, waiting until MySQL doesn't respond..

说明整个系统已经正常使用了,mha程序开始监控了.

=============分割线开始======================

有时候出现下面的情况,其实未必是程序有问题,而是有时候网络连接不通导致:

app1 master maybe down(20:PING_FAILING). master:****
Check /******/***.log for details.

只要重新出现ok一般也没什么事.

=============分割线结束======================

有启动就有关闭,下面这个就是关闭命令

masterha_stop --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf

不会返回什么特别的东西,一般都会关闭成功.

剩下的就是测试怎么故障恢复了,这里就不细说了,各位可以自己试试.


手动切换

MHA集群的手动切换,通过masterha_master_switch来完成,但是要注意,

一定要预先定义好master_ip_online_change和master_ip_failover这两个脚本,还要把masterha_manager的进程停掉,

这里简单列几个例子:

当主库还存活时切换:

#当主库还存活时,在线切换主从,选择随机从库来做主库,主从结构替换
masterha_master_switch --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf --master_state=alive --orig_master_is_new_slave
#当主库还存活时,在线切换主从,并指定一个从库来做主库,主从结构替换
masterha_master_switch --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf --master_state=alive --new_master_host=172.25.33.97 --new_master_port=3309 --orig_master_is_new_slave

当主库挂掉时,

#当主库进程关闭时,切换主从,选择随机从库来做主库
masterha_master_switch --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf --master_state=dead --dead_master_ip=172.25.33.95 --dead_master_host=172.25.33.95 --dead_master_port=3309 --ignore_last_failover
#当主库进程关闭时,切换主从,并指定一个从库来做主库
masterha_master_switch --global_conf=/usr/local/masterha/conf/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf --master_state=dead --dead_master_ip=172.25.33.95 --dead_master_host=172.25.33.95 --dead_master_port=3309 --new_master_ip=172.25.33.97 --new_master_host=172.25.33.97 --new_master_port=3309 --ignore_last_failover

注意:如果没有用上我上面的master_ip_failover脚本,这个命令只在主机mysql进程关闭,但是还能ping通时才能用,要是主机完全网络不通,手动切换是会提示错误的.不过,我们应当要考虑可能出现脑裂的情况,所以当主机彻底网络不通的情况下,也要保证这台机是关机,或者重启过的状态(vip设置已丢失),才能做,这才是最稳妥的.


命令参数解析

上面只介绍了控制MHA Manager的命令masterha_manager的相关参数,来看其他命令的参数.

人工交互式failover命令,还可以做master在线切换,

masterha_master_switch:

参数解析:

* --master_state=dead    这个value可能的取值是:‘dead’ or ‘alive’。如果设置为alive,就是在线master切换了,这样的场景,master必须是活着的   
* --dead_master_host=(hostname)    Dead master的主机信息,包括 --dead_master_ip,--dead_master_port  
* --new_master_host=(hostname)    New master的主机信息,这个参数是可选项,如果你想特意指定某台机器作为new master,就设置这个参数,如果new_master_host没有设置,那么选举master的规则参考automated master failover( candidate_master parameter )  
* --interactive=(0|1)    交互式failover,设置为1(默认),非交互式failover,设置为0  
* --skip_change_master(0.56)    只会完成日志补偿,不会进行change master和start slave,如果你想double check slave是否成功的恢复完成,那么设置该参数对你特别有用  
* --skip_disable_read_only    如果设置了这个参数,那么新master 将还会是 只读状态,如果你想手动开启新master的写权限,那么这个参数特别有用  
* --last_failover_minute=(minutes)    当最近的一个failover切换发生在last_failover_minute(默认为8小时)之内,MHA manager将不会在切换.因为它会认为有些问题没有得到解决.如果设置了--ignore_last_failover此参数将会失效  
* --ignore_last_failover    如果最近failover失败,MHA将不会再次开始failover机制,需要手动清理failover错误文件app_name.failover.error才行,如果设置此参数,MHA将会继续failover不管上次的failover状态

* --wait_on_failover_error=(seconds)    同 masterha_manager 里面的参数一样。这个参数,只对自动或者非交互式的failover有用,如果--interactive=0 没有设置,那么这个参数将不起作用  
* --remove_dead_master_conf    如果设置此参数,当成功failover后,MHA manager将会自动删除配置文件中关于dead master的配置选项。

* --wait_until_gtid_in_sync(0|1)    这是基于GTID的参数,如果设置为1(默认): MHA会等待,直到所有slave追上新master的gtid,如果设置为0: 那么MHA不会等待slave追上新master  
* --skip_change_master    MHA 不会执行 CHANGE MASTER  
* --skip_disable_read_only    MHA 忽略在new master上执行 SET GLOBAL read_only=0  
* --ignore_binlog_server_error    MHA忽略任何binlog server的错误

* --new_master_host=(hostname)    指定每台机器为新master
* --orig_master_is_new_slave    当master切换后,原来的老master切换后,会成为新的slave,默认情况下,这个参数是关闭的,也就是原来的老master不会出现在新的复制环境中,如果你要设置--orig_master_is_new_slave,那么必须在配置文件中设置repl_password参数,因为它不知道新master的复制密码  
* --running_updates_limit=(seconds)    如果当前master上的执行的写query超过这个值,或者slave 落后master超过这个值,master switch操作会终止,默认是1秒  
* --remove_orig_master_conf    设置后,master 切换后,原来master的相关信息在配置文件中会被删除,默认这个参数不生效,不会在配置中删除相关信息  
* --skip_lock_all_tables    如果设置这个参数,那么在切换过程中,不会对老master 进行FLUSH TABLES WITH READ LOCK


检查复制环境是否ok的命令

masterha_check_repl:

参数解析:

* --seconds_behind_master=(seconds)    masterha_check_repl 会检测延迟,如果超过这个描述,会报错,默认是 30秒
* --skip_check_ssh    通过masterha_check_ssh 去检测ssh的环境,如果设置了该参数,可以忽略SSH的检测


添加和删除配置文件中的条目的命令

masterha_conf_host:

参数解析:

* --command=(add|delete)    增加或者删除一个block  
* --conf=(config file path)    局部配置的全局路径  
* --hostname=(hostname)    主机名
* --block=(block_name)    配置文件中的一个block,当--add时,block name 必须在配置文件中不存在,当--delete时,block name 必须在配置文件中存在,当--block不指定时,名字默认为: server$hostname  
* --params=(key1=value1;key2=value2;...)    参数list


前面说过了,MHA本身是要检测relay-log的,所以就需要关闭自动删除relay-logs的purge线程,然后自己通过purge_relay_logs命令来阶段性的来删除.

purge_relay_logs:

参数解析:

* --user    MySQL用户名,默认root  
* --password    MySQL 密码,默认为空
* --host    MySQL的hostname,默认127.0.0.1,必须传递正确的host  
* --port    MySQL 的端口,默认3306
* --workdir    relay log硬连接创建和删除的目录,这个目录最好不要跨OS分区,relay log 在哪个分区,workdir就设置在哪个分区。如果跨分区,会报错Invalid cross-device link  
* --disable_relay_log_purge    如果MySQL里面的参数relay_log_purge设置为1,那么这个脚本不会做任何工作,如果这个脚本设置了 --disable_relay_log_purge参数,那么它会主动去关闭MySQL的参数relay_log_purge=0


其他参数解析:

MHA 参数列表
Local : 指每一个配置块内部。 Local功能的参数需要放置在[server_xxx] 块下面
App : 参数作用于master/slave, 这些参数需要配置在[server_default]块的下面
Global : 作用于master/slave, Global级别的参数用于管理多组master/slave结构,可以统一化管理一些参数。 

hostname
配置MySQL服务器的机器名或是IP地址,这个配置项是必须的,而且只能配置在[server_xxx]这个块下面。
如:
参数名        是否必须     作用域        默认值     例子及说明
hostname     Yes            Local Only     –         hostname=mysql_server1, hostname=192.168.0.1, etc

ip
MySQL服务器的ip地址。 默认从gethostname($hostname)中获得。 默认不用配置这个参数,MHA可以通过hostname自动获取,MHA通过IP地址连接MySQL服务器及SSH连接。
如:
参数名     是否必须     作用域     默认值     例子及说明
ip        No            Local    Only     通过gethostbyname($hostname)获得     ip=192.168.1.3

port
MySQL运行的端口号。 默认是3306. MHA使用IP和端口号连接MySQL
如:
参数名     是否必须     作用域                默认值     例子及说明
port     No            Local/App/Glbal     3306     port=3306

ssh_host
(从MHA 0.53后开始支持) MHA要ssh上MySQL目标服务器使用hostname 或是ip地址。这个参数主要用于在使用多个VLAN的环境中。为了安全原因ssh默认不允许。默认这个参数和hostname相同。
如:
参数名         是否必须     作用域         默认值             例子及说明
ssh_host     No             Local Only     和hostname相同     ssh_host=mysql_server1, ssh_host=192.168.0.1, etc

ssh_ip
(从MHA 0.53后开始支持) 和ssh_host作用相同。 默认是gethostname($ssh_host)获得。 
如:
参数名     是否必须     作用域         默认值                         例子及说明
ssh_ip     No             Local Only     gethostbyname($ssh_host)     ssh_ip=192.168.1.3

ssh_port
(从MHA 0.53后开始支持) SSH使用的端口号,默认是22.
如:
参数名         是否必须     作用域                 默认值     例子及说明
ssh_port     No             Local/App/Global     22         ssh_port=22

ssh_connection_timeout
(从MHA 0.54后支持)默认是5秒。在没添加这个参数之前ssh超时时间是写死的。
如:
参数名                     是否必须     作用域                 默认值     例子及说明
ssh_connection_timeout     No             Local/App/Global     5         ssh_connect_timeout=5

ssh_options
(从MHA 0.53后支持) 添加ssh命令行的支持参数,例如加上特别文件名的key的支持等。
如:
参数名             是否必须     作用域                 默认值         例子及说明
ssh_options     No             Local/App/Global     “” 空的     ssh_options=”-i /root/.ssh/id_dsa2″

candidate_master
你可能对于同一组slave中有着不同的规划,有的其望在Master故障时,提升为新的Master(如: Raid1的slave比Raid0的slave更适合做Master)
这个参数的作用是当设计candidate_master = 1时,这个服务器有较高的优先级提升为新的master(还要具备: 开启binlog, 复制没有延迟)。 所以当设置了candidate_master = 1的机器在master故障时必然成为新的master. 但这是很有用的设置优先级的一个参数。
如果设置了多台机器的caddidate_master = 1 , 优先策略依赖于块名字([server_xxx]). [server_1] 优衔权高于[server_2].
如:
参数名                 是否必须     作用域         默认值     例子及说明
candidate_master     No             Local Only     0         candidate_mast=1

no_master
当设置了no_master = 1的服务器,这个服务器永远不会提升为新的master. 这个参数据对于永远不期望成为master的机器很有用。 如: 你可能需要在使用raid0的机器上设置no_master = 1 或是你希望在远程的idc里运行一个slave. 注意: 当没有可以成为新master的机器是MHA就直接退出来了同时停止监控和master故障切换。
如:
参数名         是否必须     作用域         默认值     例子及说明
no_master     No             Local Only     0         no_master=1

ignore_fail
在默认情况下,MHA manager不会在slave存在故障的情况下(已经不能通过SSH/MySQL进行连接,或是SQL Thread已经停止出错,其它原因)的情况下进行Master的故障切换(当不存在slave时MHA manager也会退出)。 但有些情况下你期望在slave存在问题的情况下,也进行故障切换。 所以当设置了ignore_fail = 1时,MHA会在所有的机器有问题的时间也会进行故障切换。 默认是0.
如:
参数名             是否必须     作用域         默认值     例子及说明
ignore_fail     No             Local Only     0         ignore_fail=1

#skip_init_ssh_check#
在MHA manager启动时跳过ssh检查。
如:
参数名                     是否必须     作用域         默认值     例子及说明
skip_init_ssh_check     No             Local Only     0         skip_init_ssh_check=1

skip_reset_slave
(从MHA 0.56开始支持) Master故障切换后新的master上执行RESET SLAVE(ALL).
如:
参数名     是否必须     作用域     默认值                 例子及说明
skip_reset_slave     No         Local/App/Global     0     skip_reset_slave=1

user
用于管理MySQL的用户名。这个最后需要root用户,因为它需要执行:stop slave; change master to , reset slave. 默认: root
如:
参数名     是否必须     作用域                 默认值     例子及说明
user     No             Local/App/Global     root     user=mysql_root

password
MySQL的管理用户的密码。 默认是空的
如:
参数名         是否必须     作用域                 默认值     例子及说明
password     No             Local/App/Global     空的     password=rootpass

repl_user
MySQL用于复制的用户,也是用于生成CHANGE MASTER TO 每个slave使用的用户。 这个用户必须有REPLICATION SLAVE权限在新的Master上。默认情况下 repl_user会在将来成为master的机器上运行show slave status获取到。
如:
参数名         是否必须     作用域                 默认值                     例子及说明
repl_user     No             Local/App/Global     从show slave status     repl_user=repl

repl_password
MySQL中repl_user用户的密码。 默认是当前复制用的密码。  当你使用online_master_switch时,当使用–orig_master_is_new_slave(原来的Master成为新Master的一个slave)时,如果没有repl_password 开启同步就会失败了。因为当前master上用于复制的用户名和密码都是空的(MHA在原来的Master上执行change master to 时没有带复制的密码,虽然其它slave上设置了复制的密码)
如:
参数名             是否必须     作用域                 默认值                 例子及说明
repl_password     No             Local/App/Global     当前复制用的密码     repl_password=replpas

disable_log_bin
当设置了这个参数,在slave应用差异的relay log时不会产生二进制日志。 内部实现通过mysqlbinlog的disable-log-bin实现。
如:
参数名                 是否必须     作用域                 默认值     例子及说明
disable_log_bin     No             Local/App/Global     0         disable_log_bin=1

master_pid_file
指定MySQL的pid文件。 这个参数在一台服务器上运行多个MySQL服务进程时非常有用。
如:
参数名                 是否必须     作用域                 默认值     例子及说明
master_pid_file     No             Local/App/Global     –         master_pid_file=/var/lib/mysql/master1.pid

ssh_user
MHA Mananger, MHA node系统上的用户。 这个帐号需要在远程机器上有执行权限(Manager->MySQL),在slave成员之间复制差异的relay-log(MySQL->MySQL)
这个用户必须有读取MySQL的binary/relay日志和relay_log.info的权限,还需要对远程MySQL上remote_workdir目录的写权限。
这个用户还必须可以直接ssh到远程机顺上, 推荐使用ssh pbulic key . 一般使用的ssh_user也是运行manager那个那个用户。
如:
参数名         是否必须     作用域                 默认值                 例子及说明
ssh_user     No             Local/App/Global     当前使用的系统用户     ssh_user=root

remote_workdir
MHA node上工作目录的全路径名。如果不存在,MHA node会自动创建,如果不允许创建,MHA Node自动异常退出。 需要注意MHA manager 或是MHA node上需要检查空间是否可用,所以需要注意检查这个。 一般默认, remote_workdir是的”/var/tmp”
如:
参数名             是否必须     作用域                 默认值         例子及说明
remote_workdir     No             Local/App/Global     /var/tmp     remote_workdir=/var/log/masterha/app1

master_binlog_dir
master上用于存储binary日志的全路径。这个参数用于当master上mysql死掉后,通过ssh连到mysql服务器上,找到需要binary日志事件。这个参数可以帮助用于无法找到master进程死掉后binary日志存储位置。
一般: master_binlog_dir是”/var/lib/mysql/, /var/log/mysql”. “/var/lib/mysql/”是大多数系统发行版本的存放位置,”/var/log/mysql”是ubuntu发行版本的存放位置。 你也可以设置多个存放位置用逗号隔开。
如:
参数名                 是否必须     作用域                 默认值             例子及说明
master_binlog_dir     No             Local/App/Gobal     /var/lib/mysql     master_binlog_dir=/data/mysql1,/data/mysql2

log_level
设置MHA manager记录LOG的级别。 默认是info级别而且大多数情况也是比较适合。 同样可以设置为: debug/info/warning/error.
如:
参数名         是否必须     作用域         默认值     例子及说明
log_level     No             App/Global     info     log_level=debug

manager_workdir
用于指定mha manager产生相关状态文件全路径。 如果没设置 默认是/var/tmp
如:
参数名                 是否必须     作用域     默认值         例子及说明
manager_workdir     No             App     /var/tmp     manager_workdir=/var/log/masterha

manager_log
指定mha manager的绝对路径的文件名日志文件。 如果没设置MHA Manager将打印到STDOUT/STDERR。 当手工执行故障切换(交互模式切换),MHA Manager会忽略manager_log设置直接将日志输出到STDOUT/STDERR.
如:
参数名             是否必须     作用域     默认值     例子及说明
manager_log     No             App     STDERR     manager_log=/var/log/masterha/app1.log

check_repl_delay
在默认情况下,当一个slave同步延迟超过100M relay log(需要应用超过100M relay log), MHA在做故障切换时不会选择这个slave做为新的master,因为恢复需要经过很长时间.当设置了check_repl_delay = 0, MHA将忽略被选择的slave上的同步延迟。 这个选项在设置了candidate_master = 1特声明的期望这台机器成为master的情况下特别有用。
如:
参数名                 是否必须     作用域         默认值     例子及说明
check_repl_delay     No             App/Golbal     1         check_repl_delay=0

check_repl_filter
在默认下情况,当master和slave设置了不同了binary log/replication 过滤规则时,MHA直接报错不会进行监控和故障切换。 这些将会导致出现一些异想不到的错误”Table not exists”。如果你100%确认不同的过滤规则不会导致恢复中的错误,设置check_repl_filter=0。 需要注意: 当使用了check_repl_filter = 0时,MHA不会检查过滤规则在应用差异的relay日志,所以有可能会出现”Table not exists”的错误。当你设置了这个参数请小心处理。
如:
参数名                 是否必须     作用域         默认值     例子及说明
check_repl_filter     No             App/Global     1         check_repl_filter=0

latest_priority
在默认情况下,和Master最接近的slave(一个slave从Master上获得了最一个binlog事件)是最有优先权成为新的master。 如果你想控制一下切换的策略(如: 先选择host2,如果不行,选host3;host3不行,选host4…) 那么设置latest_priority = 0 就可以了。
如:
参数名                 是否必须     作用域         默认值     例子及说明
latest_priority     No             App/Global     1         latest_priority=0

multi_tier_slave
从MHA 0.52开始, 多层复制可以支持了。在默认情况下,不支持三层或是更多层的复制配置。 如果: host2从host1上复制,host3从host2上复制。 在默认配置的情况下不支持写host{1,2,3},因为这是一个三层的复制,MHA Manager会停止报错。 当设置了multi_tier_slave, MHA Manager就不会在三层复制报错停止。 但是会忽略第三层的机器。也就是如果host1挂了,host2将会成为新的master,host3还是从host2上进行复制。
这个参数在MHA Manager 0.52后的版开始支持。
如:
参数名                 是否必须     作用域         默认值     例子及说明
muli_tier_slave     No             App/Global     0         multi_tier_slave=1

ping_interval
这个参数设置MHA Manager多长时间去ping一下master(执行一些SQL语句). 当失去和master三次偿试,MHA Manager会认为MySQL Master死掉了。也就是说,最大的故障切换时间是4次ping_interval的时间,默认是3秒。
如果MHA Manager在和MySQL创建连接时都收到多连接错误或是认证错误,这个就不做重试就会认为master已经挂掉。
如:
参数名             是否必须     作用域         默认值     例子及说明
ping_interval     No             App/Global     3         ping_interval=5

ping_type
(从MHA 0.53后开始支持) 在默认情况下, MHA manager和MySQL创建一个连接执行”select 1″(ping_type=select)用于检查master是否健康。 但有一些情况: 每次检测都连接/然后断开会比较好一点,这样对于tcp方面的错误感知更快一点。设置ping_type=CONNECT 就行了。从MHA 0.56后pint_type=INSERT也被添加。
如:
参数名         是否必须     作用域         默认值     例子及说明
ping_type     No             App/Global     SELECT     ping_type=CONNECT

secondary_check_script
一般来讲, 非常推荐使用更多网络上机器是不同路由策略上的机器来检查MySQL Master是否存活。 默认情况下,只有MHA Manager通过一个路由来检查Master是否存活。这个也是不推荐的。MHA可以通过外部secondary_check_script配置的脚本来做到从多个路由策略下进行检查。
    secondary_check_script = masterha_secondary_check -s remote_host1 -s remote_host2
secondary_check_script包含在MHA Manager发行包中。 MHA中内置的secondary_check_script在大多数情况下工作良好,但并不是任何地都可以使用这个脚本。
在上面的例子中, MHA Manager通过Manager->(A)->remote_host1->(B)->master_host 和Manager->(A)-remote_host2->(B)->master_host来检查MySQL master是否存活。如果在连接过程中通过A可以都成功,通过B是都失败,secondary_\check_\script返回0,而且认为master已经死掉,进行故障切换。如果通过A成功,但返回代码为: 2,则MHA manager有会认为是网络问题,则不会进行故障切换。如果A成功,B也成功,masterha_secondary_check 退出返回:3 则MHA Manager就为认为MySQL Master为存活状态, 则不会进行故障切换。
一般来讲, remote_host1和remote_host2是和MHA Manager及MySQL Server位于不同的网段中。
MHA会调用secondary_check_script声明的脚本并自动带上一些参数。 masterha_secondary_check在很多场景都是适用的,但是你也可以自已实现这个程序带有更多的功能。
–user=(在远程机器上使用的SSH用户名。 ssh_user的值将被使用)
–master_host = (master的hostname)
–master_ip = (master的ip地址)
–master_port = ( master的端口号)
注意: 内置的masterha_secondary_check脚本依赖于的Perl的IO::Socket::INET(Perl 5.6.0中是默认支持包含这个模块)。 masterha_secondary_check需要通过ssh连接到远程的机器上,所以需要manager到远程机器上建立public key信任。另外masterha_secondary_check是通过和Master建立TCP的连接测试Master是否存活,所以mysql设置的max_connections不起作用。 但每次TCP连接成功后,MySQL的Aborted_connects 值都会加1。
如:
参数名                     是否必须     作用域         默认值     例子及说明
secondary_check_script     No             App/Global     null     secondary_check_script= masterha_secondary_check -s remote_dc1 -s remote_dc2

master_ip_failover_script
如:
参数名                         是否必须     作用域         默认值     例子及说明
master_ip_failover_script     No             App/Global     null     master_ip_failover_script=/usr/local/custom_script/master_ip_failover

master_ip_online_changes_script
这个参数有点类似于master_ip_failover_script,但这个参数不用于master 故障转意,只使用到master在线的切换。
冻结Master写的过程:
    –command=stop or stopssh
    –orig_master_host = (当前master的主机名)
    –orig_master_ip = (当前master的ip地址)
    –orig_master_port = (当前master的port端口号)
    –orig_master_user = (当前master的用户)
    –orig_master_password = (当前master的用户名)
    –orig_master_ssh_user = (从0.56支持,当前master的ssh的用户名)
    –orig_master_is_new_slave =  (从 0.56 ,是否把原Master更改为新的slave)
新的Master接受写的过程:
    –command=start
    –orig_master_host = ( 原master的机器名 )
    –orig_master_ip = ( 原master的ip )
    –orig_master_port = ( 原master的端口号 )
    –new_master_host = (新master的机器名)
    –new_master_ip = (新master的ip)
    –new_master_port = (新master的端口号)
    –new_master_user = (新master上的用户名)
    –new_master_password = (新master上的用户名及密码)
    –new_master_ssh_user = (从0.56支持, 新master上的ssh用户)
MHA在冻结写的切换过程中会在Master上执行FlUSH TABLES WITH READ LOCK,在这个优雅的切换过程不会有任何写入的。在新的Master在开始授权写的过程中,你可以做和master_ip_failover_script一样的事情。 例如: 创建用户及权限, 执行set global read_only=0, 更新数据库路由表竺。 如果脚本执行退出码不是0 或是10, MHA Manager异常退出并发不会继续进行master切换。
默认这个参数是空的,所以MHA Manager在默认情况下什么也不做。
可以在(MHA Manager package)/samples/scripts/master_ip_online_change。里找到例子脚本。例子脚本包含于MHA Manager源文件或是GitHub的分支中。
如:
参数名                             是否必须     作用域         默认值     例子及说明
master_ip_online_change_script     No             App/Global     null     master_ip_online_change_script= /usr/local/custom_script/master_ip_online_change

shutdown_script
如:    
参数名                 是否必须     作用域         默认值     例子及说明
shutdown_script     No             App/Global     null     shutdown_script= /usr/local/custom_script/master_shutdown

report_script
在Master故障完毕后,也许想发一个送一个报告(如email)报告一下切换完毕或是发生的错误。report_script可以完成这个工作。MHA Manager可以通过以下参数使用:
–orig_master_host = (死掉master机器名)
–new_master_host = (新的master机器名)
–new_slave_hosts = (新的slave机器名列表,用逗号隔开)
–subject = (邮件名)
–body = (正文)
默认这些参数是空的。 所以默认MHA Manager什么事情也不做。
可以在(MHA Manager package)/samples/scripts/send_report里找到例子脚本。例子脚本包含于MHA Manager源文件或是GitHub的分支中。
如:
参数名             是否必须     作用域         默认值     例子及说明
report_script     No             App/Global     null     report_script= /usr/local/custom_script/report

init_conf_load_script
这个参数用于不想设置明文在配置文件中(如:密码相关)。 只用返回”name=value”这样的值。 这个可以用来复盖global配置中的一些值。一个例子脚本如下。
    #!/usr/bin/perl
    print “password=$ROOT_PASS\n”;
    print “repl_password=$REPL_PASS\n”;
如:
参数名                     是否必须     作用域         默认值     例子及说明
init_conf_load_script     No             App/Global     null     report_script= /usr/local/custom_script/init_conf_loader