当前位置:Gxlcms > mysql > mysql双机故障切换方案

mysql双机故障切换方案

时间:2021-07-01 10:21:17 帮助过:36人阅读

情景描述:原来两台数据库server做主从,因为前端有redis帮忙扛着大部分读压力,故而数据库的压力并不大,所以我们也没做读写分离,从库单纯作为备份用。这样明

情景描述:

原来两台数据库server做主从,因为前端有redis帮忙扛着大部分读压力,故而数据库的压力并不大,所以我们也没做读写分离,从库单纯作为备份用。

这样明显有两个缺点

1、主库是单点

2、从库资源浪费

所以便想出了如下的方案:让从库作为主库的热备,具备自动故障切换(failover)功能。

基本思路:

将DB1和DB2做成主动被动模式的双主结构:DB1主动;DB2被动(通过read_only参数实现除root用户之外的只读特性),通过keepalived VIP对外,将VIP设置成原DB1的IP,保持改造过程对代码透明。

正常时,VIP在DB1,通过keepalived调用脚本定期检查mysql服务可用性(通过一个低权限用户连接mysql服务器并执行一个简单查询,根据返回结果来判定mysql是否可用)

若无法执行查询:

进一步通过 service mysql status 检查mysql服务是否正常:

若服务状态不正常,则尝试重启mysql,继续判断可用性:

若重启过后执行查询OK,则本次检查OK

若重启后仍无法执行查询,则应该关闭DB1的mysql,然后关闭DB1的keepalived,使VIP漂移到DB2,DB的keepalived察觉到自己进入master状态,通过notify_master机制触发脚本,完成将DB2的mysql从被动状态(只读)切换到主动状态(可读可写)的操作,并且发送通知邮件

若服务状态正常,则等待30s再次尝试,若仍然无法执行查询,则重启DB1的mysql,再尝试执行sql。若仍然无法执行成功,,则执行关闭DB1的 mysql、keepalived,并将mysql服务切换至DB2的操作。

以上是大致思路,具体实现看过下面的脚本,就会一目了然了。

DB1上keepalived 配置

! Configuration File for keepalived global_defs { notification_email { lijiankai@dmzj.com } notification_email_from mysql_HA@dmzj.com smtp_server 118.194.37.21 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_script chk_mysql { script "/etc/keepalived/check_mysql.sh" interval 30 #这里我的检查间隔设置的比较长,因为我们数据库前面有redis做缓存,数据库一两分钟级别的终端对整体可用性影响不大。这也是我没有采用成熟的方案而自己搞了这一套方案的“定心丸” } vrrp_instance VI_1 { state MASTER interface em2 virtual_router_id 51 priority 100 advert_int 1 nopreempt #防止切换到从库后,主keepalived恢复后自动切换回主库 authentication { auth_type PASS auth_pass 1111 } track_script { chk_mysql } virtual_ipaddress { 192.168.1.5/24 } }

/etc/keepalived/check_mysql.sh脚本内容如下

#!/bin/sh ###判断如果上次检查的脚本还没执行完,则退出此次执行 if [ `ps -ef|grep -w "$0"|grep "/bin/sh*"|grep "?"|grep "?"|grep -v "grep"|wc -l` -gt 2 ];then #理论上这里应该是1,但是实验的结果却是2 exit 0 fi ###定义一个简单判断mysql是否可用的函数 function excute_query { mysql -uxxx -pxxx -e "show processlist;" 2>>/etc/keepalived/logs/check_mysql.err } ###定义无法连接mysql,且mysql服务状态异常时的处理函数 function service_error { echo -e "`date "+%F %H:%M:%S"` -----try restarting mysql-----" >> /etc/keepalived/logs/check_mysql.err /sbin/service mysql restart &>> /etc/keepalived/logs/check_mysql.err /sbin/service mysql status &>/dev/null if [ $? -ne 0 ];then ###若重启mysql服务后,仍不正常----关闭mysql----关闭keepalived echo -e "`date "+%F %H:%M:%S"` -----restart mysql failure-----" >> /etc/keepalived/logs/check_mysql.err echo -e "`date "+%F %H:%M:%S"` -----stop mysql-----" >> /etc/keepalived/logs/check_mysql.err /sbin/service mysql stop &>> /etc/keepalived/logs/check_mysql.err echo -e "`date "+%F %H:%M:%S"` -----now stop keepalived-----" >> /etc/keepalived/logs/check_mysql.err /sbin/service keepalived stop &>> /etc/keepalived/logs/check_mysql.err echo -e "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" >> /etc/keepalived/logs/check_mysql.err fi } ###定义若mysql服务正常,但是无法执行查询的处理函数 function connect_error { echo -e "`date "+%F %H:%M:%S"` -----excute query error, but mysql service is ok, retry after 30s-----" >> /etc/keepalived/logs/check_mysql.err sleep 30 excute_query; if [ $? -ne 0 ];then echo -e "`date "+%F %H:%M:%S"` -----still can not connect to mysql-----" >> /etc/keepalived/logs/check_mysql.err service_error; excute_query; if [ $? -ne 0 ];then echo -e "`date "+%F %H:%M:%S"` -----stop mysql-----" >> /etc/keepalived/logs/check_mysql.err /sbin/service mysql stop &>> /etc/keepalived/logs/check_mysql.err echo -e "`date "+%F %H:%M:%S"` -----stop keepalived-----" >> /etc/keepalived/logs/check_mysql.err /sbin/service keepalived stop &>> /etc/keepalived/logs/check_mysql.err echo -e "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" >> /etc/keepalived/logs/check_mysql.err fi fi } ###检查开始: mysql是否可连接 excute_query; if [ $? -ne 0 ];then ###检查服务状态 /sbin/service mysql status &>/dev/null if [ $? -ne 0 ];then ###若服务不正常 echo -e "`date "+%F %H:%M:%S"` -----mysql service error-----" >> /etc/keepalived/logs/check_mysql.err service_error; else ###若服务正常,但无法连接 connect_error; fi fi 注:脚本里关闭keepalived是在完全关闭mysql之后才执行,这样做的潜在缺点是:假如mysql服务关闭的时间过长,则直接导致整个切换过程过长,即服务终止时间过长 但是,之所以选择完全关闭DB1的 mysql再切换到DB2,是为了避免某些因素导致的数据不一致的发生

人气教程排行