使用Keepalived实现MySQL主从高可用

Posted wzy0623

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Keepalived实现MySQL主从高可用相关的知识,希望对你有一定的参考价值。

目录

一、问题提出

二、方案选择

三、Keepalived简介

1. VRRP

1.1 VRRP协议

1.2 工作机制

2. Keepalived设计与实现

1.1 多进程模式

1.2 控制面板

1.3 看门狗

1.4 IPVS封装

四、安装配置

1. 安装keepalived软件

2. 主从的配置文件修改

五、测试

参考:


一、问题提出

        由于公司服务器硬件已临界损耗期限,最近数据库主机频繁出现故障,不得不手工执行主从库切换操作。这种方式的问题是全程需要人工干预,宕机时间长,严重影响线上业务。于是开始调研mysql 高可用解决方案,要达到两个主要目标:主库出现问题时快速自动切换到从库;对应用透明。
 

二、方案选择

        MySQL的高可用方案有很多,比如Cluster、MMM、MHA、DRBD,以及Oracle官方推出的Fabric等,这些方案各有优劣,但都比较复杂,安装配置有一定难度,对线上库实施动静太大。就我们的具体情况而言,并不需要这么复杂的环境,实施简单、对现有架构影响最小、能迅速解决问题的方案才是最适合的。比如我们现在只是配置了MySQL Replication,加上如Keepalived这样的高可用软件,就能实现我们的需求。

        MySQL架构为Master/Slave,当Master故障时,虚IP漂移到Slave上提供服务,简单环境如图1所示。在这种架构中,故障自动切换以后,需要采取手动操作的方式与新的Master进行复制。当然也可以设置为Active-Passive模式下的双Master复制。

图1

 

三、Keepalived简介

        Keepalived的作用是检测服务器的状态,如果有一台服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其它服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

 

 

 

1. VRRP

        Keepalived是对VRRP的一个实现,因此在理解Keepalived的工作原理之前,有必要先了解VRRP的原理。

 

 

 

 

1.1 VRRP协议

        在现实的网络环境中,两台需要通信的主机(end-host)大多数情况下并没有直接地物理连接。对于这样的情况,它们之间的路由怎么选择?通常有两种方法解决如何选定到达目的主机的下一跳路由问题:

 

 

 

  • 使用动态路由协议,如RIP、OSPF等。
  • 配置静态路由。

        很明显,在主机上配置动态路由,因为管理、维护成本以及是否支持等诸多问题是不切实际的。那么配置静态路由就变得很流行。实际上,这种方式一直沿用至今。但是,路由器,或者说默认网关(default gateway)却经常成为单故障点。就算配置了多个静态路由,却因为必须重启网络才能生效而变得不实用。

        VRRP(虚拟路由冗余协议,Virtual Router Redundancy Protocol)的目的就是为了解决静态路由单点故障问题。它通过一种竞选(election)协议动态地将路由任务交给LAN中虚拟路由器中的某台VRRP路由器。这里有两个关键名词:VRRP路由器和虚拟路由器。

 

 

  • VRRP路由器:VRRP路由器就是一台路由器,只不过上面运行了VRRPD程序来实现VRRP协议而已,是物理的路由器。一台VRRP路由器可以位于多个虚拟路由器中。
  • 虚拟路由器:所谓虚拟,就是说并不是实际存在的,是一个逻辑而不是物理的路由器。虚拟路由器通常由多台VRRP路由器通过某种方式组成,就好像将这些物理路由器都丢到一个池里面去,整个池对外看起来就像是一台路由器,但其实内部有多台。虚拟路由器的标识称为VRID。

        在一个VRRP虚拟路由中,有多台物理的VRRP路由器,但是这多台物理路由并不同时工作,而是由一台称为master的负责路由工作,其它的都是backup。master并非一成不变,VRRP协议让每个VRRP路由器参与竞选,最终获胜的就是master。master有一些特权,比如拥有虚拟路由器的IP地址,我们的主机就是用这个IP地址作为静态路由的。拥有特权的master要负责转发发送给网关地址的包和响应ARP请求。

 

 

 

1.2 工作机制

        VRRP通过竞选协议来实现虚拟路由器的功能,所有的协议报文都是通过IP多播(multicast)包形式发送的,多播地址为224.0.0.18。虚拟路由器由VRID(范围0-255)和一组IP地址组成,对外表现为一个众所周知的MAC地址:00-00-5E-00-01-VRID。所以,在一个虚拟路由器中,不管谁是master,对外都是相同的MAC和IP(称之为VIP)。客户端主机并不需要因为master的改变而修改自己的路由配置,对它们来说,这种主从的切换是透明的。

        在一个虚拟路由器中,只有作为master的VRRP路由器会一直发送VRRP广告包(VRRP Advertisement Message),backup不会抢占master,除非它的优先级更高。当master不可用时,backup收不到广告包,多台backup中优先级最高的这台会抢占为master。这种抢占是非常快速的(<1秒),以保证服务的连续性。出于安全性考虑,VRRP包使用了加密协议进行加密。

 

 

 

 

2. Keepalived设计与实现

        Keepalived是一个高度模块化设计的软件,从源代码结构似乎也很容易看出这一点。Keepalived 1.2.13源代码中只有如下目录:check  core  etc  include  libipvs-2.4  libipvs-2.6  vrrp

 

 

 

  • check:Keepalived的healthchecker子进程的目录,包括了所有的健康检查方式以及对应配置的解析,LVS的配置解析也在这个里面。
  • core:Keepalived的核心程序,如全局配置的解析,进程启动等等。
  • etc:包含Keepalived的配置模板和启动脚本等文件。
  • include:头文件目录。
  • libipvs*:LVS使用的库文件。
  • vrrp:Keepalived的vrrpd子进程以及相关的代码。

        Keepalived架构如图2所示。

 

 

图2

 

1.1 多进程模式

        Keepalived采用了多进程的设计模式,每个进程负责不同的功能,我们在使用LVS的机器上通常可以看到三个Keepalived进程:
111 keepalived    < 父进程,负责内存管理、监控子进程等
112 \\_ keepalived < VRRP子进程
113 \\_ keepalived < healthchecker子进程
 

1.2 控制面板

        这里所谓的控制面板就是对配置文件的编译和解析。Keepalived的配置文件解析比较另类,并不是一次解析所有配置,而是只在用到某模块时才解析相应的配置。在源文件里面可以看到类似XXX_parser.c的文件,就是做这个用的。
 

1.3 看门狗

        WatchDog框架提供了对VRRP和healthchecker子进程的监控。
 

1.4 IPVS封装

        Keepalived里面所有对LVS的相关操作并不直接使用ipvsadm客户端程序,而是使用IPVS提供的函数进行操作,这些代码都在check/ipwrapper.c中。
 

四、安装配置

        环境:
        MySQL Master     172.16.1.126
        MySQL Slave      172.16.1.127
        VIP              172.16.1.100

        MySQL主从复制配置从略。
 

1. 安装keepalived软件

        用root执行下面的命令,主从操作一样。

wget -q http://www.keepalived.org/software/keepalived-1.2.13.tar.gz
tar -zxvf keepalived-1.2.13.tar.gz
cd keepalived-1.2.13
./configure && make && make install
cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
mkdir /etc/keepalived
cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/
cp /usr/local/sbin/keepalived /usr/sbin/
chkconfig --add keepalived
chkconfig --level 345 keepalived on

 

2. 主从的配置文件修改

        master的keepalived配置文件如下:

 

 

[root@hdp3~]#more /etc/keepalived/keepalived.conf
global_defs 
   router_id MySQL-HA
 

vrrp_script check_run 
script "/home/mysql/mysql_check.sh"
interval 60


vrrp_sync_group VG1 
group 
VI_1



vrrp_instance VI_1 
    state BACKUP
    interface ens32 
    virtual_router_id 51
    priority 100  
    advert_int 1
    nopreempt
    authentication 
        auth_type PASS
        auth_pass 1234
    
    track_script 
    check_run
    
    notify_master /home/mysql/master.sh
    notify_stop /home/mysql/stop.sh

    virtual_ipaddress 
        172.16.1.100
    

[root@hdp3~]#


        slave的keepalived配置文件如下:

 

[root@hdp4~]#more /etc/keepalived/keepalived.conf
global_defs 
   router_id MySQL-HA
 

vrrp_script check_run 
script "/home/mysql/mysql_check.sh"
interval 60


vrrp_sync_group VG1 
group 
VI_1



vrrp_instance VI_1 
    state BACKUP
    interface ens32  
    virtual_router_id 51
    priority 90  
    advert_int 1
    nopreempt
    authentication 
        auth_type PASS
        auth_pass 1234
    
    track_script 
    check_run
    
    notify_master /home/mysql/master.sh
    notify_stop /home/mysql/stop.sh

    virtual_ipaddress 
        172.16.1.100
    

[root@hdp4~]#

        master与slave的keepalived配置文件中只有priority设置不同,master为100,slave为90,其它全一样。配置文件是以块形式组织的,每个块都在包围的范围内,#和!开头的行都是注释。

        global_defs为全局定义,对整个Keepalived起作用,而不管是否使用LVS。

 

  • router_id:运行Keepalived的机器的一个标识。

        vrrp_script配置业务进程监控脚本。

 

 

  • script:设置脚本文件名。
  • interval:设置脚本执行的时间间隔,这里为每60秒执行一次。

        /home/mysql/mysql_check.sh文件用以检测MySQL服务是否正常,当发现连接不上mysql,自动把keepalived进程杀掉,让VIP进行漂移。文件内容如下。

 

 

[root@hdp3~]#more /home/mysql/mysql_check.sh
#!/bin/bash
. /home/mysql/.bashrc
count=1

while true
do

mysql -uroot -S /data/mysql.sock -e "show status;" > /dev/null 2>&1
i=$?
ps aux | grep mysqld | grep -v grep > /dev/null 2>&1
j=$?
if [ $i = 0 ] && [ $j = 0 ]
then
   exit 0
else
   if [ $i = 1 ] && [ $j = 0 ]
   then
       exit 0
   else
        if [ $count -gt 5 ]
        then
              break
        fi
   let count++
   continue
   fi
fi

done

/etc/init.d/keepalived stop
[root@hdp3~]#

        vrrp_sync_group配置VRRP同步组。不使用Sync Group的话,如果机器有两个网段,一个内网一个外网,每个网段开启一个VRRP实例。假设VRRP配置为检查内网,那么当外网出现问题时,VRRPD认为自己仍然健康,那么不会触发Master和Backup的切换,从而导致问题。Sync Group解决这个问题,可以把两个实例都放进一个Sync Group,这样的话,Sync Group里面任何一个实例出现问题都会发生切换。

 

  • group:设置同一组中的VRRP实例名,这里只有一个实例VI_1。

        vrrp_instance配置VRRP实例。VRRP实例表示在上面开启了VRRP协议。这个实例说明了VRRP的一些特性,比如主从、VRID等等。可以在每个网卡上开启一个实例。VRRP实例主要定义vrrp_sync_group里面的每个组的漂移IP等。

 

 

  • state:指定实例的初始状态。在两台路由都启动后,马上会发生竞争,高priority的会竞选为Master,所以这里的state并不表示这台就一直是Backup。
  • interface:实例绑定的网卡。
  • virtual_router_id:VRID标记,值为0..255,这里使用默认的51。
  • priority:高优先级竞选为Master,Master要高于Backup至少50。这里MySQL主从库两个优先级分别设置为100和90,因此当Keepalived启动后,MySQL主库会被选为Master。
  • advert_int:检查间隔,这里设置为默认的1秒。
  • nopreempt:设置为不抢占,注意这个配置只能设置在state为BACKUP的主机上。当MASTER出现问题后,BACKUP会竞选为新的MASTER,那么当之前的MASTER重新在线后,是继续成为MASTER还是变成BACKUP呢?默认不设置不抢占,那么之前的MASTER起来后会继续抢占成为MASTER。这样的频繁切换对于业务是不能容忍的,我们希望MASTER起来后成为BACKUP,所以要设置不抢占。又因为nopreempt配置只能用在state为BACKUP的主机上,因此MASTER的state也得设置为BACKUP,也就是说172.16.1.126和172.16.1.127都要将state设置为BACKUP。通过在两台BACKUP上面设置不同的priority,让它们一起来就抢占,高priority的172.16.1.126成为最初的MASTER。
  • authentication:设置认证类型和认证密码。 
  • auth_type:认证类型,支持PASS、AH两种,通常使用PASS类型。
  • auth_pass:明文认证密码。同一VRRP实例的MASTER与BACKUP使用相同的密码才能正常通信。
  • track_script:设置追踪脚本,这里为check_run,即调用vrrp_script中定义的脚本。 
  • notify_master:指定当切换到MASTER时执行的脚本。
  • notify_stop:VRRP停止以后执行的脚本。
  • virtual_ipaddress:指定漂移地址(VIP),也就是切换到MASTER时,这些IP或被添加,切换到BACKUP时,这些IP会被删除。因此每台服务器上可以不绑定任何虚拟地址,而都把它们放到virtual_ipaddress里面,可以都多个。Keepalived会自动使用ip addr进行绑定。

        /home/mysql/master.sh的作用是状态改为master以后执行的脚本。首先判断复制是否有延迟,如果有延迟,等1分钟后,不论是否有延迟,都并停止复制,并且记录binlog和pos点。文件内容如下。

 

 

[root@hdp3~]#more /home/mysql/master.sh
#!/bin/bash

. /home/mysql/.bashrc

Master_Log_File=$(mysql -uroot -S /data/mysql.sock -e "show slave status\\G" | grep -w Master_Log_File | awk -F": " 'print $2')
Relay_Master_Log_File=$(mysql -uroot -S /data/mysql.sock -e "show slave status\\G" | grep -w Relay_Master_Log_File | awk -F": " 'print $2')
Read_Master_Log_Pos=$(mysql -uroot -S /data/mysql.sock -e "show slave status\\G" | grep -w Read_Master_Log_Pos | awk -F": " 'print $2')
Exec_Master_Log_Pos=$(mysql -uroot -S /data/mysql.sock -e "show slave status\\G" | grep -w Exec_Master_Log_Pos | awk -F": " 'print $2')

i=1

while true
do

if [ $Master_Log_File = $Relay_Master_Log_File ] && [ $Read_Master_Log_Pos -eq $Exec_Master_Log_Pos ]
then
   echo "ok"
   break
else
   sleep 1

   if [ $i -gt 60 ]
   then
      break
   fi
   continue
   let i++
fi
done

mysql -uroot -S /data/mysql.sock -e "stop slave;"
mysql -uroot -S /data/mysql.sock -e "reset slave all;"
mysql -uroot -S /data/mysql.sock -e "reset master;"
mysql -uroot -S /data/mysql.sock -e "show master status;" > /tmp/master_status_$(date "+%y%m%d-%H%M").txt

[root@hdp3~]#

        /home/mysql/stop.sh表示Keepalived停止以后需要执行的脚本。检查是否还有复制写入操作,最后无论是否执行完毕都退出。文件内容如下。

 

[root@hdp3~]#more /home/mysql/stop.sh
#!/bin/bash

. /home/mysql/.bashrc

M_File1=$(mysql -uroot -S /data/mysql.sock -e "show master status\\G" | awk -F': ' '/File/print $2')
M_Position1=$(mysql -uroot -S /data/mysql.sock -e "show master status\\G" | awk -F': ' '/Position/print $2')
sleep 1
M_File2=$(mysql -uroot -S /data/mysql.sock -e "show master status\\G" | awk -F': ' '/File/print $2')
M_Position2=$(mysql -uroot -S /data/mysql.sock -e "show master status\\G" | awk -F': ' '/Position/print $2')

i=1

while true
do

if [ $M_File1 = $M_File1 ] && [ $M_Position1 -eq $M_Position2 ]
then
   echo "ok"
   break
else
   sleep 1

   if [ $i -gt 60 ]
   then
      break
   fi
   continue
   let i++
fi
done

[root@hdp3~]#

五、测试

1. 分别在master上和slave上启动keepalived进程。

/etc/init.d/keepalived start

        成功启动后可以看到如图3所示的3个Keepalived进程。

图3

2. 查看master上的VIP

[root@hdp3~]#ip addr

        结果如图4所示,可以看到VIP已经绑定成功。

图4


3. 客户端使用VIP连接数据库,创建测试库,插入数据。

 

C:\\WINDOWS\\system32>mysql -u wxy -p -h 172.16.1.100
Enter password: ******
Welcome to the MySQL monitor.  Commands end with ; or \\g.
Your MySQL connection id is 2958
Server version: 5.6.14-log Source distribution

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.

mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> use test;
Database changed
mysql> create table t1(a int);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql>

4. 模拟mysqld crash
        在master上执行以下命令:

 

[root@hdp3~]#pkill -9 mysqld

5. 再次使用VIP连接,数据没有异常,复制停止了,因为已经切换为主库。

 

C:\\WINDOWS\\system32>mysql -u wxy -p -h 172.16.1.100
Enter password: ******
Welcome to the MySQL monitor.  Commands end with ; or \\g.
Your MySQL connection id is 1568
Server version: 5.6.14-log Source distribution

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.

mysql> use test;
Database changed
mysql> select * from t1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> show slave status;
Empty set (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      120 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

mysql>

        binlog和pos点记录如下:

[root@hdp4~]#more /tmp/master_status_180704-1751.txt
File	Position	Binlog_Do_DB	Binlog_Ignore_DB	Executed_Gtid_Set
mysql-bin.000001	120			
[root@hdp4~]#

        此时VIP漂移到172.16.1.127,而172.16.1.126上绑定的VIP已经删除。在172.16.1.126查看IP地址如图5所示。

图5

        同时172.16.1.126的keepalived进程也已经被杀掉:

[root@hdp3~]#ps -ef | grep keepalived | grep -v grep
[root@hdp3~]#

 

六、总结

        本MySQL高可用方案配置简单,对现有MySQL架构无任何影响,也不需要停止数据库服务,完全联机操作即可。有一点需要注意,主从库的端口必须一样。

 

 

 

参考:

1. Keepalived+MySQL实现高可用
2. Keepalived权威指南

 

 

以上是关于使用Keepalived实现MySQL主从高可用的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 5.6通过Keepalived+互为主从实现高可用架构

MySQL之keepalived高可用

keepalived实现mysql高可用

Mysql互为主从+keepalived实现高可用性

Redis+Keepalived高可用环境部署记录

MySQL互为主从+Keepalived高可用数据库集群