简介:
MHA是一位日本MySQL大牛用Perl写的一套MySQL故障切换方案,来保证 数据库系统的高可用.在宕机的时间内(通常10—30秒内),完成故障切换,部署MHA,可避免主从一致性问题,节约购买新服务器的费用,不影响服务器性能,易安装,不改变现有部署。
还支持在线切换,从当前运行master切换到一个新的master上面,只需要很短的时间(0.5-2秒内),此时仅仅阻塞写操作,并不影响读操作,便于主机硬件维护。
一: 前期准备
1: 准备4台服务器 1核1G
2: ip规划:
高可用lnmp服务器集群ip部署规则
服务器名称 ip 运行的服务
Mysql主服务器 192.168.206.139 Mysql+node
Mysql从服务器 192.168.206.140 Mysql+node
Mysql从服务器 192.168.206.141 Mysql+node
manager 192.168.206.151 Manager+node
vip ip 192.168.206.121
二: 安装前的检查:
1: 检查网络:
ping www.baidu.com
2: 检查防火墙:
systemctl status firewalld
关闭防火墙: systemctl stop firewalld
关闭setenforce: setenforce 0
3: 检查内核系统,要保持一致
uname -r
cat /etc/redhat-release
4: 时间同步 检查时间
ntpdate ntp.aliyun.com 同步阿里云的时间
检查时间
date
三 安装部署
1: 配置免密
(139 140 141 151)
ssh-keygen
ssh-copy-id
2: 安装mysql 配置mysql文件
(139 140 141 )
yum -y install mariadb mariadb-server
192.168.206.139(主)
vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
If you need to run mysqld under a different user or group,
#customize your systemd unit file for mariadb according to the
instructions in http://fedoraproject.org/wiki/Systemd
server-id=1
log-bin=mysql-bin
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
include all files from the config directory
!includedir /etc/my.cnf.d
192.168.206.140(从)
vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#Settings user and group are ignored when systemd is used.
#If you need to run mysqld under a different user or group,
#customize your systemd unit file for mariadb according to the
#instructions in http://fedoraproject.org/wiki/Systemd
server-id=2
log-bin=slave-bin
relay-log=slave-log
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
include all files from the config directory
!includedir /etc/my.cnf.d
192.168.206.141(从)
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
#Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#Settings user and group are ignored when systemd is used.
#If you need to run mysqld under a different user or group,
#customize your systemd unit file for mariadb according to the
instructions in http://fedoraproject.org/wiki/Systemd
server-id=3
log-bin=slave2-bin
relay-log=slave2-log
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
!includedir /etc/my.cnf.d
3: 配置主从
192.168.206.139(主)
mysql
grant all on . to tom@‘192.168.206.140’ identified by ‘123’;
grant all on . to tom@‘192.168.206.141’ identified by ‘123’;
flush privileges ;
show master status;
192.168.206.140(从)
mysql
change master to master_host=‘192.168.206.139’, master_user=‘tom’, master_password=‘123’, master_log_file=‘mysql-bin.000003’, master_log_pos=592;
start slave ;
show slave status\G;
192.168.206.141(从)
mysql
change master to master_host=‘192.168.206.139’, master_user=‘tom’, master_password=‘123’, master_log_file=‘mysql-bin.000003’, master_log_pos=592;
start slave ;
show slave status\G;
139 140 141(master,slaves)
grant all privileges on . to tom@‘192.168.206.%’ identified by ‘123’;
flush privileges;
4: node节点安装
139 140 141 151 all
yum -y install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-DBD-MySQL perl-devel perl-CPAN
上传mha的node源码包
mha4mysql-node-0.57.tar.gz (可去自行下载)
mkdir /etc/mha
tar zxf mha4mysql-node-0.57.tar.gz -C /etc/mha
mv /etc/mha/mha4mysql-node-0.57/ /etc/mha/node
cd /etc/mha/node
perl Makefile.PL
make && make install
注意:编译安装前最好做时间同步.
5: manager节点安装
192.168.206.151 (manager)
yum -y install epel-release --nogpgcheck
yum -y install perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
上传mha的manager的源码包
mha4mysql-manager-0.57.tar.gz (自行下载)
tar zxf mha4mysql-manager-0.57.tar.gz -C /etc/mha
mv /etc/mha/mha4mysql-manager-0.57/ /etc/mha/manager
cd /etc/mha/manager
perl Makefile.PL
make && make install
修改manager的配置文件
mkdir /etc/mha/app1
cp /etc/mha/manager/samples/conf/app1.cnf /etc/mha
vim /etc/mha/app1.cnf
[server default]
manager_workdir=/etc/mha/app1
manager_log=/etc/mha/app1/manager.log
master_binlog_dir="/var/lib/mysql"
remote_workdir=/etc/mha/app1
master_ip_failover_script=/etc/mha/master_ip_failover
master_ip_online_change_script=/etc/mha/master_ip_online_change
report_script=/etc/mha/send_report
user=tom
password=123
repl_user=tom
repl_password=123
ping_interval=1
secondary_check_script= masterha_secondary_check -s 192.168.206.140 -s 192.168.206.141
[server1]
hostname=192.168.206.139
port=3306
ssh_port=22
[server2]
hostname=192.168.206.140
port=3306
ssh_port=22
candidate_master=1
check_repl_delay=0
[server3]
hostname=192.168.206.141
port=3306
no_master=1
ssh_port=22
6: 配置脚本
给两台从服务器配置脚本
192.168.206.140 192.168.206.141 (从)
mysql
set global relay_log_purge=0;
exit
mkdir /var/lib/mysql/logs1
ln /var/lib/mysql/relay-log* /var/lib/mysql/logs1/
vim /etc/mha/purge_relay_log.sh
#!/bin/bash
user=root
passwd=123
port=3306
log_dir=’/var/lib/mysql/’
work_dir=’/var/lib/mysql/logs1’
purge=’/usr/local/bin/purge_relay_logs’
if [ ! -d $log_dir ]
then
mkdir $log_dir -p
fi
p u r g e − − u s e r = purge --user= purge−−user=user --password=$passwd --disable_relay_log_purge --port= p o r t − − h o s t = l o c a l h o s t − − w o r k d i r = port --host=localhost --workdir= port−−host=localhost−−workdir=work_dir >> $log_dir/purge_relay_logs.log 2>&1
测试
mysqladmin -uroot password 123
purge_relay_logs --user=root --host=localhost --port=3306 --password=123 -disable_relay_log_purge --workdir=/var/lib/mysql/
出现succeeded成功
给四台服务器配置三个脚本(自动切换脚本 手动切换脚本 报警脚本)
自动切换脚本
vim /etc/mha/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 = ‘192.168.206.121/24’;
my $key = ‘0’;
my s s h s t a r t v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_start_vip = "/sbin/ifconfig ens33: sshstartvip="/sbin/ifconfigens33:key $vip";
my s s h s t o p v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_stop_vip = "/sbin/ifconfig ens33: sshstopvip="/sbin/ifconfigens33: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==== s s h s t o p v i p = = ssh_stop_vip== sshstopvip==ssh_start_vip===\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();
KaTeX parse error: Expected 'EOF', got '}' at position 28: …0; }̲; i…@) {
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";
}
手动切换脚本
vim /etc/mha/master_ip_online_change
#!/usr/bin/env perl
use strict;
use warnings FATAL =>‘all’;
use Getopt::Long;
my $vip = ‘192.168.206.121/24’; # Virtual IP
my $key = “0”;
my s s h s t a r t v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_start_vip = "/sbin/ifconfig ens33: sshstartvip="/sbin/ifconfigens33:key $vip";
my s s h s t o p v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_stop_vip = "/sbin/ifconfig ens33: sshstopvip="/sbin/ifconfigens33:key down";
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==== s s h s t o p v i p = = ssh_stop_vip== sshstopvip==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();
KaTeX parse error: Expected 'EOF', got '}' at position 28: …0; }̲; i…@) {
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_start_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";
}
报警脚本
vim /etc/mha/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.qq.com’;
my $mail_from=‘[email protected]’;
my $mail_user=‘[email protected]’;
my $mail_pass=‘nxyhbucpcpwxceag’;
my $mail_to=[‘[email protected]’];
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( s m t p , smtp, smtp,mail_from, m a i l u s e r , mail_user, mailuser,mail_pass, m a i l t o , mail_to, mailto,subject,$body);
sub mailToContacts {
my ( $smtp, $mail_from, $user, $passwd, $mail_to, $subject, $msg ) = @_;
open my D E B U G , " > / t m p / m o n i t o r m a i l . l o g " o r d i e " C a n ′ t o p e n t h e d e b u g f i l e : DEBUG, "> /tmp/monitormail.log" or die "Can't open the debug file: DEBUG,">/tmp/monitormail.log"ordie"Can′topenthedebugfile:!\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;
给三个脚本文件增加执行权限
chmod +x master_ip_failover
chmod +x master_ip_online_change
chmod +x send_report
7: manager检测及开启
151(manager)
ssh免密检测
/etc/mha/manager/bin/masterha_check_ssh --conf=/etc/mha/app1.cnf
出现successfully成功
检测mysql主从是否正常
/etc/mha/manager/bin/masterha_check_repl --conf=/etc/mha/app1.cnf
最后出现is ok 为正常
四: 测试
给主数据库服务器添加vip
Ifconfig ens33:0 192.168.206.121 netmask 255.255.255.0
Ip a
启动manager
nohup /etc/mha/manager/bin/masterha_manager --conf=/etc/mha/app1.cnf --ignore_last_failover >/tmp/mha_manager.log < /dev/null 2>&1 &
查看主的状态
/etc/mha/manager/bin/masterha_check_status --conf=/etc/mha/app1.cnf
关闭主mysql
systemctl stop mariadb
查看manager日志
tail -100f /etc/mha/app1/manager.log
将关闭的mysql开启并做成新主的从
systemctl start mariadb
change master to master_host=‘192.168.206.140’,master_user=‘tom’, master_password=‘123’, master_log_file=‘slave-bin.000003’, master_log_pos=603;
start slave;
show slave status\G;
修改manager配置文件
vim /etc/mha/app1.cnf
启动manager
nohup /etc/mha/manager/bin/masterha_manager --conf=/etc/mha/app1.cnf --ignore_last_failover >/tmp/mha_manager.log < /dev/null 2>&1 &
关闭新主mysql服务器的mysql
systmcalt stop mariadb
查看vip是否漂移
从mysql变为主 vip生成 成功
五: 疑难问题解决 坑点分析
1: 免密登录一定要每一台都要做.
六: 总结
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。
优点:
由per语言开发的开源工具
可以支持基于GTID的复制模式
当主DB不可用时,从多个从服务器中选举出来新的主DB
提供了主从切换和故障转移功能,在线故障转移时不易丢失数据
同一个监控节点可以监控多个集群
缺点:
需要编写脚本或利用第三方工具来实现VIP的配置
MHA启动后只只监控主服务器是否可用,没办法监控从服务器
需要基于SSH免认证登陆配置,存在一定的安全隐患
没有提供从服务器的读负载均衡功能