使用Keepalived实现mysql高可用

keepalived简介

简单地说,keepalived 就是通过管理 VIP 来实现机器的高可用的,在使用 keepalived 的情况下,只有一台服务器能够提供服务(通过 VIP 来实现),当 Master 主机宕机后,VIP 会自动飘移到另一台服务器

keepalived 采用 Master/Slave 模式, 在 Master 上设置配置文件的 VIP,当 Master 宕机后,VIP 自动漂移到另一台 keepalived 服务器上

keepalived 可以用来做各种软件的高可用集群,它会一直检测服务器的状态,如果有一台服务器宕机,或工作出现故障,keepalived 将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后 keepalived 自动将服务器加入到服务器群中。

Keepalived 运行原理

https://images2017.cnblogs.com/blog/999804/201709/999804-20170921140203415-1596297268.png

Mysql 主主复制 ,主节点自动切换。利用 keepalived 软件监控主节点状态,当主节点崩溃,立刻热切换主节点到备份节点从而得到高可用性。

双机热备是指两台机器都在运行,但并不是两台机器都同时在提供服务。当提供服务的一台出现故障的时候,另外一台会马上自动接管并且提供服务,而且切换的时间非常短。

keepalived安装

Yum 安装

yum install -y keepalived

源码安装

# 安装依赖
yum install -y gcc popt-devel openssl openssl-devel libssl-dev libnl-devel popt-devel libnfnetlink-devel

# 下载安装包
wget http://www.keepalived.org/software/keepalived-2.1.5.tar.gz

# 解压并安装
tar -xvz -f  keepalived-2.1.5.tar.gz
cd keepalived-2.1.5
./configure --prefix=/usr/local/keepalived
make && make install

cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
mkdir /etc/keepalived/
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/

修改配置

Master配置

global_defs {
	notification_email {
	    xXXXX2@qq.com
	#报警邮件接收人的地址
	}
       
	notification_email_from XXX@qq.com
	smtp_server 127.0.0.1 
	smtp_connect_timeout 30

}

#定义检测脚本       
vrrp_script check_mysql_valid {   
    #检测mysql服务是否在运行。检测方式有多种,比如进程,脚本等等。当前项目使用脚本进行检测
    #脚本放置到服务器指定目录,并修改下面的路径
    script "/etc/keepalived/keepalived_mysql_check.sh"   
    interval 2                   
    #脚本执行间隔时间,每2s检测一次
}
       
vrrp_instance VI_1 {
    state MASTER    
    interface ens33      
    #指定虚拟ip的网卡接口
    virtual_router_id 51    
    #路由器标识,MASTER和BACKUP必须是一致的
    priority 101            
    #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP 
    #的优先级。这样MASTER故障恢复后,就可以将VIP资源再次抢回来 
    advert_int 1
    #指定发送VRRP通告的间隔。单位是秒         
    authentication {   
        auth_type PASS 
        auth_pass XXXX     
    }
    
    #指定VIP地址
    virtual_ipaddress {    
        192.168.175.110 dev eth0 scope global
    }
    #调用检测脚本
    track_script {               
	  check_mysql_valid             
    }
}

 Slave配置

global_defs {
	notification_email {
	    xXXXX2@qq.com
	#报警邮件接收人的地址
	}
       
	notification_email_from XXX@qq.com
	smtp_server 127.0.0.1 
	smtp_connect_timeout 30

}

#检测mysql服务是否在运行。有很多检测方式,比如进程、脚本等等,本项目使用脚本进行检测       
vrrp_script check_mysql_valid {   
    #指定脚本位置
    script "/etc/keepalived/keepalived_mysql_check.sh"   
    #脚本执行间隔,每2s检测一次
    interval 2                   
}
       
vrrp_instance VI_1 {
    state MASTER    
    interface eth0      
    #指定虚拟ip的网卡接口
    virtual_router_id 51    
    #路由器标识,MASTER和BACKUP必须是一致的
    priority 99            
    #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP 
    #的优先级。这样MASTER故障恢复后,就可以将VIP资源再次抢回来 
    advert_int 1
    #指定发送VRRP通告的间隔。单位是秒         
    authentication {   
        auth_type PASS 
        auth_pass XXXX     
}

 #变为 MASTER 时执行
 notify_master "/bin/bash /etc/keepalived/keepalived_mysql_start.sh"  

 #指定VIP
 virtual_ipaddress {    
   192.168.175.110 dev eth0 scope global
 }

 #执行检测脚本
 track_script {               
	check_mysql_valid             
 }
}

配置脚本

Mysql服务是否正常的检测脚本

创建脚本并赋予执行权限:

/etc/keepalived/keepalived_mysql_check.sh
#!/bin/sh
# MySQL 检测脚本
MySqlPath=$(cd $(dirname $0); pwd)
cd $MySqlPath

ThisTime=`date '+%F %T'`

#指定脚本执行时,日志输出位置
log_file='/var/log/keepalived_mysql.log'

# MySQL 连接方式,根据实际情况调整
export MYSQL_PWD='root'
MYSQL_USER='root'
MYSQL_SOCKET="/tmp/mysql.sock"
mysql_connect="mysql -u${MYSQL_USER} -S${MYSQL_SOCKET} -p{MYSQL_PWD}"

# 日志格式化
function formatEcho() {
    message=$1
    message_level=$2
    if [ -e $message_level ];then
        message_level='info'
    fi
    echo "`date '+%F %T'` - [${message_level}] $message" >> $log_file
}

# 检查mysql服务是否正常 正常返回 0,否则返回1
function check {
    ret=`$mysql_connect -N -e 'select 1 as value'`
    if [ $? -ne 0 ] || [ $ret -ne '1' ];then
        return 1
    else
        return 0
    fi
}

#全局设置数据库状态  1为只读
function read_only {
    param=$1
    $mysql_connect -e "set global read_only = ${param}"
    
    formatEcho "设置是否只读 read_only ${param}"
}

# 失效转移操作
function failOver {
    formatEcho "开始执行失效转移"
    
    #停止 keepalived
    killall keepalived

    #如果还能执行的话,设为 read_only
    read_only 1

    if [ $? -eq 0 ];then
    
        #如果还能执行,关闭所有的连接
        
        $mysql_connect -e "select concat('KILL ',id,';') from information_schema.processlist where user!='root' AND db is not null into outfile '/tmp/kill.txt.${ThisTime}';"
       
        if [ $? -eq 0 ];then
            $mysql_connect -e "source /tmp/kill.txt.${ThisTime};"
        fi
    fi

    formatEcho "失效转移执行完成,当前数据库关闭访问"
}

# 尝试 3 次检查
for ((i=1; i<=3; i ++))  
do  
    #调用检测脚本
    check
    
    if [ $? -eq 0 ];then
        formatEcho "MySQL is ok"
        # 正常退出脚本
        exit 0
    else
        formatEcho "Connection failed $i time(s)"
        sleep 1
    fi
done

formatEcho '无法连接当前数据库'

# 失效转移
failOver

切换为master时执行的脚本

 创建脚本并赋予执行权限:

/etc/keepalived/keepalived_mysql_start.sh

#!/bin/sh
# keepalived 变为 Master 时执行

MySqlPath=$(cd $(dirname $0); pwd)
cd $MyPath

ThisTime=`date '+%F %T'`

#脚本执行时输出的日志
log_file='/var/log/keepalived_mysql.log'

# MySQL 连接方式,根据实际情况调整
export MYSQL_PWD='root'
MYSQL_USER='root'
MYSQL_SOCKET="/tmp/mysql.sock"
mysql_connect="mysql -u${MYSQL_USER} -S${MYSQL_SOCKET} -p{MYSQL_PWD}"

# 日志格式化
function formatEcho() {
    message=$1
    message_level=$2
    if [ -e $message_level ];then
        message_level='info'
    fi
    echo "`date '+%F %T'` - [${message_level}] $message" >> $log_file
}

# 检查mysql是否正常运行, 正常返回 0、否则返回1
function check {
    ret=`$mysql_connect -N -e 'select 1 as value'`
    if [ $? -ne 0 ] || [ $ret -ne '1' ];then
        return 1
    else
        return 0
    fi
}

# 获取 slave status 的信息
function slave_info() {
    tmp_file=/tmp/slave_info.tmp
    $mysql_connect -e 'show slave status\G' > /tmp/slave_info.tmp
    
    slave_sql=`grep 'Slave_SQL_Running:' $tmp_file | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`
    seconds_behind_master=`grep 'Seconds_Behind_Master:' $tmp_file | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`

    master_log_file=`grep 'Master_Log_File:' $tmp_file | head -1 | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`
    master_log_pos=`grep 'Read_Master_Log_Pos:' $tmp_file | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`

    relay_master_log_file=`grep 'Relay_Master_Log_File:' $tmp_file | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`
    exec_master_log_pos=`grep 'Exec_Master_Log_Pos:' $tmp_file | sed 's/\s*//g' | tr "A-Z" "a-z"  | awk -F":" '{print $2}'`
}

# 设置是否只读 1为只读
function read_only {
    param=$1
    $mysql_connect -e "set global read_only = ${param}"
    formatEcho "设置是否只读 read_only ${param}"
}

# 处理数据同步,如果是数据一致性优先,等待同步完毕。如果是服务可用性优先,可以注销下面的代码
function sync_master() {
   
    slave_info
    
    if [ $slave_sql == "yes" ];then
        formatEcho "当前同步位置 Master ${master_log_file} ${master_log_pos}"
        formatEcho "等待同步到 Master ${master_log_file} ${master_log_pos}"
        $mysql_connect -e "select master_pos_wait('$master_log_file', $master_log_pos);" > /dev/null
        formatEcho "同步完毕"
    fi
}

formatEcho "当前数据库提升为主库"

#调用检测脚本
check

if [ $? -ne 0 ];then
    formatEcho "无法连接当前数据库"
    exit 1
fi

# 等待同步
sync_master


# 设为可写
read_only 0

重启keepalived

systemctl start keepalived

到此配置完成,接下来就可以进行验证了。

1、使用命令  ip addr  查看Master 主机是否多了虚拟IP

2、关闭Master的Keepalived ,查看VIP是否漂移到了 Slave机器

3、然后再测试mysql服务出现故障,VIP是否会自动切换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值