Mysql集群高可用之mha

1 MHA介绍

  官方介绍:https://code.google.com/archive/p/mysql-master-ha/

  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工具包,具体的说明如下:

   链接: https://pan.baidu.com/s/1_4t_5vEyN8ckxyqoB7fCeg 

  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/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.10.16.224 db01
10.10.16.225 db02
10.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关闭Firewall
chkconfig iptables off
sed -i 's#SELINUX=.*#SELINUX=disabled#g' /etc/selinux/config
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
grep SELINUX=disabled /etc/selinux/config 
setenforce 0
getenforce

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,另外一台充当从库,因为至少需要三台服务器。

  安装脚本参考安装mysql5.6.34源码安装  此方式安装过程较长

  手动安装步骤:建议二进制安装,安装包较大(300M),直接解压,步骤简洁,下面主要介绍手动安装:

2.21 手动安装

  安装包下载地址:http://ftp.ntu.edu.tw/MySQL/Downloads/MySQL-5.6/

          链接: https://pan.baidu.com/s/1YtSKlp2IPyRNPOSu9c87oQ   提取码: 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 start
Starting 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

   GTID即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。参考MySQL5.6 新特性之GTID,更具体的说明见官方说明

  没开启之前先看一下GTID的状态:

mysql> show global variables like '%gtid%';

  编辑mysql配置文件(主库从库都需要修改):

主从环境的搭建和5.5没有什么区别,唯一需要注意的是:开启GTID需要启用这三个参数:
[root@db01 ~]# vim /etc/my.cnf
#在[mysqld]标签下添加
[mysqld]
gtid_mode=ON
log_slave_updates
enforce_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;          #开启slave
mysql> 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

  https://directory.fsf.org/wiki   #Debian下载地址

  https://code.google.com/p/mysql-master-ha/  #mha下载地址,需要FQ

  在所有节点进行安装mha node:   链接: https://pan.baidu.com/s/1_4t_5vEyN8ckxyqoB7fCeg 

  根据系统环境上传对应mha安装包到指定目录:这里提供两种安装方式的包,便于理解

[root@db01 tools]# rz -be
mha4mysql-manager-0.56-0.el6.noarch.rpm
mha4mysql-manager-0.56.tar.gz
mha4mysql-node-0.56-0.el6.noarch.rpm
mha4mysql-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
View Code

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                启动MHA
masterha_stop                   停止MHA
masterha_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/
View Code

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=mha
password=mha
#ping包间隔频率
ping_interval=1
#主从复制用户
repl_user=rep
repl_password=123456
ssh_user=root

[server1]
hostname=10.10.16.224
port=3306

[server2]
#优先提升为主库
candidate_master=1
#忽略延迟
check_repl_delay=0
hostname=10.10.16.225
port=3306

[server3]
hostname=10.10.16.229
port=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
#设置监控用户root
user=root
#设置监控主库,发送ping包的时间间隔,尝试三次没有回应的时候自动进行failover
ping_interval=1
#设置远端mysql在发生切换时binlog的保存位置
remote_workdir=/tmp
#设置复制用户的密码
repl_password=123456
#设置复制环境中的复制用户名 
repl_user=rep
#设置发生切换后发送的报警的脚本
report_script=/usr/local/send_report
#一旦MHA到server02的监控之间出现问题,MHA Manager将会尝试从server03登录到server02
secondary_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.11
port=3306

[server2]
hostname=192.168.56.12
port=3306
#设置为候选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=192.168.56.13
#不让成为主
no_master=1
port=3306
View Code

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.cnf
app1 (pid:45489) is running(0:PING_OK), master:10.10.16.224

  说明:每次切换以后,,MHA会自动关闭,需要修改配置文件以后再开启

2.46 切换master测试

  停掉主库,模拟主库发生故障,进行自动failover操作。

[root@db01 ~]# /etc/init.d/mysqld stop
Shutting 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/manager
Sat 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.224
port=3306

  再次检查mha运行状态:

[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (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进程。
View Code

    通过MHA自带脚本方式,管理虚拟IP的漂移

这里是修改/usr/local/bin/master_ip_failover,也可以使用其他的语言完成,比如php语言。使用php脚本编写的failover这里就不介绍了。修改完成后内容如下,而且如果使用脚本管理vip的话,需要手动在master服务器上绑定一个vip 
  为了防止脑裂发生,推荐生产环境采用脚本的方式来管理虚拟ip,而不是使用keepalived来完成。到此为止,基本MHA集群已经配置完毕。接下来就是实际的测试环节了。通过一些测试来看一下MHA到底是如何进行工作的
View Code

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 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.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";
}
View Code

  添加执行权限:

[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=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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=1
check_repl_delay=0
hostname=10.10.16.224
port=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 eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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.229
master_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]# ll
total 44
-rw-r--r-- 1 root root 285 Mar  8 03:11 mysql-bin.000001  #最开始只有1个

  主库db01刷新binlog:

[root@db01 ~]# mysql -uroot –p'123456'
#刷新binlog
mysql> flush logs;

  db03上再次查看binlog目录:

[root@db03 binlog]# ll
total 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=0
hostname=10.10.16.224
port=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 changed
mysql> 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/bash
MysqlLogin="mysql -uroot -p123456"
i=1
while true
do
 ${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\G
lave_IO_Running:Yes
Slave_SQL_Running:NO
Seconds_Behind_Master:NULL
Last_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官网 https://github.com/Qihoo360/Atlas/wiki/Atlas%E7%9A%84%E6%9E%B6%E6%9E%84)。

  主要功能: 1 读写分离

        2 从库负载均衡

           3 IP过滤

         4 自动分表

         5 DBA可平滑上下线DB

         6 自动摘除宕机的DB

  系统架构请参考:https://blog.csdn.net/liaomin416100569/article/details/79195796

   安装Atlas真的是炒鸡简单,官方提供的Atlas有两种:网盘里已分享

  Atlas (普通) : Atlas-2.2.1.el6.x86_64.rpm 

  Atlas (分表) : Atlas-sharding_1.0.1-el6.x86_64.rpm

  我们这里只需要下载普通的即可。安装位置:主库进行安装

#下载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 start
OK: 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   |
+-------------+----------------+-------+------+
#平滑摘除mysql
mysql> 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)

  未完,待续...

 

 

 

 

 

 

 

 

  

 

posted @ 2019-04-15 13:29  淺景尘  阅读(486)  评论(0编辑  收藏  举报
TOP