浅谈mysql-MHA
一、MHA简介
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本人youshimaton开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能最大程度上保证数据库的一致性,以达到真正意义上的高可用。
MHA由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。MHA Manager可以独立部署在一台独立的机器上管理多个Master-Slave集群,也可以部署在一台Slave上。当Master出现故障时,它可以自动将最新数据的Slave提升为新的Master,然后将所有其他的Slave重新指向新的Master。整个故障转移过程对应用程序是完全透明的。
【基本原理】:
从宕机崩溃的master保存二进制日志事件(binlog events);
识别含有最新更新的slave;
应用差异的中继日志(relay log)到其他的slave;
应用从master保存的二进制日志事件(binlog events);
提升一个slave为新的master;
使其他的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工具包主要包括以下几个工具:
save_binary_logs 保存和复制master的二进制日志
apply_diff_relay_logs 识别差异的中继日志事件
filter_mysqlbinlog 去除不必要的ROLLBACK事件
purge_relay_logs 清除中继日志
二、公司需求
不影响mysql性能(不开启半同步)
不增加mysql服务器(按原有集群,一主三从)
不使用keepalived(多台切换)
不影响读写分离功能
1.mysql架构
图1.1
【测试MHA】:
角色 |
IP地址 |
主机名 |
MHA manger |
172.16.1.53 |
mha03 |
MySQL master |
172.16.1.51 |
mha01 |
MySQL slave1 |
172.16.1.52 |
mha02 |
MySQL slave2 |
172.16.1.53 |
mha03 |
Atlas |
51、52、53 |
三台都装 |
2.安装mysql
所需安装包:
mysql-5.5.32-linux2.6-x86_64.tar.gz
[root@db01 ~]# cd /usr/local/src/
[root@db01 src]# rz -y #将安装包上传至/usr/local/src目录下
[root@db01src]# tar xf mysql-5.5.32-linux2.6-x86_64.tar.gz #解压二进制包
[root@db01 src]# mv mysql-5.5.32-linux2.6-x86_64/application/mysql-5.5.32 #移动并改名
[root@db01 src]# ln -s /application/mysql-5.5.32//application/mysql #做软连接
[root@db01 scripts]# useradd mysql -s/sbin/nologin -M #创建mysql用户
[root@db01 src]# cd/application/mysql/scripts/ #进入mysql初始化目录
[root@db01 scripts]# ./mysql_install_db--user=mysql --datadir=/application/mysql/data/--basedir=/application/mysql/ #初始化mysql
[root@db01 scripts]# cd ../support-files/ #进入mysql功能文件目录
[root@db01 support-files]# cp my-small.cnf/etc/my.cnf #将mysql的配置文件拷贝到/etc下
[root@db01 support-files]# cp mysql.server/etc/init.d/mysqld #将mysql启动文件拷贝到/etc下
[root@db01support-files]# sed -i 's#/usr/local#/application#g'/etc/init.d/mysqld /application/mysql/bin/mysqld_safe #修改启动文件
[root@db01 support-files]# exportPATH="/application/mysql/bin/:$PATH" #将mysql的命令放置系统中
[root@db01support-files]# echo "exportPATH="/application/mysql/bin/:$PATH"" >> /etc/profile #将以上命令写入环境变量
[root@db01support-files]# source /etc/profile #刷新环境变量
[root@db01support-files]# /etc/init.d/mysqld start #启动mysql
StartingMySQL.... SUCCESS #mysql启动成功
[root@db01support-files]# mysql -uroot password faxuan #给mysql设置密码
[root@db01support-files]# netstat -anltup|grep 3306 #检查mysql端口
[root@db01support-files]# ps -ef|grep mysql #检查mysql进程
至此,mysql就搭建完毕,其它几台也同样
3.设置主从复制
主库和从库都要开启bin-log日志
所有的mysql的server-id不同
创建从库复制权限的用户
【主库操作】:
[root@db01 tools]# vim /etc/my.cnf #修改配置文件
server-id = 1 #主库为1 从库必须大于1
[root@db02tools]# /etc/init.d/mysqld restart #重启mysql
[root@db01 support-files]# mysql -uroot-pfaxuan #登录数据库
mysql> grant replication slave on *.* to slave@'172.16.1.%' identified by '123456'; #授权用户
mysql> show master status; #查看主库bin-log值
+---------------------------+-----------+---------------------+-------------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB |
+---------------------------+------------+---------------------+------------------------+
| mysql-bin.000004 | 257 | | | #记住标颜色的两个值
+----------------------------+-----------+--------------------+-------------------------+
【从库操作】:
[root@db01 tools]# vim /etc/my.cnf #修改配置文件
server-id = 1 ==》 1改为2 #主库为1 从库必须大于1
[root@db02 tools]# /etc/init.d/mysqld restart #重启mysql
[root@db02 tools]# mysql -uroot -pfaxuan #登录数据库
mysql> change master to #在从库上设置主库信息
->master_host='172.16.1.51', #主库IP
->master_user='slave', #授权用户(在主库上操作授权的用户)
->master_password='123456', #授权用户的密码
->master_log_file='mysql-bin.000004', #刚才主库记录的File值
-> master_log_pos=257; #刚才主库记录的Position值
mysql> start slave; #开启复制
mysql> show slave status\G #查看复制状态
Slave_IO_Running: Yes
Slave_SQL_Running:Yes #主从复制成功
至此,主从复制完毕,其它几台也同样
【从库设置】:
[root@db02 tools]# mysql -uroot -pfaxuan #登录mysql
mysql> set global relay_log_purge = 0; #禁用自动删除功能
mysql> set global read_only=1; #从库不可写
[root@db02 tools]# vim /etc/my.cnf #编辑配置文件
relay_log_purge = 0 #不自动删除relay log
[root@db02 tools]# /etc/init.d/mysqld restart #重启mysql
4、安装mysql MHA
所需安装包:
mha4mysql-node-0.56-0.el6.noarch.rpm
mha4mysql-manager-0.56-0.el6.noarch.rpm
【所有节点】:
[root@db01 ~]# yum install perl-DBD-MySQL -y #安装依赖包
将mha4mysql-node-0.56-0.el6.noarch.rpm上传到/usr/local/src下
[root@db01 src]# rpm -ivhmha4mysql-node-0.56-0.el6.noarch.rpm #安装
[root@db01 src]# mysql -uroot -pfaxuan #登录mysql
mysql> grant all privileges on *.* tomha@'172.16.1.%' identified by 'mha'; #添加管理账号
[root@db01 src]# ln -s/application/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog #创建软连接
[root@db01 src]# ln -s/application/mysql/bin/mysql /usr/bin/mysql #创建软连接
【管理节点】:
[root@mha03tools]# wget -O/etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo #使用epel源
[root@db03 src]# yum install -y perl-Config-Tinyepel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes #安装依赖包
将mha4mysql-manager-0.56-0.el6.noarch.rpm 包上传到/usr/local/src下
[root@db03 src]# rpm -ivhmha4mysql-manager-0.56-0.el6.noarch.rpm #安装
[root@db03 src]# mkdir -p /etc/mha #在/etc下创建mha目录
[root@db03 src]# mkdir -p /var/log/mha/app1 #创建日志目录
[root@db03 src]# vim /etc/mha/app1.cnf #编辑配置文件
[server default]
manager_log=/var/log/mha/app1/manager #管理日志目录
manager_workdir=/var/log/mha/app1 #管理工作目录
master_binlog_dir=/application/mysql/data #主库bin-log日志
user=mha #上一步授权的用户
password=mha #上一步授权的密码
ping_interval=2
repl_password=123456 #复制密码(主从)
repl_user=slave #复制用户(主从)
ssh_user=root #ssh远程连接用户
[server1] #第一个主机
hostname=172.16.1.51 #IP
port=3306 #端口
[server2]
candidate_master=1 #优先的新主人(切换主库优先)
check_repl_delay=0 #忽略复制延迟
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
【配置文件详解】:
[server default]
manager_workdir=/var/log/masterha/app1.log ##设置manager的工作目录
manager_log=/var/log/masterha/app1/manager.log ##设置manager的日志
master_binlog_dir=/data/mysql ##设置master 保存binlog的位置,以便MHA可以找到master的日志,我这里的也就是mysql的数据目录
master_ip_failover_script=/usr/local/bin/master_ip_failover ##设置自动failover时候的切换脚本
master_ip_online_change_script=/usr/local/bin/master_ip_online_change ##设置手动切换时候的切换脚本
password=123456 ##设置mysql中root用户的密码,这个密码是前文中创建监控用户的那个密码
user=root 设置监控用户root
ping_interval=1 ##设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行railover
remote_workdir=/tmp ##设置远端mysql在发生切换时binlog的保存位置
repl_password=123456 ##设置复制用户的密码
repl_user=repl ##设置复制环境中的复制用户名
report_script=/usr/local/send_report ##设置发生切换后发送的报警的脚本
secondary_check_script=/usr/local/bin/masterha_secondary_check -s server03 -s server02 --user=root--master_host=server02 --master_ip=192.168.0.50 --master_port=3306 ##一旦MHA到server02的监控之间出现问题,MHA Manager将会尝试从server03登录到server02
shutdown_script="" ##设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机放在发生脑裂,这里没有使用)
ssh_user=root ##设置ssh的登录用户名
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
candidate_master=1 ##设置为候选master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave
check_repl_delay=0 ##默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的master
[server3]
hostname=172.16.1.53
port=3306
【配置ssh秘钥登录】:
[root@db01 src]# ssh-keygen -t rsa #创建秘钥对
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected] #分发公钥,包括自己
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected]
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected]
其它两台也同样配置
【测试】:
在管理机上操作
[root@db03 src]# masterha_check_ssh--conf=/etc/mha/app1.cnf #测试ssh
Tue Aug 2 14:37:44 2016 - [info] All SSHconnection tests passed successfully. #说明ssh配置成功
[root@db03 src]# masterha_check_repl--conf=/etc/mha/app1.cnf #测试复制
MySQL Replication Health is OK. #说明复制配置成功
【启动MHA】:
[root@db03 src]# nohup masterha_manager--conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover /var/log/mha/app1/manager.log 2>&1 &
【测试】:
[root@db02 src]# mysql -uroot -pfaxuan #登录从库的mysql
mysql> show slave status\G #查看复制状态
主库是172.16.1.51
[root@db01 src]# /etc/init.d/mysqld stop #在主库上执行,停掉主库
mysql> show slave status\G #再在从库查看复制状态
可以看到,主库自动切换成了,mha配置文件中设置的172.16.1.53
再次启动172.16.1.51主的mysql后,不会自动加入集群。
需要手动修改配置文件,将172.16.1.51更改为数据从库。
本次MHA架构搭建成功。
三、测试VIP漂移
1.vip配置可以采用两种方式:
通过keepalived的方式管理虚拟ip的漂移。
通过MHA自带脚本方式启动虚拟ip的方式(即不需要keepalived或者heartbeat类似的软件)。
因为公司的需求,这里给大家介绍第二种方式:
2.修改配置文件:
[root@db03 bin]# vim /etc/mha/app1.cnf
[server default]
manager_log=/var/log/mha/app1/manager.log
manager_workdir=/var/log/mha/app1.log
master_binlog_dir=/application/mysql/data
master_ip_failover_script=/usr/local/bin/master_ip_failover #MHA自带脚本
password=mha
ping_interval=1
remote_workdir=/tmp
repl_password=123456
repl_user=slave
shutdown_script=""
ssh_user=root
user=mha
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
在这里不配置之前介绍的以下两个参数:
andidate_master=1 #优先的新主人
heck_repl_delay=0 #忽略复制延迟
因为我们需要实现,多台主机之间互相切换,不使用keepalived
这个配置比较适合两台服务器做半同步,然后再加上keepalived
3.编写脚本:
#!/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 = '172.16.1.55/24'; #虚拟IP
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth1:$key$vip";
my $ssh_stop_vip = "/sbin/ifconfig eth1:$keydown";
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 ( $commandeq "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() {
return0 unless ($ssh_user);
`ssh$ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
"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";
}
[root@db01 ~]# ifconfig eth1:1 172.16.1.55 #手动给master上添加VIP
[root@db01 ~]#ip a|grep eth1
3: eth1:
inet 172.16.1.51/24 brd 172.16.1.255 scopeglobal eth1
inet 172.16.1.55/16 brd172.16.255.255 scope global eth1:1
#查看手动配置的VIP
4.测试:
[root@db01 ~]# sysbench --test=oltp--oltp-table-size=1000000 --oltp-read-only=off --init-rng=on --num-threads=16--max-requests=0 --oltp-dist-type=uniform --max-time=1800 --mysql-user=root--mysql-socket=/tmp/mysql.sock --mysql-password=faxuan --db-driver=mysql--mysql-table-engine=innodb --oltp-test-mode=complex prepare
sysbench 0.4.12: multi-threaded system evaluation benchmark
Creating table 'sbtest'...
Creating 1000000 records in table 'sbtest'... #插入100000万条数据
mysql> stopslave; #在从库52上执行,停止复制
[root@db01 ~]#/etc/init.d/mysqld stop #写完数据后,将主库进程停掉
#VIP已经不在51上了