MySQL高可用架构之MHA
一、运维人员需要掌握的MySQL技术:
1、基本SQL语句
2、基本的管理【库表数据的管理 权限的管理】
3、容灾 保证数据不丢失。
二、工作中MySQL的问题:
AB不同步怎么办?
1)如果当天及时发现的:先基于当前同步,再做差异还原
2)好几天才发现:重做B
三、数据完整性如何实现?
1)AB同步
AB互为主备+keepalived
php连接VIP,如果master宕机,slave承担访问流量;但如果master回来了,来承当访问流量并且造成数据不一致的情况(MHA解决这种问题,当A回来了进行差异还原使数据一致)。
2)MySQL注入
MySQL注入:登上你MySQL,删掉数据(在数据库层),然后所有的服务器就没数据了
备份策略:每周全备一次,每天增量备份
3)数据量的增长
IO成为瓶颈—分析业务(1、读多写少;2、读多写多;3、读少写多)
以读多写少的情况为例:
读写分离 A负责写 B负责读
因为读的要求较多,一台B效率低,所以架构演变成ABBB(一主多从),并把B做成集群,以提高读效率。
那么,当A宕机了,由哪个B来负责写入呢?
通过选举机制,从B中选出一个来当A,然后所有的B给新A做备份,并保证数据的完整性!******
四、MHA实现机制:
监控AB的状态
完整的选举机制(看谁的数据跟master最接近)
让一个B切换到新A
保证数据的完整性(通过差异还原)
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
该软件由两部分组成: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,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝TMHA已经支持一主一从。
假如MySQL MHA架构运行正常,突然在上午10:00一个复制组中的A的MySQL服务 down了!
因为AB复制是异步复制,所以可能有一些数据尚没有被B拉到其relay_log中,即AB数据不一致,MHA是怎样解决这种情况的呢?
1、mha_manager 使用scp命令将A当前binlog拷贝到mha_manager
2、待新A(选举:依据谁的relay_log新)产生后,mha_manager再拿着旧A的binlog和新的relay_log做比对,并进行差异还原以保证新A和旧A数据的一致性
3、mha_manager最后拿着老A的binlog去找复制组中其他B 做差异还原,保证数据的一致性
实验步骤:
1) ssh证书户信任(ssh的密钥验证)
2) ABB架构()
3) 安装mha_manager 、 mha_node
4) 测试
IP地址规划
Mysql_manager(18.240)—需要是64位的系统
MySQL_A(18.241)
MySQL_B1(18.242)
MySQL_B2(18.243)
1、ssh证书互信脚本---每台机器上都要操作
1.1使用ssh-kegen生成公私钥(每台服务器上)
1.2执行脚本
#!/bin/bash
for i in 0 1 2 3
do
ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.18.24$i
done
2、ABB搭建
2.1测试yum仓库的可用性脚本
#!/bin/bash
for i in 0 1 2 3
do
ssh 192.168.18.24$i "
if ( yum install telnet-server -y ) > /dev/null 2>&1;then
echo "192.168.18.24$i Yum is TURE"
else
echo "192.168.18.24$i Yum is FALSE "
fi
"
done
2.2安装脚本:
#!/bin/bash
for i in 0 1 2 3
do
ssh 192.168.18.24$i "
if ( yum install mysql mysql-server perl-* -y ) > /dev/null 2>&1;then
echo "192.168.18.24$i installation finish"
else
echo "192.168.18.24$i installation error "
fi
"
done
2.3所有的机器初始化MySQL,设置ABB架构:
MYSQL_A(241)上的操作:
vim /etc/my.cnf
server_id=1 //设置优先级最高
log_bin=binlog //开启binlog日志
log_biin=binlog.index
MYSQL_B1、MYSQL_B2上的操作同mysql_a只是注意server_id的不同!
2.4 设置用户
在msyql_a(241)中:因为前面已经开启二进制日志了,所以其他机器也能学到赋权语句!!故,其他机器就不用再赋权了!
> grant all on *.* to “root”@“%” identified by “123”; //给mha_manager用,因为其在failover时需要登陆上来,并且拷贝binlog到所有的slave上去。
> grant replication slave on *.* to “sky”@“%”identified by “123”; //复制专用用户
> flush privileges; //刷新权限
> show master status\G //看一下binlog日志到第几个文件了
在mysql_b1(242)中:
- slave stop;
- change master to master_host=”192.168.18.241”,master_user=”sky”,master_passoword=”123”,master_log_file=”binlog.000001”;
- slave start;
- show slave status\G //查看复制线程状态
在mysql_b2(243)做242上同样的操作!
3、安装配置启动mha_manager、mha_node
3.1安装
manager机器上:
cd /usr/src/mha_soft
[root@localhost mha_soft]# rpm -ivh mha4mysql-node-0.54-0.el6.noarch.rpm //安装node
cd dependent
yum -y install localinstall ./* //装上依赖
cd ..
rpm -ivh mha4mysql-manager-0.55-0.el6.noarch.rpm //安装manager
mha_manager的配置文件:
[root@localhost mha]# cp -r mha /etc/
mha目录下主要有以下两个文件
mha.cnf mha_start
[root@localhost mha]# vim /etc/mha/mha.cnf //mha配置文件
[server default]
#mysql admin account and password user=root
password= #mha workdir and worklog manager_workdir=/etc/mha
manager_log=/etc/mha/manager.log #mysql A/B account and pw repl_user=sky
repl_password= #check_mha_node time
ping_interval= #ssh account
ssh_user=root [server1]
hostname=192.168.18.241
ssh_port=
master_binlog_dir=/var/lib/mysql
candidate_master= [server2]
hostname=192.168.18.242
ssh_port=
master_binlog_dir=/var/lib/mysql
candidate_master= [server3]
hostname=192.168.18.243
ssh_port=
master_binlog_dir=/var/lib/mysql
candidate_master=
vim /etc/mha/mha_start //启动脚本
nohup masterha_manager --conf=/etc/mha/mha.cnf > /tmp/mha_manager.log </dev/null >& &
其他节点:
安装mha4mysql-node…rpm包(直接rpm安装即可)
3.2 检测ssh互信有没有问题
[root@localhost src]# masterha_check_ssh --conf=/etc/mha/mha.cnf
…
Tue Jun 13 02:21:31 2017 - [info] All SSH connection tests passed successfully.
3.3 测AB
[root@localhost src]# masterha_check_repl --conf=/etc/mha/mha.cnf
…
MySQL Replication Health is OK.
3.4 启动
[root@localhost src]# cat /etc/mha/mha_start //先看一下启动方式
nohup masterha_manager --conf=/etc/mha/mha.cnf > /tmp/mha_manager.log </dev/null 2>&1 &
运行:
[root@localhost src]# nohup masterha_manager --conf=/etc/mha/mha.cnf > /tmp/mha_manager.log </dev/null 2>&1 &
3.5 测试
现在两个slave的Master_Host同为241,把241干掉后,就会选举新的master了!
先在mha_manager上打开日志:
# tailf /etc/mha/manager.log
到241上关闭MySQL服务:
service mysqld stop
查看mha_manager日志输出:
… //此处省略
----- Failover Report -----
mha: MySQL Master failover 192.168.18.241 to 192.168.18.242 succeeded
Master 192.168.18.241 is down!
Check MHA Manager logs at localhost.localdomain:/etc/mha/manager.log for details.
Started automated(non-interactive) failover.
The latest slave 192.168.18.242(192.168.18.242:3306) has all relay logs for recovery.
Selected 192.168.18.242 as a new master.
192.168.18.242: OK: Applying all logs succeeded.
192.168.18.243: This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
192.168.18.243: OK: Applying all logs succeeded. Slave started, replicating from 192.168.18.242.
192.168.18.242: Resetting slave info succeeded.
Master failover to 192.168.18.242(192.168.18.242:3306) completed successfully.
看来242变成了master!~
可以去新主上创建个库或到243上查看一下master.info来验证!!
老master恢复后如果想要它再做master,要先将新master的数据同步,之后删除下面两个文件,再重新开启MHA功能,令新master宕掉即可(实验可行,实际操作不推荐)如下:
注意:mha_manager每执行一次failover后,该进程自动退出。如果还想测试failover需要重新开启---开启前要将下面两个文件删掉:
[root@MHA_243 mha]# cd /etc/mha/
[root@MHA_243 mha]# rm -fr mha.failover.complete saved_master_binlog_from_192.168.19.241_3306_20170817154913.binlog
下面演示old_master回来,如何保证old_master同步new_master的新产生的数据:
当old_master服务宕掉后,去mha_monitor上执行:
[root@mha_master mha]# grep -i change /etc/mha/manager.log (-i 是不区分大小写)
Tue Jun 13 02:30:23 2017 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='192.168.18.242', MASTER_PORT=3306, MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=106, MASTER_USER='sky', MASTER_PASSWORD='xxx';
然后在old_master上执行:
mysql> slave stop;
mysql> change master to master_host='192.168.18.242', master_port=3306, master_log_file='binlog.000001', master_log_pos=106, master_user='sky', master_password='123';(只需要修改密码即可)
mysql> slave start;
4、MHA failover(master故障)后VIP漂移
MHA架构中,master来承担写请求,但是如果发生了failover,那么就应该让new_master来承担写请求,有哪些方式可以实现呢?
1、 改变master的IP:在web上修改PHP页面的代码(所有写请求修改成new_master的IP)
2、 使用虚拟IP(VIP),将VIP漂移给new_master
显然,第二种方案要更加容易实现、高效。
实现起来,大家可能会首当其冲的想到keepalived,但是在这里不适用,因为我们不好判断哪一个salve会在failover后变成master(在keepalived中,VIP根据物理路由器的优先级来确定,万一漂到一台slave上那可如何是好!)。不过我们可以通过脚本的方式来实现将VIP绑定到new_master上。
脚本思路如下:
脚本(/etc/mha/check_mysql)运行在manager上,它来管理VIP
判断谁是主,确保它有VIP,并继续判断,如果slave有VIP,则收回。
脚本名称:master_vip_drift.sh
脚本需要根据前面设置的数据库密码对应修改,此处设置的为用户root,密码123
#!/bin/bash
VIP=192.168.18.245
NETMASK=255.255.255.0
MUSER=root
MPW=
MYSQL_IP="192.168.18.241 192.168.18.242 192.168.18.243"
NIC=eth0
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~main program~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#check_master_mysql
check_master() { #检测谁是master
for IP in $MYSQL_IP
do
if ssh $IP "lsof -i :3306" &>/dev/null;then
ssh $IP "mysql -uroot -p123 -e 'show slave status \G'|grep -w 'Slave_IO_Running'" &>/dev/null
if [ $? -eq ];then
MY_master=$IP
echo "$MY_master"
fi
fi
done
} check_master_alive() { #检测master的存活状态
for IP in $MYSQL_ip
do
if ssh $IP "ip add show eth0"|grep inet|grep "$VIP" &>/dev/null;then
ssh $IP "lsof -i:3306" &>/dev/null
if [ $? -ne ];then
ssh $IP "ifconfig $NIC:245 down "
fi
fi
done
} VIP () { #给master赋予VIP,不是master收回VIP
for IP in $MYSQL_IP
do
ssh $IP "ip add show eth0"|grep inet|grep "$VIP" &>/dev/null
if [ $? -eq ] && [ $MY_master != "$IP" ];then #如果有VIP但是不是master,收回VIP
ssh $IP "ifconfig $NIC:245 down"
elif [ $? -eq ] && [ $MY_master == "$IP" ];then #如果没有VIP却是master,赋予其VIP
ssh $IP "ifconfig $NIC:245 $VIP netmask $NETMASK up"
fi
done
} while true
do
check_master
check_master_alive
VIP
sleep
done
当前实验环境:
241 mysql_a
243 mysql_b2
242 mysql_b1 新 master
245 VIP
240 mha_monitor
1. 重新运行masterha_manager:
[root@mha_master mha]# nohup masterha_manager --conf=/etc/mha/mha.cnf > /tmp/mha_manager.log </dev/null 2>&1 &
2. 重新运行脚本master_vip_drift.sh
[root@mha_master mha]# ./master_vip_drift.sh &
3. 去242上检查VIP有没有绑定上
4. 模拟242的MySQL服务宕掉
5. 看看monitor上的日志,找出谁是新master
6、验证241上有没有VIP,242上的VIP有没有被收回
***monitor进行一次failover后自动关闭,还需手动运行
***需手动删除/etc/mha/下的失败切换文件failover file和binlog,否则failover不成功!
5、分析failover日志—了解MHA工作流程
5.1 tailf /etc/mha/manager.log
5.2 到master上关闭MySQL服务
5.3 查看日志并从头往下捋一遍
6、MySQL MHA读写分离后将slave做成集群
用的是HAProxy这款支持七层和四层分发的将slave做成集群,来承担读请求
实现读写分离:
通过修改PHP页面中绑定的IP地址,master承担写请求用VIP,slave集群承担读请求用haproxyIP。
实验环境:
241 mysql_a //master
242 mysql_b1
243 mysql_b2
245 VIP(master)
246 mha_monitor
247 HAProxy
248 client/httpd(lamp)
大致结构图如下:
结构图说明:
a.MHA对abb架构实行监控,发现a宕之后选出新a(实现VIP漂移,仅a有VIP)
b.haproxy对slave集群实现负载均衡,承担读请求
c.web集群请求后台数据,写请求传给a(VIP),读请求传给haproxy,haproxy再对读请求实现分发达到负载均衡
6.1 安装HAProxy
yum install gcc -y
tar xf haproxy-1.5.3.tar
make TARGET=linux26 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy
cp /usr/src/haproxy/haproxy-1.5.3/examples/haproxy.cfg /usr/local/haproxy/
cp /usr/src/haproxy/haproxy-1.5.3/examples/haproxy.init /etc/init.d/haproxy
chmod 755 /etc/init.d/haproxy
ln -s /usr/local/haproxy/sbin/* /usr/sbin/
mkdir /etc/haproxy
mkdir /usr/share/haproxy
ln -s /usr/local/haproxy/haproxy.cfg /etc/haproxy/
cd ..
6.2 设置配置文件
6.2.1 拷贝配置文件
[root@HAProxy_247 haproxy]# cp haproxy.cfg /usr/local/haproxy/
cp: overwrite `/usr/local/haproxy/haproxy.cfg'? y
6.2.2 编辑配置文件
[root@HAProxy_247 haproxy]# vim /usr/local/haproxy/haproxy.cfg
注意修改RS的IP:
# this config needs haproxy-1.1. or haproxy-1.2. global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn
chroot /usr/share/haproxy
uid
gid
daemon
#debug
#quiet defaults
log global
mode http
#option httplog
option dontlognull
retries
option redispatch
maxconn
contimeout
clitimeout
srvtimeout listen MySQL 0.0.0.0:
mode tcp
maxconn
balance roundrobin
option mysql-check user root
server mysql_1 192.168.18.242: inter 1s rise fall
server mysql_2 192.168.18.243: inter 1s rise fall listen admin_status
mode http
bind 0.0.0.0:
option httplog
log global
stats enable
stats refresh 10s
stats hide-version
stats realm Haproxy\ Statistics
stats uri /admin-status
stats auth admin:
stats admin if TRUE
6.3 启动HAProxy服务
[root@HAProxy_247 haproxy]# service haproxy start
6.4 访问HAProxy的网页
http://localhost:8899/admin-status
用户名密码查看配置文件舍子
6.5 客户端测试---密码123
6.6 回到HAProxy管理界面,可以看到那台slave响应的请求