最近在研究mysql的高可用架构,自己想总结下常用的高可用方案都有哪些、有哪些优缺点以及应用的场景?搞得是头昏脑涨,天昏地暗,看了诸多资料,每次都觉得公说公有理婆说婆有理。其实嘛,大家说的都有一定的道理,只不过适合自己的才是最正确的。今天就从比较常用的主从+MHA说起。

学习一种新的架构还是软件,最好还是先从了解它的原理开始,这样才能在应用时扬长避短。

一、【MHA原理】

相较于其它HA软件,MHA的目的在于维持MySQL Replication中Master库的高可用性,其最大特点是可以修复多个Slave之间的差异日志,最终使所有Slave保持数据一致,然后从中选择一个充当新的Master,并将其它Slave指向它。

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线程)

基本工作流程大致如下:

(1) Manager定期监控Master,监控时间间隔由参数ping_interval决定,缺省为3秒钟一次;可利用其自身的监控功能,也可调用第三方软件来监控;MHA自身提供了两种监控方式:SELECT(执行SELECT 1)和CONNECT(创建连接/断开连接),

主要由ping_type参数决定,默认是select方式。

(2) 当监测到Master故障时,调用SSH脚本对所有Node执行一次检查,包括如下几个方面:

――MySQL实例是否可以连接;

――Master服务器是否可以SSH连通;

    ――检查SQL Thread的状态;

    ――检查哪些Server死掉了,哪些Server是活动的,以及活动的Slave实例;

    ――检查Slave实例的配置及复制过滤规则;

    ――最后退出监控脚本并返回代表特殊意义代码。

(3) 开始Master故障切换,包括如下几个子阶段:

    ――Phase 1: Configuration Check Phase

在这个阶段,若某个Slave实例的SQL Thread停止了,则会自动启动它;并再次确认活动的Servers及Slaves。

    ――Phase 2: Dead Master Shutdown Phase

在这个阶段,首先调用master_ip_failover_script,若HA是基于VIP实现的,则关闭VIP,若是基于目录数据库实现的,则修改映射记录。然后调用shutdown_script脚本强制关闭主机,以避免服务重启时,发生脑裂。

    ――Phase 3: Master Recovery Phase

   又包括如下3个子阶段:

     Phase 3.1: Getting Latest Slaves Phase

    检查各个Slave,获取最近的和最旧的binary log file和position,并检查各个Slave成为Master的优先级,依赖于candidate_master、no_master、 [server_xxx]顺序、binary log差异量等因素。

     Phase 3.2: Saving Dead Master's Binlog Phase

    若dead master所在服务器依然可以通过SSH连通,则提取dead master的binary log,提取日志的起点就是上一步获取的最新的binary log file和position,直到最后一条事件日志,并在dead master本地的工作目录(由参数remote_workdir决定)中

创建文件保存这些提取到的日志,然后将该文件拷贝到Manager服务器的工作 目录下(由参数manager_workdir决定)。若dead master系统就无法连接,也就不存在差异的binary log了。MHA还要对各个Slave节点进行健康检查,主要是SSH连通性。

    Phase 3.3: Determining New Master Phase

    接下来调用apply_diff_relay_logs命令恢复Slave的差异日志,这个差异日志指的是各个Slave之间的relay log。恢复完成后,所有的Slave数据是一致的,此时就可以根据优先级选择New Master了。

    Phase 3.4: New Master Diff Log Generation Phase

    这里是生成dead master和new master之间的差异日志,即将Phase 3.2保存的binary log拷贝到New Master的工作目录中(remote_workdir)。

    Phase 3.5: Master Log Apply Phase

    将上一步拷贝的差异日志恢复到New Master上,若发生错误,也可手动恢复。然后获取New Master的binlog name和position,以便其它Slave从这个新的binlog name和position开始复制。最后会开启New Master的写权限,即将read_only参数设置为0。

    ――Phase 4: Slaves Recovery Phase

    Phase 4.1: Starting Parallel Slave Diff Log Generation Phase

    生成Slave与New Slave之间的差异日志,并将该日志拷贝到各Slave的工作目录下,这部分日志dead master和new master之间差异的那部分日志,因为各个Slave在Phase 3.3阶段已经同步了。

    Phase 4.2: Starting Parallel Slave Log Apply Phase

    在各个Slave上应用这部分差异日志,然后通过CHANGE MASTER TO命令将这些Slave指向新的New Master,最后开始复制(start slave)。

    ――Phase 5: New master cleanup phase

    清理New Master其实就是重置slave info,即取消原来的Slave信息。至此整个Master故障切换过程完成。

二、【实验部分】

1、【环境说明】:默认三台机器上都已安装mysql5.6,且主从复制已经配置完成。
角色 主机名 ip地址 功能

主库 node1 192.168.245.129 (w/r)
candidate_master node2 192.168.245.131 (r)
从库 node3 192.168.245.132 (r)
vip: 192.168.245.100

aaarticlea/png;base64,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" alt="" width="367" height="235" />

129为主库,对外提供读写服务,而131和132机器对外提供读服务,需要设置为只读状态,不建议将它写入配置文件,因为从库随时会切换为主库。如下:

set global read_only=

2、配置三台机器之间的信任机制(省)

目的:机器之间能够无需输入密码进行访问。

3、安装mha软件

  • rpm安装:每台机器都要安装node,manager节点建议安装到单独的一台机器上或者一个不用切换为主的从库上
#安装可能需要的依赖包
[root@node1 software]# yum install perl-DBD-MySQL
[root@node1 software]# yum install perl-Config-Tiny
[root@node1 software]# yum install perl-Parallel-ForkManager*.rpm
[root@node1 software]# yum install perl-Mail-Sender*.rpm
[root@node1 software]# yum install perl-Mail-Sendmail*.rpm
[root@node1 software]# yum install perl-Log-Dispatch*.rpm
#安装mha,这里用rpm包安装,默认在/usr/bin
[root@node1 software]# yum install mha4mysql-node-0.56-0.el6.noarch.rpm
[root@node1 software]# yum install mha4mysql-manager-0.56-0.el6.noarch.rpm
  • 二进制包安装
#node安装
wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53.tar.gz
tar xf mha4mysql-node-0.53.tar.gz
cd mha4mysql-node-0.53
perl Makefile.PL
make && make install #manager安装
wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.53.tar.gz
tar xf mha4mysql-manager-0.53.tar.gz
cd mha4mysql-manager-0.53
perl Makefile.PL
make && make install

4、手工配置主库服务器的vip并测试

这里通过脚本手动创建vip,如下:

[root@node1 scripts]# cat init_vip.sh
vip="192.168.245.100/32"
/sbin/ip addr add $vip dev eth0

【测试】

绑定完成后,可以用以下命令查看绑定情况:

[root@node2 etc]# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:d7:0f:4a brd ff:ff:ff:ff:ff:ff
inet 192.168.245.131/24 brd 192.168.245.255 scope global eth0
inet 192.168.245.100/32 scope global eth0
inet6 fe80::20c:29ff:fed7:f4a/64 scope link
valid_lft forever preferred_lft forever

到任意从库ssh 192.168.245.100 --看是否连上vip或者mysql -h 192.168.245.100 -udarren -pdarren    --是否连上vip数据库.       如果都能够连接上,表示vip设置成功了。

5、配置mha及启动

(1)创建mha监控用户(在主库执行,这样每个服务器都有这个用户了)

mysql> grant all privileges on *.* to 'root'@'%' identified  by '123456';
Query OK, 0 rows affected (0.00 sec) mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

(2)关闭purge_relay_logs:

  • 在修改配置文件前,注意一个知识点,须将从库上的relay log自动清除设置为OFF,因为MySQL数据库主从复制在缺省情况下从库的relay logs会在SQL线程执行完毕后被自动删除,但是对于MHA场景下,对于某些滞后从库的恢复依赖于其他从库的relay log,因此采取禁用自动删除功能以及定期清理的办法。对于清理过多过大的relay log需要注意引起的复制延迟资源开销等。MHA可通过purge_relay_logs脚本及配合cronjob来完成此项任务。

purge_relay_logs的主要功能:

a、为relay日志创建硬链接(最小化批量删除大文件导致的性能问题)

b、SET GLOBAL relay_log_purge=1; FLUSH LOGS; SET GLOBAL relay_log_purge=0;
            c、删除relay log(rm –f  /path/to/archive_dir/*)

purge_relay_logs的用法及相关参数
1 purge_relay_logs --
help
Usage:
purge_relay_logs --user=root --password=rootpass --host=127.0.0.1 2 参数描述
--user 用户名,缺省为root
--password 密码
--port 端口号
--host 主机名,缺省为127.0.0.1
--workdir 指定创建relay log的硬链接的位置,默认是/var/tmp,成功执行脚本后,硬链接的中继日志文件被删除,由于系统不同分区创建硬链接文件会失败,故需要执行硬链接具体位置,建议指定为relay log相同的分区
--disable_relay_log_purge 默认情况下,如果参数relay_log_purge=1,脚本不做任何处理,自动退出.设定该参数,脚本会将relay_log_purge设置为0,当清理relay log之后,最后将参数设置为OFF(0)
定制清理relay log cronjob
pureg_relay_logs脚本在不阻塞SQL线程的情况下自动清理relay log。对于不断产生的relay log直接将该脚本部署到crontab以实现按天或按小时定期清理。
$ crontab -l
# purge relay logs at 5am
0 5 * * * app /usr/bin/purge_relay_logs --user=root --password=PASSWORD --disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1
  • 在我们的两个从库上设置relaylog为OFF:
(product)root@127.0.0.1 [(none)]> set global relay_log_purge=0;
Query OK, 0 rows affected (0.00 sec)
  • 然后通过定时任务,每隔一天定时清除relaylog:
#清除脚本
#!/bin/bash
user=root
passwd=root
port=3306
log_dir='/data/masterha/log'
work_dir='/data'
purge='/usr/bin/purge_relay_logs' if [ ! -d $log_dir ]
then
mkdir $log_dir -p
fi $purge --user=$user --password=$passwd --disable_relay_log_purge --port=$port --workdir=$work_dir >> $log_dir/purge_relay_logs.log 2>&1 #定时任务
crontab -e
#每天早上5点10分执行
10 5 * * * sh /data/scripts/purge_relay_log.sh

(3)修改配置文件:

到manager节点的/etc下面新建masterha目录,并将mha需要的配置初始化文件拷贝到该目录下:

[root@node3 ~]# cd /etc
[root@node3 etc]# mkdir masterha
#创建以下mha日志目录,没有则报错
[root@node3 etc]#mkdir -p /var/log/masterha/app1
[root@node3 mastermha]# ll
total 32
-rw-r--r--. 1 root root 503 Nov 9 01:26 app1.conf
-rwxr-xr-x. 1 root root 55 Nov 9 01:26 drop_vip.sh
-rwxr-xr-x. 1 root root 55 Nov 9 01:26 init_vip.sh
-rw-r--r--. 1 root root 357 Nov 9 01:26 masterha_default.conf
-rwxr-xr-x. 1 root root 3888 Nov 9 01:26 master_ip_failover
-rwxr-xr-x. 1 root root 10298 Nov 9 01:26 master_ip_online_change

然后修改vip的值:在masterha目录下执行grep "vip" *,将会列出所有文件中vip变量,然后一一修改为192.168.245.100。

修改app1.conf文件:

[server default]
manager_log=/var/log/masterha/app1/app1.log
manager_workdir=/var/log/masterha/app1
master_ip_failover_script="/etc/masterha/master_ip_failover"
master_ip_online_change_script="/etc/masterha/master_ip_online_change"
password=root
ping_interval=1
remote_workdir=/var/log/masterha/app1
repl_password=repl4slave
repl_user=repl
report_script="/etc/masterha/send_mail"
shutdown_script=""
ssh_user=root
user=root [server1]
candidate_master=1
check_repl_delay=0
hostname=192.168.245.129
master_binlog_dir=/data/mysql/mysql_3306/logs [server3]
hostname=192.168.245.132
port=3306

(4)检查mha环境并启动

#检查MHA Manger到所有MHA Node的SSH连接状态:
[root@node3 masterha]# /usr/bin/masterha_check_ssh --conf=/etc/masterha/app1.conf
Mon Nov 16 01:24:21 2015 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Nov 16 01:24:21 2015 - [info] Reading application default configuration from /etc/masterha/app1.conf..
Mon Nov 16 01:24:21 2015 - [info] Reading server configuration from /etc/masterha/app1.conf..
Mon Nov 16 01:24:21 2015 - [info] Starting SSH connection tests..
Mon Nov 16 01:24:24 2015 - [debug]
Mon Nov 16 01:24:21 2015 - [debug] Connecting via SSH from root@192.168.245.129(192.168.245.129:22) to root@192.168.245.131(192.168.245.131:22)..
Mon Nov 16 01:24:23 2015 - [debug] ok.
Mon Nov 16 01:24:23 2015 - [debug] Connecting via SSH from root@192.168.245.129(192.168.245.129:22) to root@192.168.245.132(192.168.245.132:22)..
Mon Nov 16 01:24:24 2015 - [debug] ok.
Mon Nov 16 01:24:25 2015 - [debug]
Mon Nov 16 01:24:22 2015 - [debug] Connecting via SSH from root@192.168.245.131(192.168.245.131:22) to root@192.168.245.129(192.168.245.129:22)..
Mon Nov 16 01:24:23 2015 - [debug] ok.
Mon Nov 16 01:24:23 2015 - [debug] Connecting via SSH from root@192.168.245.131(192.168.245.131:22) to root@192.168.245.132(192.168.245.132:22)..
Mon Nov 16 01:24:25 2015 - [debug] ok.
Mon Nov 16 01:24:25 2015 - [debug]
Mon Nov 16 01:24:22 2015 - [debug] Connecting via SSH from root@192.168.245.132(192.168.245.132:22) to root@192.168.245.129(192.168.245.129:22)..
Mon Nov 16 01:24:24 2015 - [debug] ok.
Mon Nov 16 01:24:24 2015 - [debug] Connecting via SSH from root@192.168.245.132(192.168.245.132:22) to root@192.168.245.131(192.168.245.131:22)..
Mon Nov 16 01:24:25 2015 - [debug] ok.
Mon Nov 16 01:24:25 2015 - [info] All SSH connection tests passed successfully.

如果遇到这个报错:

Can't exec "mysqlbinlog": No such file or directory at /usr/share/perl5/vendor_perl/MHA/BinlogManager.pm line 106.
mysqlbinlog version command failed with rc 1:0, please verify PATH, LD_LIBRARY_PATH, and client options
at /usr/bin/apply_diff_relay_logs line 493
Mon Nov 16 01:32:36 2015 - [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln205] Slaves settings check failed!
Mon Nov 16 01:32:36 2015 - [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln413] Slave configuration failed.
Mon Nov 16 01:32:36 2015 - [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln424] Error happened on checking configurations. at /usr/bin/masterha_check_repl line 48
Mon Nov 16 01:32:36 2015 - [error][/usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm, ln523] Error happened on monitoring servers.
Mon Nov 16 01:32:36 2015 - [info] Got exit code 1 (Not master dead). MySQL Replication Health is NOT OK!

解决方法如下,添加软连接(所有节点)

ln -s /usr/local/mysql/bin/mysqlbinlog /usr/local/bin/mysqlbinlog
ln -s /usr/local/mysql/bin/mysql /usr/local/bin/mysql

到此为止,都没问题了,开始启动manager节点进行监控,一般启动我们都使用nohup方式,但是当出现故障成功切换后,manager监控也会关闭,所以建议使用daemontools方式在后台运行。

  • nohup方式启动
nohup /usr/bin/masterha_manager --conf=/etc/masterha/app1.conf --remove_dead_master_conf --ignore_last_failover &
#关闭mha监控
/usr/bin/masterha_stop --conf=/etc/masterha/app1.conf
  • daemontools方式启动:
#下载daemontools工具
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
#安装
cd /home/software/daemontools/admin/daemontools-0.76
vim src/conf-cc #在第一行最后空一格后添加 -include /usr/include/errno.h 避免编译时报错
package/install #安装
#在/etc/init/创建svscan.conf文件并添加如下内容:
vim /etc/init/svscan.conf
start on runlevel [345]
respawn
exec /command/svscanboot
#在/etc/init目录下重新加载并启动
[root@node3 init]# initctl reload-configuration
[root@node3 init]# initctl start svscan
svscan start/running, process

使用daemon启动mha监控:

[root@node3 init]# mkdir -p /service/masterha_app
[root@node3 ~]# cd /service/masterha_app/
[root@node3 masterha_app]# pwd
/service/masterha_app
#在/service/masterha_app/创建run脚本并增加执行权限,内容如下
[root@node3 masterha_app]# cat /service/masterha_app/run
#!/bin/bash
exec /usr/bin/masterha_manager --conf=/etc/masterha/app1.conf --remove_dead_master_conf --ignore_last_failover
[root@node3 masterha_app]# chmod +x /service/masterha_app/run
#停止监控
svc -d /service/masterha_app
#开启监控
svc -u /service/masterha_app

另起一个session,查看启动日志:

[root@node3 app1]# tail -f app1.log
192.168.245.129(192.168.245.129:3306) (current master)
+--192.168.245.131(192.168.245.131:3306)
+--192.168.245.132(192.168.245.132:3306) Mon Nov 16 01:55:10 2015 - [warning] master_ip_failover_script is not defined.
Mon Nov 16 01:55:10 2015 - [warning] shutdown_script is not defined.
Mon Nov 16 01:55:10 2015 - [info] Set master ping interval 1 seconds.
Mon Nov 16 01:55:10 2015 - [warning] secondary_check_script is not defined. It is highly recommended setting it to check master reachability from two or more routes.
Mon Nov 16 01:55:10 2015 - [info] Starting ping health check on 192.168.245.129(192.168.245.129:3306)..
Mon Nov 16 01:55:10 2015 - [info] Ping(SELECT) succeeded, waiting until MySQL doesn't respond..

当看到最后一句“Ping(SELECT) succeeded, waiting until MySQL doesn't respond..”表示mha已经启动起来了。当然,你或许在一台机子上希望监控多套master-salve复制,这非常容易,只要为第二套集群创建一个新的配置文件并启动manager

1
# masterha_manager --conf=/etc/conf/masterha/app1.cnf  <br># masterha_manager --conf=/etc/conf/masterha/app2.cnf<br>如果你在app1和app2上有一些共有的参数,可在全局配置文件中配置。

启动参数介绍:

--remove_dead_master_conf  该参数表示当发生主从切换后,老的主库的ip将会从配置文件中移除。如果故障机器修复好了,需要手工添加ip信息到配置文件中

--manger_log                            日志存放位置

--ignore_last_failover                 在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover,之所以这样限制是为了避免ping-pong效应。该参数代表忽略上次MHA触发切换产生的文件, 默认情况下,MHA发生切换后会在日志目录,也就是上面我设置的/data产生app1.failover.complete文件,下次再次切换的时候如 果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后收到删除该文件,为了方便,这里设置为--ignore_last_failover。

查看MHA Manager监控是否正常:

[root@node3 app1]#  /usr/bin/masterha_check_status --conf=/etc/masterha/app1.conf
app1 (pid:6795) is running(0:PING_OK), master:192.168.245.129

6、模拟测试

(1)自动Failover测试

  • 首先用sysbench工具模拟主库业务的写入。
#下载sysbench
http://dev.mysql.com/downloads/benchmarks.html
#安装sysbench
yum install libtool -y #依赖包
tar zxvf sysbench-0.4.12.7.tar.gz
cd sysbench-0.4.12.7
./configure && make && make install

在主库执行,创建sysbench测试表:

(product)root@127.0.0.1 [(none)]> create database sbtest;
Query OK, 1 row affected (0.00 sec) [root@node1 sysbench-0.4.12.7]# /usr/local/bin/sysbench --test=oltp --oltp-table-size=100000 --oltp-read-only=off --init-rng=on --num-threads=4 --max-requests=0 --oltp-dist-type=uniform --max-time=1800 --mysql-user=root --mysql-socket=/tmp/mysql_3306.sock --mysql-password=root --mysql-host=192.168.245.129 --db-driver=mysql --mysql-table-engine=innodb --oltp-test-mode=complex prepare
sysbench 0.4.12.6: multi-threaded system evaluation benchmark Creating table 'sbtest'...
Creating 100000 records in table 'sbtest'...
  • 停止接管主库那个从库的io_thread线程:
(product)root@127.0.0.1 [(none)]> stop slave io_thread;
Query OK, 0 rows affected (0.01 sec)
  • 向主库插入数据:
[root@node1 sysbench-0.4.12.7]# /usr/local/bin/sysbench --test=oltp --oltp-table-size=100000 --oltp-read-only=off --init-rng=on --num-threads=4 --max-requests=0 --oltp-dist-type=uniform --max-time=180 --mysql-user=root --mysql-socket=/tmp/mysql_3306.sock --mysql-password=root --mysql-host=192.168.245.129 --db-driver=mysql --mysql-table-engine=innodb --oltp-test-mode=complex run
sysbench 0.4.12.6: multi-threaded system evaluation benchmark Running the test with following options:
Number of threads: 4
Initializing random number generator from timer. Random number generator seed is 0 and will be ignored Doing OLTP test.
Running mixed OLTP test
Using Uniform distribution
Using "BEGIN" for starting transactions
Using auto_inc on the id column
Using 1 test tables
Threads started!
Time limit exceeded, exiting...
(last message repeated 3 times)
Done. OLTP test statistics:
queries performed:
read: 489090
write: 174675
other: 69870
total: 733635
transactions: 34935 (194.05 per sec.)
deadlocks: 0 (0.00 per sec.)
read/write requests: 663765 (3686.93 per sec.)
other operations: 69870 (388.10 per sec.) Test execution summary:
total time: 180.0317s
total number of events: 34935
total time taken by event execution: 719.7722
per-request statistics:
min: 3.47ms
avg: 20.60ms
max: 444.43ms
approx. 95 percentile: 28.17ms Threads fairness:
events (avg/stddev): 8733.7500/260.92
execution time (avg/stddev): 179.9430/0.01

然后启动从库上io_thread:

(product)root@127.0.0.1 [(none)]> start slave io_thread;
Query OK, 0 rows affected, 1 warning (0.00 sec)
  • kill主库的mysqld:
pkill -9 mysqld

最后,查看mha日志,这时已经接管过来了!

)

(2)修复故障master

通常情况下自动切换以后,待原master主机修复后,如果数据完整的情况下,可能想把原来master重新作为新主库的slave,这时我们可以借助当时自动切换时刻的MHA日志来完成对原master的修复。下面是提取相关日志的命令:

[root@node3 masterha]#  grep -i "All other slaves should start" /var/log/masterha/app1/app1.log
Mon Nov 16 03:02:20 2015 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='192.168.245.131', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000013', MASTER_LOG_POS=35416929, MASTER_USER='repl', MASTER_PASSWORD='xxx';

将change master to拿到原master上执行,那么就作为新master的slave了。

(3)在线切换测试

在许多情况下, 需要将现有的主服务器迁移到另外一台服务器上。 比如主服务器硬件故障,RAID 控制卡需要重建,将主服务器移到性能更好的服务器上等等。 MHA 提供快速切换和优雅的阻塞写入,这个切换过程只需要 0.5-2s 的时间,这段时间内数据是无法写入的。在很多情况下,0.5-2s 的阻塞写入是可以接受的。因此切换主服务器不需要计划分配维护时间窗口。

MHA在线切换的大概过程:
1.检测复制设置和确定当前主服务器
2.确定新的主服务器
3.阻塞写入到当前主服务器
4.等待所有从服务器赶上复制
5.授予写入到新的主服务器
6.重新设置从服务器

注意,在线切换的时候应用架构需要考虑以下两个问题:

1.自动识别master和slave的问题(master的机器可能会切换),如果采用了vip的方式,基本可以解决这个问题。

2.负载均衡的问题(可以定义大概的读写比例,每台机器可承担的负载比例,当有机器离开集群时,需要考虑这个问题)

为了保证数据完全一致性,在最快的时间内完成切换,MHA的在线切换必须满足以下条件才会切换成功,否则会切换失败。

1.所有slave的IO线程都在运行

2.所有slave的SQL线程都在运行

3.所有的show slave
status的输出中Seconds_Behind_Master参数小于或者等于running_updates_limit秒,如果在切换过程中不指
定running_updates_limit,那么默认情况下running_updates_limit为1秒。

4.在master端,通过show processlist输出,没有一个更新花费的时间大于running_updates_limit秒。

在线切换步骤如下:

首先,停掉MHA监控:

[root@node3 app1]# svc -d /service/masterha_app
[root@node3 app1]# checkstatus
app1 is stopped(2:NOT_RUNNING).

其次,进行在线切换操作(模拟在线切换主库操作,原主库192.168.245.129变为slave,192.168.245.131提升为新的主库)

[root@node3 masterha]# /usr/bin/masterha_master_switch --conf=/etc/masterha/app1.conf --master_state=alive --new_master_host=192.168.245.131 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
Mon Nov 16 21:47:24 2015 - [info] MHA::MasterRotate version 0.56.
Mon Nov 16 21:47:24 2015 - [info] Starting online master switch..
Mon Nov 16 21:47:24 2015 - [info]
Mon Nov 16 21:47:24 2015 - [info] * Phase 1: Configuration Check Phase..
Mon Nov 16 21:47:24 2015 - [info]
Mon Nov 16 21:47:24 2015 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Nov 16 21:47:24 2015 - [info] Reading application default configuration from /etc/masterha/app1.conf..
Mon Nov 16 21:47:24 2015 - [info] Reading server configuration from /etc/masterha/app1.conf..
Mon Nov 16 21:47:24 2015 - [info] GTID failover mode = 0
Mon Nov 16 21:47:24 2015 - [info] Current Alive Master: 192.168.245.129(192.168.245.129:3306)
Mon Nov 16 21:47:24 2015 - [info] Alive Slaves:
Mon Nov 16 21:47:24 2015 - [info] 192.168.245.132(192.168.245.132:3306) Version=5.6.21-log (oldest major version between slaves) log-bin:enabled
Mon Nov 16 21:47:24 2015 - [info] Replicating from 192.168.245.129(192.168.245.129:3306) It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 192.168.245.129(192.168.245.129:3306)? (YES/no): yes
Mon Nov 16 21:47:35 2015 - [info] Executing FLUSH NO_WRITE_TO_BINLOG TABLES. This may take long time..
Mon Nov 16 21:47:35 2015 - [info] ok.
Mon Nov 16 21:47:35 2015 - [info] Checking MHA is not monitoring or doing failover..
Mon Nov 16 21:47:35 2015 - [info] Checking replication health on 192.168.245.132..
Mon Nov 16 21:47:35 2015 - [info] ok.
Mon Nov 16 21:47:35 2015 - [error][/usr/share/perl5/vendor_perl/MHA/ServerManager.pm, ln1218] 192.168.245.131 is not alive!
Mon Nov 16 21:47:35 2015 - [error][/usr/share/perl5/vendor_perl/MHA/MasterRotate.pm, ln232] Failed to get new master!
Mon Nov 16 21:47:35 2015 - [error][/usr/share/perl5/vendor_perl/MHA/ManagerUtil.pm, ln177] Got ERROR: at /usr/bin/masterha_master_switch line 53

这里怎么会报错呢?意思是131这个机器not alive,可是我去检查下没有问题啊,主从也ok的,后来发现了问题所在,原因是:之前启动的manager脚本中加上了--remove_dead_master_conf参数,导致appl.conf中没有131机器的配置。

然后到app1.conf中加上131机器的配置信息,再次执行:

其中参数的意思:

--orig_master_is_new_slave 切换时加上此参数是将原 master 变为 slave 节点,如果不加此参数,原来的 master 将不启动

--running_updates_limit=10000,故障切换时,候选master 如果有延迟的话, mha 切换不能成功,加上此参数表示延迟在此时间范围内都可切换(单位为s),但是切换的时间长短是由recover 时relay 日志的大小决定

(4)切换时发送邮件:

需要创建一个send_mail脚本,然后将脚本路径写入app1.conf中即可。

至此,mysql mha部分就搞定了,下面将会结合mha这个架构加入代理层,从而实现读写分离功能,主要采用360公司的Atlas,敬请期待。。。

mysql高可用研究(一) 主从+MHA架构 (转)的更多相关文章

  1. mysql高可用研究(一) 主从+MHA架构

    最近在研究mysql的高可用架构,自己想总结下常用的高可用方案都有哪些.有哪些优缺点以及应用的场景?搞得是头昏脑涨,天昏地暗,看了诸多资料,每次都觉得公说公有理婆说婆有理.其实嘛,大家说的都有一定的道 ...

  2. mysql高可用研究(二) 主从+MHA+Atlas

    关于Atlas的详细介绍请访问:https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md 为什么要使用Atlas?应用程序直连数据库不好吗? ...

  3. 优酷土豆资深工程师:MySQL高可用之MaxScale与MHA

    本文根据DBAplus社群第67期线上分享整理而成 本次分享主要包括以下内容: 1.MySQL高可用方案 2.为什么选择MHA 3.读写分离方案的寻找以及为什么选择Maxscale 一.MySQL  ...

  4. (5.9)mysql高可用系列——正常主从切换测试

    [0]实验环境 操作系统:CentOS linux 7.5 数据库版本:5.7.24 数据库架构:主从复制,主库用于生产,从库用于数据容灾和主库备机,采用默认传统的异步复制. 主库IP:192.168 ...

  5. MySQL高可用架构之MHA

    简介: MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是 ...

  6. MySQL高可用架构-MHA环境部署记录

    一.MHA介绍 MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司) ...

  7. MySQL高可用架构之基于MHA的搭建

    一.MySQL MHA架构介绍: MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Fa ...

  8. 转一下大师兄的"MySQL高可用架构之MHA"

    简介: MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是 ...

  9. (转)MySQL高可用架构之MHA

    MySQL高可用架构之MHA  原文:http://www.cnblogs.com/gomysql/p/3675429.html 简介: MHA(Master High Availability)目前 ...

随机推荐

  1. Java中多线程服务中遇到的Redis并发问题?

    背景: 一个中小型H5游戏 核心错误信息: (1): java.lang.ClassCastException: [B cannot be cast to java.lang.Long at redi ...

  2. 重写 console.log()

    /*重写console.log*/ console.log = (function(mFun){ return function(str){ mFun.call(console,'hello! ' + ...

  3. element el-tree 添加图标

    1.指定渲染函数:render-content="renderContent" <el-tree ref="tree" :data="funct ...

  4. sublime的插件

    记录一下常用的插件: 1. htmlpretty 用于HTML.CSS.JS的格式化,以方便阅读代码.插件全名是HTML-CSS-JS Pretty.安装后使用方法是: 打开一个HTML/CSS/JS ...

  5. post 数据

    可参照:http://www.voidcn.com/blog/Vindra/article/p-4917667.html 一.get请求 curl "http://www.baidu.com ...

  6. ECMAScript 6 变量的解构赋值

    1.数组的结构赋值 1.1 基本用法 可以用“模式匹配”的写法给数组的元素赋值,只要等号两边的模式相同,左边的变量就会被赋予对应的值.注意:元素的值和位置是一一对应关系,如果对应的位置没有值,就会解构 ...

  7. ISP PIPLINE (二) LensShading Correct

    what is the LSC? lens shading 分为:Y-shading , color shading. 在讲LSC之前,我们先来理解一个重要的术语--CRA(Chief ray ang ...

  8. Leetcode中值得一做的题

    3.longest substring Given a string, find the length of the longest substring without repeating chara ...

  9. 2017 ACM Jordanian Collegiate Programming Contest

    A. Chrome Tabs 当$n=1$时答案为$0$,当$k=1$或$k=n$时答案为$1$,否则答案为$2$. #include<cstdio> int T,n,k; int mai ...

  10. NEERC-2017

    A. Archery Tournament 用线段树套set维护横坐标区间内的所有圆,查询时在$O(\log n)$个set中二分查找即可. 时间复杂度$O(n\log^2n)$. #include& ...