目录
一、问题提出
二、方案选择
三、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是对VRRP的一个实现,因此在理解Keepalived的工作原理之前,有必要先了解VRRP的原理。
在现实的网络环境中,两台需要通信的主机(end-host)大多数情况下并没有直接地物理连接。对于这样的情况,它们之间的路由怎么选择?通常有两种方法解决如何选定到达目的主机的下一跳路由问题:
很明显,在主机上配置动态路由,因为管理、维护成本以及是否支持等诸多问题是不切实际的。那么配置静态路由就变得很流行。实际上,这种方式一直沿用至今。但是,路由器,或者说默认网关(default gateway)却经常成为单故障点。就算配置了多个静态路由,却因为必须重启网络才能生效而变得不实用。
VRRP(虚拟路由冗余协议,Virtual Router Redundancy Protocol)的目的就是为了解决静态路由单点故障问题。它通过一种竞选(election)协议动态地将路由任务交给LAN中虚拟路由器中的某台VRRP路由器。这里有两个关键名词:VRRP路由器和虚拟路由器。
在一个VRRP虚拟路由中,有多台物理的VRRP路由器,但是这多台物理路由并不同时工作,而是由一台称为master的负责路由工作,其它的都是backup。master并非一成不变,VRRP协议让每个VRRP路由器参与竞选,最终获胜的就是master。master有一些特权,比如拥有虚拟路由器的IP地址,我们的主机就是用这个IP地址作为静态路由的。拥有特权的master要负责转发发送给网关地址的包和响应ARP请求。
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包使用了加密协议进行加密。
Keepalived是一个高度模块化设计的软件,从源代码结构似乎也很容易看出这一点。Keepalived 1.2.13源代码中只有如下目录:check core etc include libipvs-2.4 libipvs-2.6 vrrp
Keepalived架构如图2所示。
图2
Keepalived采用了多进程的设计模式,每个进程负责不同的功能,我们在使用LVS的机器上通常可以看到三个Keepalived进程:
111 keepalived < 父进程,负责内存管理、监控子进程等
112 \_ keepalived < VRRP子进程
113 \_ keepalived < healthchecker子进程
这里所谓的控制面板就是对配置文件的编译和解析。Keepalived的配置文件解析比较另类,并不是一次解析所有配置,而是只在用到某模块时才解析相应的配置。在源文件里面可以看到类似XXX_parser.c的文件,就是做这个用的。
WatchDog框架提供了对VRRP和healthchecker子进程的监控。
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主从复制配置从略。
用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
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。
vrrp_script配置业务进程监控脚本。
/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里面任何一个实例出现问题都会发生切换。
vrrp_instance配置VRRP实例。VRRP实例表示在上面开启了VRRP协议。这个实例说明了VRRP的一些特性,比如主从、VRID等等。可以在每个网卡上开启一个实例。VRRP实例主要定义vrrp_sync_group里面的每个组的漂移IP等。
/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权威指南