MHA高可用解决方案

 MHAMaster High Availability,对主节点进行监控,可实现自动故障转移至其它从节点;通过提升某一从节点为新的主节点,基于主从复制实现,还需要客户端配合实现,目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从。

原理:如果master复制二进制日志给slave1 slave2的途中崩溃掉,那么manager会将master没有传递完二进制日志保存下来(差异备份),识别二进制日志备份较多的slave,备份较多的slave将复制内容给其他slave。再选取出一个新master,新master接收差异备份,再通过半同步主从复制传递给剩下的slave。

充当master,一台充当备用master,另外一台充当从库,出于机器成本的考虑,淘宝进行了改造,目前淘宝TMHA已经支持一主一从

官方网站:
https://code.google.com/archive/p/mysql-master-ha/

https://github.com/yoshinorim/mha4mysql-manager/releases
https://github.com/yoshinorim/mha4mysql-node/releases/tag/v0.58

 

 

 

 工作原理

 

 

 

1. MHA利用 SELECT 1 As Value 指令判断master服务器的健康性(和mycat向主节点发送select user() 函数一样确认健康性),一旦master 宕机,MHA 从宕机崩溃的master保存二进制日志事件(binlog events)
2. 识别含有最新更新的slave

3. 应用差异的中继日志(relay log)到其他的slave
4. 应用从master保存的二进制日志事件(binlog events)
5. 提升一个slave为新的master

6. 使其他的slave连接新的master进行复制

MHA软件
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信息
masterha_stop --conf=app1.cnf 停止MHA
masterha_secondary_check 两个或多个网络线路检查MySQL主服务器的可用


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

save_binary_logs     保存和复制master的二进制日志
apply_diff_relay_logs   识别差异的中继日志事件并将其差异的事件应用于其他的slave
filter_mysqlbinlog   去除不必要的ROLLBACK事件(MHA已不再使用此工具)
purge_relay_logs 清除中继日志(不会阻塞SQL线程)

 MHA自定义扩展:

secondary_check_script: 通过多条网络路由检测master的可用性
master_ip_ailover_script: 更新Application使用的masterip
shutdown_script: 强制关闭master节点
report_script: 发送报告
init_conf_load_script: 加载初始配置参数
master_ip_online_change_script:更新master节点ip地址

 MHA配置文件:

global配置,为各application提供默认配置,默认文件路径 /etc/masterha_default.cnf
application配置:为每个主从复制集群

环境:五台主机
10.0.0.30 Mycat 调度器

10.0.0.5 CentOS7 MHA管理端
10.0.0.10 CentOS8 MySQL8.0 Master

10.0.0.20 CentOS8 MySQL8.0 Slave1
10.0.0.100 CentOS8 MySQL8.0 Slave2

1. 在MHA管理端上安装两个包,分别为manager和node rpm包。
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm            ###支持MySQL 5.7和MySQL 8.0 ,和CentOS8版本上的Mariadb -10.3.17不兼容以及不支持CentOS7及其以下版本。
mha4mysql-node-0.58-0.el7.centos.noarch.rpm                  ###用于与被管理的节点相连接。

 

 <在master(10.0.0.10)、slave1(10.0.0.20)、slave2(10.0.0.100)中安装节点包

mha4mysql-node-0.58-0.el7.centos.noarch.rpm  

>

2.MHA管理端编写一个基于key验证的脚本,将生成的authorized_keys 文件拷贝到远程主机(这样MHA管理可以访问被控制的node的二进制日志)。
PS:MHA管理端要与节点下的主从库能够双向连接(否则检测ssh环境会报错),因此将生成私钥整个.ssh文件拷贝到主从库可实现双向连接。

NET=10.0.0
PASSWD=123456

rm -rf /root/.ssh
ssh-keygen -P "" -f /root/.ssh/id_rsa &>/dev/null
ssh-copy-id 127.0.0.1

for i in {1..100};do
IP=$NET.$i
if ping -c1 -w1 $IP &> /dev/null;then
/usr/bin/expect <<-EOF
set time 20
spawn scp -r /root/.ssh $IP:/root/
expect {
"*yes/no" { send "yes\r"; exp_continue }
"*password:" {send "$PASSWD\r"; exp_continue }
"*password:" {send "$PASSWD\r"; exp_continue }
}
expect eof
EOF
fi
done

 

3.在MHA管理端建立配置文件 注意: 此文件的行尾不要加空格等符号,否则坑死你
<标红的地方需要准备两个脚本放置相应目录下,分别为master_ip_failover和sendmail.sh>

mkdir /etc/mastermha/

vim /etc/mastermha/app1.cnf
[server default]
user=cql      #用于远程连接MySQL所有节点的用户,需要有管理员的权限
password=123456
manager_workdir=/data/mastermha/app1/
manager_log=/data/mastermha/app1/manager.log
remote_workdir=/data/mastermha/app1/
ssh_user=root       #用于实现远程ssh基于KEY的连接,访问二进制日志
repl_user=slave     #主从复制的用户信息
repl_password=123456
ping_interval=1     #健康性检查的时间间隔
master_ip_failover_script=/usr/local/bin/master_ip_failover   #切换VIP的perl脚本,也可以使用Keepalived
report_script=/usr/local/bin/sendmail.sh                      #当发生主从切换时执行报警脚本(发邮件)
check_repl_delay=0   #默认如果slave中从库落后主库relaylog 100M,主库不会选择这个从库
为新的master,因为这个从库进行恢复需要很长的时间.通过check_repl_delay=0这个参数,MHA触发主从切换的时候会忽略复制的延时,对于设置了candidate_master=1的从库非常有用,这样确保这个从库一定能成为最新的master
master_binlog_dir=/data/binary_logs/  #指定二进制日志存放的目录(与主库的二进制一路要一致),mha4mysql-manager-0.58必须指定,之前版本不需要指定

[server1]
hostname=10.0.0.10
candidate_master=1
[server2]
hostname=10.0.0.20
candidate_master=1  #设置为优先候选master,即使不是集群中事件最新的slave,也会优先当master,但日志量落后主库100M以上例外
[server3]
hostname=10.0.0.100

 

 

<master_ip_failover脚本>

vim /usr/local/bin/master_ip_failover 
chmod +x /usr/local/bin/master_ip_failover

#!/usr/bin/env perl
use 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 $vip = '10.0.0.150/24';#设置Virtual IP
my $gateway = '10.0.0.254';#网关Gateway IP
my $interface = 'eth0';    #指定VIP所在网卡
my $key = "1";
my $ssh_start_vip = "/sbin/ifconfig $interface:$key $vip;/sbin/arping -I
$interface -c 3 -s $vip $gateway >/dev/null 2>&1";
my $ssh_stop_vip = "/sbin/ifconfig $interface:$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";
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 "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" ) {
# 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 "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";
`ssh $ssh_user\@$orig_master_host \" $ssh_start_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() {
`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";
}

<sendmail.sh脚本>
1)对mail.rc(邮箱系统)在末尾添加以下内容,记得提前安装mailx 包,否则无法发送出去。

vim /etc/mail.rc
set from=1251618589@qq.com
set smtp=smtp.qq.com
set smtp-auth-user=1251618589@qq.com
set smtp-auth-password=lrifcsqrlxbvgifh

2)根据MHA配置文件,编写一个当主从库发生变化后能够通知管理员的邮件

vim /usr/local/bin/sendmail.sh
echo '数据库发生了主从切换' | mail -s 'MHA 报警!!!' 1251618589@qq.com
chmod +x /usr/local/bin/sendmail.sh   ###编辑后增加执行权限

4.实现master与slav1、slave2 的半同步复制(没有必要不建议使用半同步,旧master宕机重启MHA时会因为半同步master插件的影响而无法启动)。
1)开启二进制日志并在my.cnf中指定存放二进制日志独立文件夹/data/mysql(修改属主、组为mysql)。
2)创建拥有管理员权限的账号cql(用于MHA连接节点中所管理的主从库)以及创建主从复制的账号slave(赋予replication权限)
5.master(10.0.0.10)详细配置。
1)skip_name_resolve=1    ###跳过ip的反向解析

general_log                          ###启用通用日志,用于观察数据库发生的事项。

vim /etc/my.cnf
log-bin=/data/binary_logs/mysql-bin   ###主库的二进制路径要与MHA配置文件的一致
server_id=10
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000
skip_name_resolve=1
general_log 

2)配置vip

ifconfig eth0:1 10.0.0.150/24

6.slave1(10.0.0.20)和slave2(10.0.0.100)的详细配置

vim /etc/my.cnf
log-bin=/data/binary_logs/mysql-bin
server_id=100
rpl_semi_sync_slave_enabled=ON
read-only=on   #从库设置为只读,如果master挂掉,那么新master的read-only会被MHA管理端自动改成off
skip_name_resolve=1
general_log

7.启动MHA之前进行环境检查
1)如果ssh检测报错连接被拒绝,排查MHA是否不具备同一个.ssh文件。
2)主库的二进制日志路径必须要与MHA配置文件的一致,否则报错无法获取日志。

masterha_check_ssh --conf=/etc/mastermha/app1.cnf   ###检测被管理节点下的主从库与MHA是否能够双向连接
masterha_check_repl --conf=/etc/mastermha/app1.cnf  ###检测被管理节点下的主从库复制情况

8.启动MHA

#开启MHA,后台执行(生产中建议后台执行)
nohup masterha_manager --conf=/etc/mastermha/app1.cnf &> /dev/null 
#开启MHA,默认是前台运行
masterha_manager --conf=/etc/mastermha/app1.cnf
#查看状态
masterha_check_status --conf=/etc/mastermha/app1.cnf 

 

遇到的坑:
1)启动MHA之前先查看masterhma提供的日志偏移量,将宕机的旧master 进行change master to 
2)
当 旧master 宕机后,MHA自动退出(因为MHA程序是一次性的),退出后如果无法再启动MHA、将相关文件删除再启动、或检查VIP是否飘逸到新master上,如果是旧master"系统"宕机的话这个脚本可能无法将VIP飘逸到新master上(脚本缺陷),因为新master需要手动添加VIP。
3)使用VIP脚本进行飘逸时,所有主机必须安装net-tools包否则无法成功。
3)
rm -rf  /data/mastermha (相关文件),删除后要注意使用"第七步"检查,否则无法启动MHA!!!

4)主从进行切换时,旧master连接slave2出现公钥错误的情况,将/root/.ssh/known_hosts 文件中对方公钥删除重新下载,否则下一次无法启动MHA。
5)
拷贝过去的 .ssh 文件莫名被修改,导致检测ssh链接时失败(重新拷贝)。

6)report_script和/master_ip_failover 如果不加执行权限不仅设置的邮件接收不到vip也无法飘逸。
7)没有特殊要求,不要使用半同步复制,否则在启动MHA时候就会发现新master仍旧与旧master处于一个"从主"关系而不是"主从"关系,这是由于开启半同步插件导致的。如果重新进行半同步配置那是相当的麻烦,因为要重启mysql影响业务。

9.查看旧master的二进制日志偏移量,根据MHA记载的偏移量恢复宕机的旧master进行change master to 以从库的身份继续运行。MHA日志的位置以app1.cnf为准。

cat /data/mastermha/app1/manager.log  | grep 'CHANGE MASTER TO'

10.如果再次运行MHA,需要先删除下面文件包括旧master的二进制日志偏移量(删除后务必记得用命令检查ssh和主从库复制)。

rm -rf /data/mastermha     #每个远程主机即三个节点的的工作目录以及日志的存放路径

11.搭建mycat调度器则在schame.xml 文件中将主库设置的vip添加进去,MHA在旧master宕机后会将VIP飘逸到新master上,这样mycat能够继续实现读写分离,而不担心master单点故障后无法使用。
1)master(10.0.0.10) vip(10.0.0.150) 从库slave1(10.0.0.20)

 

 <编写server.xml与schema.xml后顺利进入Mycat>

 

 

 <分别开启主从库的通用日志检验用户是否能在mycat上实现读写分离>
1)mysql中查看通用日志的方法

show variables like 'general_log';  #查看日志是否开启
set global general_log=on;    #开启日志功能
show variables like 'general_log_file'; #查看日志文件保存位置
set global general_log_file='tmp/general.log'; #设置日志文件保存位置

 2)开启并查看master和slave1通用日志。
<对students表添加一条记录,可以看到主库的通用日志中已将操作记载了下来>

<而从库毫无反应,可见已实现了读写分离>

 3)将主库(10.0.0.10)mysql服务关闭模拟宕机现象,通过MHA将新master(10.0.0.20)提升上来的同时飘逸vip(10.0.0.150)到新master,而Mycat配置文件schema.xml写库添加的IP为VIP,因此理论上来说能够解决掉Mycat主库单点故障而无法将从库提升为主库的问题。

 <可以看到通过VIP的作用的确实现了在Mycat中将slave提升为master想法>

 缺点:如果主从复制因为二进制日志数据量特别巨大导致延迟过重,这时系统宕机那么从库只能接收已获取的二进制日志,未接收部分会丢失。

 

posted on 2021-06-21 21:13  1251618589  阅读(15)  评论(0编辑  收藏  举报

导航