1 MHA介绍
官方介绍:
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司的youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
1.1 基本介绍
该软件由两部分组成: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服务器上,因此可以保证所有节点的数据一致性。
目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库。
MHA有两个重要的角色,一个是manager,另外一个是node;
MHA Manager:通常单独部署在一台独立机器上管理多个master/slave集群;
MHA node:运行在每台MySQL服务器上(master/slave/manager),它通过监控具备解析和清理logs功能的脚本来监控故障转移。
1.2 mha原理
通过上图:MHA Manager管理多组主从复制。可以将MHA工作原理总结为如下:
(1)从宕机崩溃的master保存二进制日志事件(binlog events);
(2)识别含有最新更新的slave;
(3)应用差异的中继日志(relay log)到其他的slave;
(4)应用从master保存的二进制日志事件(binlog events);
(5)提升一个slave为新的master;
(6)使其他的slave连接新的master进行复制;
1.3 实验环境
主机名 | IP地址(NAT) | 描述 |
db01 | eth0:10.10.16.224 | 系统:CentOS6.8 安装:mysql5.6.34 master(主) |
db02 | eth0:10.10.16.225 | 系统:CentOS6.8 安装:mysql5.6.34 slave(从) |
db03 | eth0:10.10.16.229 | 系统:CentOS6.8 安装:mysql5.6.34 slave(从) |
1.4 软件包准备
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线程)
PS:这里建议将以上脚本统一放到bin目录下
mha管理节点安装包: mha4mysql-manager-0.56-0.el6.noarch.rpm mha4mysql-manager-0.56.tar.gz
mha node节点安装包: mha4mysql-node-0.56-0.el6.noarch.rpm mha4mysql-node-0.56.tar.gz
mysql中间件: Atlas-2.2.1.el6.x86_64.rpm
2 mha部署
2.1 环境准备
这里是在所有节点上执行。
2.11 设置主机名解析
设置主机名解析主要是便于主机之间无间缝操作和互通:
[root@db01 ~]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4::1 localhost localhost.localdomain localhost6 localhost6.localdomain610.10.16.224 db0110.10.16.225 db0210.10.16.229 db03
2.12 配置ssh互信
使用检查mha ssh插件脚本检测通过:
#创建秘钥对[root@db01 ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1#发送公钥,包括自己[root@db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.10.16.224[root@db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.10.16.225[root@db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.10.16.229
2.13 关闭iptables和selinux
防报错,测试环境建议关闭iptables和selinux:
/etc/init.d/iptables stop #centos7关闭Firewallchkconfig iptables offsed -i 's#SELINUX=.*#SELINUX=disabled#g' /etc/selinux/configsed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/configgrep SELINUX=disabled /etc/selinux/config setenforce 0getenforce
2.14 使用epel源
安装阿里云epel源:
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
2.15 安装依赖包
在所有节点安装MHA node所需的perl模块(需要有安装epel源)
yum install perl-DBD-MySQL -y
2.2 安装mysql
目前MHA主要支持一主多从的架构,要搭建MHA,要求一个主从复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库,因为至少需要三台服务器。
安装脚本参考: 此方式安装过程较长
手动安装步骤:建议二进制安装,安装包较大(300M),直接解压,步骤简洁,下面主要介绍手动安装:
2.21 手动安装
安装包下载地址:
链接: 提取码: bj27
上传mysql安装包(mysql-5.6.34-linux-glibc2.5-x86_64.tar.gz)至/home/tools
创建安装目录[root@db01 tools]# mkdir /usr/local/mysql-5.6.34 #解压mysql二进制包[root@db01 tools]# tar xf mysql-5.6.34-linux-glibc2.5-x86_64.tar.gz -C /usr/local/mysql-5.6.34#做软链接[root@db01 tools]# ln -s /usr/local/mysql-5.6.34/ /usr/local/mysql#创建mysql用户[root@db01 tools]# useradd mysql -s /sbin/nologin -M#进入mysql初始化目录[root@db01 tools]# cd /usr/local/mysql/scripts/#初始化mysql[root@db01 scripts]# ./mysql_install_db \--user=mysql \--datadir=/usr/local/mysql/data/ \--basedir=/usr/local/mysql/#注解--user: 指定mysql用户--datadir:指定mysql数据存放目录--basedir:指定mysql base目录#拷贝mysql配置文件[root@db01 ~]# \cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf#拷贝mysql启动脚本[root@db01 ~]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld#修改mysql默认安装目录(否则无法启动) 默认/usr/local不需要改[root@db01 ~]# sed -i 's#/usr/local#/your_path#g' /etc/init.d/mysqld #这里省略...[root@db01 ~]# sed -i 's#/usr/local#/your_path#g' /usr/local/mysql/bin/mysqld_safe #这里省略...#配置mysql环境变量[root@db01 ~]# echo 'export PATH="/usr/local/mysql/bin:$PATH"' >> /etc/profile.d/mysql.sh#刷新环境变量[root@db01 ~]# source /etc/profile
启动mysql和设置密码:
#加入开机自启[root@db01 ~]# chkconfig mysqld on#启动mysql[root@db01 ~]# /etc/init.d/mysqld startStarting MySQL........... SUCCESS! #启动成功#配置mysql密码为[root@db01 ~]# mysqladmin -uroot password 123456
说明:以上步骤在所有节点操作。
2.22 配置主从复制
先决条件:(任何一台服务器,除了MySQL主库)
● 主库和从库都要开启binlog
● 主库和从库server-id不同
● 要有主从复制用户
1.主库操作:
开启binlog和server_id修改:
#编辑mysql配置文件[root@db01 ~]# vim /etc/my.cnf#在mysqld标签下配置[mysqld]log_bin=mysql-bin #开启binlog日志server_id =1 #主库server-id为1,从库必须大于1
创建主从复制用户:
#登录数据库[root@db01 ~]# mysql -uroot –p'123456'#创建rep用户mysql> grant replication slave on *.* to rep@'10.10.16.%' identified by '123456'; #监控用户(master和slave上都执行)
2.从库操作:开启binlog和server_id修改:
#修改db02配置文件[root@db02 ~]# vim /etc/my.cnf#在mysqld标签下配置[mysqld]log_bin=mysql-bin #开启binlog日志server_id =5 #主库server-id为1,从库必须大于1[root@db02 ~]# /etc/init.d/mysqld restart #重启mysql
从库db03同上,server_id=10,开启binlog,步骤省略。
注:在以往如果是基于binlog日志的主从复制,则必须要记住主库的master状态信息。
mysql> show master status;+------------------+----------+| File | Position |+------------------+----------+| mysql-bin.000002 | 120 |+------------------+----------+
3.开启GTID:
即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。参考,更具体的说明见。
没开启之前先看一下GTID的状态:
mysql> show global variables like '%gtid%';
编辑mysql配置文件(主库从库都需要修改):
主从环境的搭建和5.5没有什么区别,唯一需要注意的是:开启GTID需要启用这三个参数:[root@db01 ~]# vim /etc/my.cnf#在[mysqld]标签下添加[mysqld]gtid_mode=ONlog_slave_updatesenforce_gtid_consistency#重启数据库[root@db01 ~]# /etc/init.d/mysqld restart#检查GTID状态mysql> show global variables like '%gtid%';+--------------------------+-------+| Variable_name | Value |+--------------------------+-------+| enforce_gtid_consistency | ON | #执行GTID一致| gtid_executed | || gtid_mode | ON | #开启GTID模块| gtid_owned | || gtid_purged | |+--------------------------+-------+
注:主库从库都需要开启GTID否则在做主从复制的时候就会报错:
配置mysql主从复制时,在从机上需要进行CHANGE MASTER TO操作,以确定需要同步的主机IP,用户名,密码,binlog文件,binlog位置等信息。
[root@db02 ~]# mysql -uroot -p'123456'mysql> change master to-> master_host='10.10.16.224',-> master_user='rep',-> master_password='123456',-> master_auto_position=1;ERROR 1777 (HY000): CHANGE MASTER TO MASTER_AUTO_POSITION = 1 can only be executed when @@GLOBAL.GTID_MODE = ON.
4.配置主从复制:
从库也需要创建主从复制用户:上面执行过可以忽略
mysql> grant replication slave on *.* to rep@'10.10.16.%' identified by '123456';Query OK, 0 rows affected (0.00 sec)mysql> select user,host from mysql.user;
开始配置主从复制
mysql> change master to master_host='10.10.16.224',master_user='rep',master_password='123456',master_auto_position=1;或者:CHANGE MASTER TO MASTER_HOST='10.10.16.224',MASTER_USER='rep', MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000010',MASTER_LOG_POS=112; #可变化的位置点和log文件mysql> start slave; #开启slavemysql> show slave status\G #查看slave状态
说明:master_auto_position=1 为GTID位置点为1,MASTER_LOG_FILE为master的binlog文件
从库设置禁用自动删除relay log 功能:
mysql> set global relay_log_purge = 0; mysql> set global read_only=1; #设置只读#编辑配置文件[root@db02 ~]# vim /etc/my.cnf[mysqld]#禁用自动删除relay log 永久生效relay_log_purge = 0
至此,主从部署完成。
2.3 安装mha node
#Debian下载地址
#mha下载地址,需要翻墙
在所有节点进行安装mha node: 链接:
根据系统环境上传对应mha安装包到指定目录:这里提供两种安装方式的包,便于理解
[root@db01 tools]# rz -bemha4mysql-manager-0.56-0.el6.noarch.rpmmha4mysql-manager-0.56.tar.gzmha4mysql-node-0.56-0.el6.noarch.rpmmha4mysql-node-0.56.tar.gz
开始安装node包:这里使用rpm包安装
[root@db01 tools]# rpm -ivh mha4mysql-node-0.56-0.el6.noarch.rpm
添加mha管理账号:
#主库上创建一个管理mha的账号mysql> grant all privileges on *.* to 'mha'@'10.10.16.%' identified by 'mha';#主库上创建,从库会自动复制(在从库上查看)mysql> select user,host from mysql.user;
创建命令软链接(所有节点):
#如果不创建命令软连接,检测mha复制情况的时候会报错[root@db01 ~]# ln -s /usr/local/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog[root@db01 ~]# ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
二进制安装mha node(任选其一):
[root@db01 ~]# yum -y install perl-DBD-MySQL //先安装所需的perl模块[root@db01 ~]# tar -zvxf mha4mysql-node-0.56.tar.gz[root@db01 ~]# cd mha4mysql-node-0.56[root@db01 mha4mysql-node-0.56]# perl Makefile.PL这一步可能报错如下:1)Can't locate ExtUtils/MakeMaker.pm in @INC (@INC contains: inc /usr/local/lib64/perl5 /usr/local/share/perl5......解决办法:[root@db01 mha4mysql-node-0.56]# yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker 2)Can't locate CPAN.pm in @INC (@INC contains: inc /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5....解决办法:[root@db01 mha4mysql-node-0.56]# yum install -y perl-CPAN[root@db01 mha4mysql-node-0.56]# make && make install
2.4 安装mha manager
mha manager可以部署在从库上,也可以部署其他机器上,这里部署在db03上:生产环境根据实际ip更改配置和自动切换脚本,采用rpm安装
2.41 安装mha manager依赖的per模块
yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes -y
2.42 安装mha manager软件包
rpm -ivh mha4mysql-manager-0.56-0.el6.noarch.rpm
如果报错:error: Failed dependencies: xxxxxxxxxxxxx
遇到此问题时,可以在安装rpm包命令的后面加两个参数,如:rpm -ivh jdk-1_5_0_07-linux-i586.rpm --nodeps --force
--nodeps --force 参数意义:安装时不再分析包之间的依赖关系而强制安装。
修改对应mysql环境所需的master_ip_failover脚本和mha配置文件
manger管理IP | 配mha配置文件名 | 脚本名 |
10.10.16.224 | base.cnf | base_master_ip_failover |
10.10.16.225 | exam_study.cnf | exam_study_master_ip_failover |
二进制安装mha manager(任选其一):
安装perl的mysql包:[root@db03 ~]# yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Config-IniFiles perl-Time-HiRes -y 安装MHA Manager软件包:[root@db03 ~]# tar -xvf mha4mysql-manager-0.56.tar.gz[root@db03 ~]# cd mha4mysql-manager-0.56 [root@db03 mha4mysql-manager-0.56]# perl Makefile.PL[root@db03 mha4mysql-manager-0.56]# make && make install 安装完MHA Manager后,在/usr/local/bin目录下会生成以下脚本:[root@db03 mha4mysql-manager-0.56]# ll /usr/local/bin/总用量 84-r-xr-xr-x. 1 root root 16367 5月 31 21:37 apply_diff_relay_logs-r-xr-xr-x. 1 root root 4807 5月 31 21:37 filter_mysqlbinlog-r-xr-xr-x. 1 root root 1995 5月 31 22:23 masterha_check_repl-r-xr-xr-x. 1 root root 1779 5月 31 22:23 masterha_check_ssh-r-xr-xr-x. 1 root root 1865 5月 31 22:23 masterha_check_status-r-xr-xr-x. 1 root root 3201 5月 31 22:23 masterha_conf_host-r-xr-xr-x. 1 root root 2517 5月 31 22:23 masterha_manager-r-xr-xr-x. 1 root root 2165 5月 31 22:23 masterha_master_monitor-r-xr-xr-x. 1 root root 2373 5月 31 22:23 masterha_master_switch-r-xr-xr-x. 1 root root 5171 5月 31 22:23 masterha_secondary_check-r-xr-xr-x. 1 root root 1739 5月 31 22:23 masterha_stop-r-xr-xr-x. 1 root root 8261 5月 31 21:37 purge_relay_logs-r-xr-xr-x. 1 root root 7525 5月 31 21:37 save_binary_logs 其中:masterha_check_repl 检查MySQL复制状况masterha_check_ssh 检查MHA的SSH配置状况masterha_check_status 检测当前MHA运行状态masterha_conf_host 添加或删除配置的server信息masterha_manager 启动MHAmasterha_stop 停止MHAmasterha_master_monitor 检测master是否宕机masterha_master_switch 控制故障转移(自动或者手动)masterha_secondary_check 多种线路检测master是否存活 另外:在mha4mysql-manager-0.56/samples/scripts下还有以下脚本,需要将其复制到/usr/local/bin[root@db03 mha4mysql-manager-0.56]# cd samples/scripts/[root@db03 scripts]# ll总用量 32-rwxr-xr-x. 1 4984 users 3648 4月 1 2014 master_ip_failover //自动切换时VIP管理脚本,不是必须,如果我们使用keepalived的,我们可以自己编写脚本完成对vip的管理,比如监控mysql,如果mysql异常,我们停止keepalived就行,这样vip就会自动漂移-rwxr-xr-x. 1 4984 users 9870 4月 1 2014 master_ip_online_change //在线切换时VIP脚本,不是必须,同样可以可以自行编写简单的shell完成-rwxr-xr-x. 1 4984 users 11867 4月 1 2014 power_manager //故障发生后关闭master脚本,不是必须-rwxr-xr-x. 1 4984 users 1360 4月 1 2014 send_report //故障切换发送报警脚本,不是必须,可自行编写简单的shell完成[root@Manager_Slave scripts]# cp ./* /usr/local/bin/
2.43 编辑manager配置文件
#创建配置文件目录和#日志目录[root@db03 ~]# mkdir -p /etc/mha[root@db03 ~]# mkdir -p /var/log/mha/app1#编辑mha配置文件[root@db03 ~]# vim /etc/mha/app1.cnf[server default]#设置manager的工作目录manager_workdir=/var/log/mha/app1#设置manager的日志文件manager_log=/var/log/mha/app1/manager#master保存binlog的位置master_binlog_dir=/usr/local/mysql/data#监控用户user=mhapassword=mha#ping包间隔频率ping_interval=1#主从复制用户repl_user=reprepl_password=123456ssh_user=root[server1]hostname=10.10.16.224port=3306[server2]#优先提升为主库candidate_master=1#忽略延迟check_repl_delay=0hostname=10.10.16.225port=3306[server3]hostname=10.10.16.229port=3306
完整配置文件详解:举例
[server default]#设置manager的工作目录manager_workdir=/var/log/masterha/app1#设置manager的日志manager_log=/var/log/masterha/app1/manager.log #设置master 保存binlog的位置,以便MHA可以找到master的日志,我这里的也就是mysql的数据目录master_binlog_dir=/data/mysql#设置自动failover时候的切换脚本master_ip_failover_script= /usr/local/bin/master_ip_failover#设置手动切换时候的切换脚本master_ip_online_change_script= /usr/local/bin/master_ip_online_change#设置mysql中root用户的密码,这个密码是前文中创建监控用户的那个密码password=123456#设置监控用户rootuser=root#设置监控主库,发送ping包的时间间隔,尝试三次没有回应的时候自动进行failoverping_interval=1#设置远端mysql在发生切换时binlog的保存位置remote_workdir=/tmp#设置复制用户的密码repl_password=123456#设置复制环境中的复制用户名 repl_user=rep#设置发生切换后发送的报警的脚本report_script=/usr/local/send_report#一旦MHA到server02的监控之间出现问题,MHA Manager将会尝试从server03登录到server02secondary_check_script= /usr/local/bin/masterha_secondary_check -s server03 -s server02 --user=root --master_host=server02 --master_ip=192.168.56.11 --master_port=3306#设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机放在发生脑裂,这里没有使用)shutdown_script=""#设置ssh的登录用户名ssh_user=root [server1]hostname=192.168.56.11port=3306[server2]hostname=192.168.56.12port=3306#设置为候选master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slavecandidate_master=1#默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的mastercheck_repl_delay=0[server3]hostname=192.168.56.13#不让成为主no_master=1port=3306
2.44 启动测试
测试ssh是否OK
[root@db03 ~]# masterha_check_ssh --conf=/etc/mha/app1.cnf#看到如下字样,则测试成功Tue Mar 7 01:03:33 2017 - [info] All SSH connection tests passed successfully.
测试复制是否OK
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf#看到如下字样,则测试成功MySQL Replication Health is OK.
如果报错:1045:Access denied for user 'mha'@'db03' (using password: YES), but this is not a MySQL crash. Check MySQL server settings.
处理办法:在mysql配置文件mysqld标签下加上 skip-name-resolve ,重启mysql
2.45 启动mha
[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &[root@db03 tools]# masterha_check_status --conf=/etc/mha/app1.cnfapp1 (pid:45489) is running(0:PING_OK), master:10.10.16.224
说明:每次切换以后,,MHA会自动关闭,需要修改配置文件以后再开启
2.46 切换master测试
停掉主库,模拟主库发生故障,进行自动failover操作。
[root@db01 ~]# /etc/init.d/mysqld stopShutting down MySQL..... SUCCESS!
登录从库(db02),查看salve状态:
[root@db02 ~]# mysql -uroot -p123456#查看slave状态mysql> show slave status\G#db02的slave已经为空Empty set (0.00 sec)
登录从库(db03),查看slave状态:
[root@db03 ~]# mysql -uroot -p123456#查看slave状态mysql> show slave status\G #已经自动切换到225,MHA高可用成功启用了新的主库*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.16.225 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000006 Read_Master_Log_Pos: 191 Relay_Log_File: db03-relay-bin.000002 Relay_Log_Pos: 361 Relay_Master_Log_File: mysql-bin.000006 Slave_IO_Running: Yes Slave_SQL_Running: Yes........
2.47 重新指向新的master
此时再把db01启动查看主库备份时的binlog名称和位置,MASTER_LOG_FILE和MASTER_LOG_POS:
修复宕机的Master,把它变成从库;
通常情况下自动切换以后,原master可能已经废弃掉,待原master主机修复后,如果数据完整的情况下,可能想把原来master重新作为新主库的slave,这时我们可以借助当时自动切换时刻的MHA日志来完成对原master的修复。下面是提取相关日志的命令:
[root@db03 ~]# grep -i "change master to" /var/log/mha/app1/managerSat Jul 1 23:02:20 2017 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO xx MASTER_HOST='10.10.16.225', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='rep', MASTER_PASSWORD='x';
获取上述信息以后,就可以直接在修复后的master上执行change master to相关操作,重新作为从库了。在db01上操作:
mysql> CHANGE MASTER TO MASTER_HOST='10.10.16.225', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='rep', MASTER_PASSWORD='123456';mysql> start slave;mysql> show slave status\G #检查复制状态(可以看到复制成功)
在mha manager上再次把配置文件加上去:
[root@db03 ~]# vim /etc/mha/app1.cnf[server1]hostname=10.10.16.224port=3306
再次检查mha运行状态:
[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnfapp1 (pid:2285) is running(0:PING_OK), master:10.10.16.224#停掉mha命令masterha_stop --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1
2.5 定期清除relay_logs
mysql默认会自动清理relay_logs,但MHA会使用relay_logs在主从切换时恢复数据,所以MHA会关闭relay_logs的自动清理功能,会导致relay_logs逐渐增多.
*/30 * * * * purge_relay_logs --user=root --password=123456 --host=10.10.16.* --port=3306 --disable_relay_log_purge >> /var/log/relay_log_purge.txt 2>&1
2.6 配置VIP漂移
3.1 漂移的两种方式
● 通过keepalived的方式,管理虚拟IP的漂移
usr/local/bin/master_ip_failover添加或者修改的内容意思是当主库数据库发生故障时,会触发MHA切换,MHA Manager会停掉主库上的keepalived服务,触发虚拟ip漂移到备选从库,从而完成切换。当然可以在keepalived里面引入脚本,这个脚本监控mysql是否正常运行,如果不正常,则调用该脚本杀掉keepalived进程。
● 通过MHA自带脚本方式,管理虚拟IP的漂移
这里是修改/usr/local/bin/master_ip_failover,也可以使用其他的语言完成,比如php语言。使用php脚本编写的failover这里就不介绍了。修改完成后内容如下,而且如果使用脚本管理vip的话,需要手动在master服务器上绑定一个vip 为了防止脑裂发生,推荐生产环境采用脚本的方式来管理虚拟ip,而不是使用keepalived来完成。到此为止,基本MHA集群已经配置完毕。接下来就是实际的测试环节了。通过一些测试来看一下MHA到底是如何进行工作的
3.2 mha脚本方式
修改配置文件,添加脚本文件路径
#编辑配置文件/etc/mha/app1.cnf#在[server default]标签下添加[server default]#使用MHA自带脚本master_ip_failover_script=/usr/local/bin/master_ip_failover
脚本内容:/usr/local/bin/下
vim master_ip_failover#!/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 $vip = '10.10.16.232/24';my $key = '0';my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";my $ssh_stop_vip = "/sbin/ifconfig eth0:$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" ) { 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";}
添加执行权限:
[root@db03 bin]# chmod +x /usr/local/bin/master_ip_failover
3.3 手动绑定VIP
#绑定vip:
ifconfig eth0:0 10.10.16.232/24 #在现在的主库执行——10.10.16.225
手动删除绑定的vip:
ip addr del 10.10.16.232 dev eth0:0
查看vip:
[root@db02 ~]# ifconfig eth0:0 eth0:0: flags=4163mtu 1500 inet 10.10.16.232 netmask 255.255.255.0 broadcast 10.10.16.255 ether 00:0c:29:33:c6:fa txqueuelen 1000 (Ethernet)[root@db02 ~]# ip a|grep eth0 2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 inet 10.10.16.225/24 brd 10.10.16.255 scope global eth0 inet 10.10.16.232/24 brd 10.10.16.255 scope global secondary eth0:0
3.4 重启mha
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf #检测复制#停止MHA:[root@db03 scripts]# masterha_stop --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 #修改配置:[root@db03 mha]# vim app1.cnf#添加mha删除掉的server1[server1]candidate_master=1check_repl_delay=0hostname=10.10.16.224port=3306#开启MHA:[root@db03 scripts]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 & [root@db03 scripts]# tail -100f /var/log/mha/app1/manager #查看日志,是否正常
3.5 测试VIP漂移
测试VIP是否能根据主库来漂移
登录db01查看slave:
mysql> show slave status\G*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.16.224 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000007 Read_Master_Log_Pos: 191 Relay_Log_File: db02-relay-bin.000002 Relay_Log_Pos: 361 Relay_Master_Log_File: mysql-bin.000007 Slave_IO_Running: Yes Slave_SQL_Running: Yes#停掉主库,db02是主库[root@db02 ~]# /etc/init.d/mysqld stop
查看MHA切换日志,了解整个切换过程,在10.10.16.229上查看日志:
[root@db03 ~]# tail -100f /var/log/mha/app1/manager
#在db03上查看从库slave信息
mysql> show slave status\G*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.16.224 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000006 Read_Master_Log_Pos: 191 Relay_Log_File: db03-relay-bin.000002 Relay_Log_Pos: 361 Relay_Master_Log_File: mysql-bin.000006 Slave_IO_Running: Yes Slave_SQL_Running: Yes
#在db02上查看vip信息
[root@db02 ~]# ip a |grep eth0
#在db01上查看vip信息
[root@db01 ~]# ip a |grep eth02: eth0:mtu 1500 qdisc pfifo_fast state UP qlen 1000 inet 10.10.16.224/24 brd 10.10.16.255 scope global eth0 inet 10.10.16.232/24 brd 10.10.16.255 scope global secondary eth0:0 已经成功漂移
看到最后的Master failover to 10.10.16.224(10.10.16.224:3360) completed successfully.说明备选master现在已经上位了。
从上面的输出可以看出整个MHA的切换过程,共包括以下的步骤:
1.配置文件检查阶段,这个阶段会检查整个集群配置文件配置
2.宕机的master处理,这个阶段包括虚拟ip摘除操作。
3.复制dead maste和最新slave相差的relay log,并保存到MHA Manger具体的目录下
4.识别含有最新更新的slave
5.应用从master保存的二进制日志事件(binlog events)
6.提升一个slave为新的master进行复制
7.使其他的slave连接新的master进行复制
2.5 配置binlog-server
在MySQL 5.6以后,可以利用mysqlbinlog这个命令去把远程机器的日志备份到本地目录,从而达到增量或是日志安全方面的备份。做好mysql日志的备份,是数据安全的一个重要保证。
具体实施步骤如下:
2.51 修改mha配置文件
db03上配置:
[root@db03 ~]# vim /etc/mha/app1.cnf[binlog1]no_master=1 #意思是不会成为主库hostname=10.10.16.229master_binlog_dir=/data/mysql/binlog/ 主库的目录路径要跟从库的不一样
这个功能是基于GTID实现的,MySQL版本必须是5.6以上的
2.52 备份binlog
db03上操作:
#创建备份binlog目录[root@db03 ~]# mkdir -p /data/mysql/binlog/#进入该目录[root@db03 ~]# cd /data/mysql/binlog/#备份binlog[root@db03 binlog]# mysqlbinlog -R --host=10.10.16.224 --user=mha --password=mha --raw --stop-never mysql-bin.000001 &#启动mha[root@db03 binlog]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &
2.53 测试binlog备份
db03上查看:
#查看binlog目录中的binlog[root@db03 binlog]# lltotal 44-rw-r--r-- 1 root root 285 Mar 8 03:11 mysql-bin.000001 #最开始只有1个
主库db01刷新binlog:
[root@db01 ~]# mysql -uroot –p'123456'#刷新binlogmysql> flush logs;
db03上再次查看binlog目录:
[root@db03 binlog]# lltotal 48-rw-r--r-- 1 root root 285 Mar 8 03:11 mysql-bin.000001-rw-r--r-- 1 root root 143 Mar 8 04:00 mysql-bin.000002
3 MHA完整性验证
可以新添加两个slave节点db05,db06,实验效果会更好。
实验目的:根据MHA的自动切换故障转移特性,实现无论哪台slave都能在主库宕机的情况下,MHA通过判断拥有最新的binlog位置点信息的slave立马会做新的master。
实验结果:MHA对于多台主从集群架构,一样能实现failover,自动切换。
3.1 测试mha是否智能
db01-10.10.16.224依然作为主库,所有从库确保执行change master to语句指向主库:
CHANGE MASTER TO MASTER_HOST='10.10.16.224', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='rep', MASTER_PASSWORD='123456';
条件:把提升为主的标签去掉,如果16.224宕了,mha不会把标签删掉。
[root@db03 ~]# cat /etc/mha/app1.cnf[server1]#candidate_master=1#check_repl_delay=0hostname=10.10.16.224port=3306
db03(16.229)上启动mha:
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &
db01(16.224)上创建一张表:
mysql> use APP;Database changedmysql> create table yiyi( Sno int(10) NOT NULL COMMENT '身份证号', Sname varchar(16) NOT NULL COMMENT '姓名', Ssex char(2) NOT NULL COMMENT '性别', Sage tinyint(2) NOT NULL default '0' COMMENT '年龄', Sdept varchar(16) default NULL COMMENT '部门', PRIMARY KEY (Sno) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;Query OK, 0 rows affected (0.33 sec)
shell不断往表里写数据db04上:
#!/bin/bashMysqlLogin="mysql -uroot -p123456"i=1while truedo ${MysqlLogin} -e "insert into APP.yiyi values ("$i",'wyy"$i"','m','21','computer"$i"');" ((i++)) sleep 2;done
登录mysql(从库)查看数据:
select * from APP.yiyi;
模拟:先停掉db02(16.225)从库,再停掉db01(16.224)主库,验证db03(16.229)成为主库
#登录db02 slave 停库[root@db02 ~]# /etc/init.d/mysqld stop #登录db01 master 停库[root@db01 ~]# /etc/init.d/mysqld stop
登录db03 ,发现229的binlog是最新的,此时229已顺利成为主库了。
结论:MHA通过找到最新位置点binlog,把数据重新指向229,至此数据自动补全。在多个Slave环境中,如果个别Slave没有接受到最新的relay log events,MHA则会自动从最新的那个Slave上查找差异的relay log events,并将这些差异事件应用到有延迟的Slave上,最终保持所有的Slave数据一致。
MHA可以自动修复多个Slaves之间的差异日志,所以不用担心数据一致性问题。当Master故障时,MHA会从多个Slave中随机选择一个充当新的Master;也可在配置文件中指定某一个Slave优先成为Master。
3.2 模拟从库写冲突
先从从库上创建一个数据库APP,然后再去主库创建同名的APP库来模拟数据写冲突。
#登录从库查看从库状态mysql> show slave status\Glave_IO_Running:YesSlave_SQL_Running:NOSeconds_Behind_Master:NULLLast_Error: Error 'Cant't create database 'xiaoliu'; database exists' on query,.....
对于该冲突,解决办法:
#先停止该从库stop slave; #<====临时停止同步开关set globla sql_slave_skip_counter =1; #将同步指针向下移动一个,如果多次不同步,可以重复操作。 通过分析法获取gtid值 mysql> show slave status \G; #查看一下gtid信息并记录下来:Retrieved_Gtid_Set: 8f9e146f-0a18-11e7-810a-0050568833c8:1-4 --提示跳过此事务 Executed_Gtid_Set: 8f9e146f-0a18-11e7-810a-0050568833c8:1-3,f7c86e19-24fe-11e7-a66c-005056884f03:1-9#重置master方法跳过错误mysql> STOP SLAVE;mysql> RESET MASTER;mysql> SET @@GLOBAL.GTID_PURGED ='8f9e146f-0a18-11e7-810a-0050568833c8:1-4'mysql> START SLAVE;
上面这些命令的用意是,忽略8f9e146f-0a18-11e7-810a-0050568833c8:1-4 这个GTID事务,下一次事务接着从 5 这个GTID开始,即可跳过上述错误,最终主从正常同步。
3.3 模拟网络中断
模拟:在主库写入数据的过程中,突然服务器断网了,不是master挂了
验证:测试VIP漂移是否正常,手动补全mha配置,重新启动mha,数据是否恢复
结论:经测试主库网络中断之后,VIP自动漂移到第二台slave,db02接替主库继续提供服务,数据没有丢失。
4 MySQL中间件Atlas
Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。目前该项目在360公司内部得到了广泛应用,很多MySQL业务已经接入了Atlas平台,每天承载的读写请求数达几十亿条。同时,有超过50家公司在生产环境中部署了Atlas,超过800人已加入了这个开发者交流群,并且这些数字还在不断增加。(简介内容摘自github官网 )。
主要功能: 1 读写分离
2 从库负载均衡
3 IP过滤
4 自动分表
5 DBA可平滑上下线DB
6 自动摘除宕机的DB
系统架构请参考:
安装Atlas真的是炒鸡简单,官方提供的Atlas有两种:
Atlas (普通) :
Atlas (分表) :
我们这里只需要下载普通的即可。安装位置:主库进行安装
#下载Atlas[root@db01 tools]# wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm#安装[root@db01 tools]# rpm -ivh Atlas-2.2.1.el6.x86_64.rpm Preparing... ########################################### [100%] 1:Atlas ########################################### [100%]
编辑配置文件
#进入Atlas工具目录[root@db01 ~]# cd /usr/local/mysql-proxy/bin/#生成密码[root@db01 bin]# ./encrypt 123456#修改Atlas配置文件[root@db01 ~]# vim /usr/local/mysql-proxy/conf/test.cnf#Atlas后端连接的MySQL主库的IP和端口,可设置多项,用逗号分隔proxy-backend-addresses = 10.10.16.224:3306#Atlas后端连接的MySQL从库的IP和端口proxy-read-only-backend-addresses = 10.10.16.225:3306,10.10.16.229:3306#用户名与其对应的加密过的MySQL密码pwds = root:1N/CNLSgqXuTZ6zxvGQr9A==#SQL日志的开关sql-log = ON#Atlas监听的工作接口IP和端口proxy-address = 0.0.0.0:3307#默认字符集,设置该项后客户端不再需要执行SET NAMES语句charset = utf8
启动Atlas
[root@db01 ~]# /usr/local/mysql-proxy/bin/mysql-proxyd test startOK: MySQL-Proxy of test is started
Atlas管理操作
#用atlas管理用户登录[root@db01 ~]# mysql -uuser -ppwd -h127.0.0.1 -P2345#查看可用命令帮助mysql> select * from help;#查看后端代理的库mysql> SELECT * FROM backends;+-------------+----------------+-------+------+| backend_ndx | address | state | type |+-------------+----------------+-------+------+| 1 | 10.10.16.224:3307 | up | rw || 2 | 10.10.16.225:3307 | up | ro || 3 | 10.10.16.229:3307 | up | ro |+-------------+----------------+-------+------+#平滑摘除mysqlmysql> REMOVE BACKEND 2;Empty set (0.00 sec)#检查是否摘除成功mysql> SELECT * FROM backends;+-------------+----------------+-------+------+| backend_ndx | address | state | type |+-------------+----------------+-------+------+| 1 | 10.10.16.225:3307 | up | rw || 2 | 10.10.16.229:3307 | up | ro |+-------------+----------------+-------+------+#保存到配置文件中mysql> SAVE CONFIG;Empty set (0.06 sec)
未完,待续...