KeepAliveD in AWS
需求
在AWS环境,已有两台服务器安装Mysql,并配置为主主模式(Active/Active)。要求实现一种方案,当一个Mysql故障后,能自动切换到另一Mysql服务器,提供服务的高可用。
操作系统要求: ubuntu14.04
前期调研
想在AWS 环境实现数据库的高可用,考虑了方案:
- RDS -- AWS服务,使用DNS 实现服务切换,耗时1分钟-- 时间太长,不满足需求
- ELB -- AWS服务,本质是实现负载均衡。不能实现Active/Passive 模式 -- 不满足需求
- Haproxy -- 使用 Active/Passive模式,能够实现Mysql服务的切换,切换耗时15秒。但这个方案需要一个新的VM,在解决一个问题的同时,引入了一个新的单点故障。 -- 放弃
- Veritas -- 传统的HA方案,是商业软件,需要额外付费。配置的时候需要双网卡来配置心跳检测网络。这种网卡冗余方案在公有云中不合时宜——先跳过,如果其他方案不可行,再回过头来看。
- HeartBeat -- 需要单独网络做心跳检查 -- 先跳过。
- KeepAliveD -- 公司其他部门使用KeepAliveD+Apache实现Web高可用,是一套成熟,可靠的方案。而且服务切换只需要3-5秒,效率很高。
选择方案
最后考虑 AWS 环境中部署keepalived + Mysql 实现高可用。
KeepAliveD 工作原理
Keepalived是一个免费开源的,用C编写的类似于layer3, 4 & 7交换机制软件,具备我们平时说的第3层、第4层和第7层交换机的功能。主要提供loadbalancing(负载均衡)和 high-availability(高可用)功能,负载均衡实现需要依赖Linux的虚拟服务内核模块(ipvs),而高可用是通过VRRP协议实现多台机器之间的故障转移服务。
简单来说,只需要把它当作路由器即可!
VRRP协议
网络在设计的时候必须考虑到冗余容灾,包括线路冗余,设备冗余等,防止网络存在单点故障,那在路由器或三层交换机处实现冗余就显得尤为重要,在网络里面有个协议就是来做这事的,这个协议就是VRRP协议,Keepalived就是巧用VRRP协议来实现高可用性(HA)的。
遇到的问题:
- 通过命令 “apt install keepalived” 安装包不可用。
- 亚马逊云不支持KeepAliveD中的组播模式。主备之间的VRRP包互相发不通。
- 在AWS环境中,所有的ARP广播都被禁止了。这样KeepAliveD的IP欺骗机制基本上也就不可行了。在资源服务器上配置的Virtual IP,应用服务器没有办法访问。
VIP的默认配置是不生效的:(AWS 中,只有本机认可,没有广播,其他服务器不知道)
- 在AWS环境中,所有的ARP广播都被禁止了。这样KeepAliveD的IP欺骗机制基本上也就不可行了。在资源服务器上配置的Virtual IP,应用服务器没有办法访问。
解决办法:
- 需要下载源码包,并针对ubuntu 做修改(源码适用redhat)。
- 切换KeepAliveD到单播模式,在配置中增加单播机器的IP:
unicast_src_ip 172.*.*.1 #localIp
unicast_peer {
172.*.*.124 #Resource-02
}
还有一点需要特别注意,VRRP协议既不属于TCP也不属于UDP,在做防火墙策略的时候,在协议类型选项需要选“All traffice”的选项来防止由于防火墙原因造成通信问题。
-
- 用 AWS CLI 来实现 VIP 指向的切换
-
3.1.1 如果使用private IP作为 VIP,则:两个服务器配置三个IP 地址,其中一个是 Secondary private IP,它作为内网的VIP使用。这个配置是基础配置。也就是说,如果一个IP指向这台服务器,可是这台服务器上的网卡不认为自己拥有这个IP是不行的。
-
3.1.2 如果Public IP (EIP) 作为 VIP,配置相对简单,可以跳过Secondary private IP
-
3.2 在两台服务器上安装亚马逊云自己的客户端工具(awscli) 并配置(Authentication,IP 切换时使用)
-
3.3 在KeepAliveD认为自己获取到Master权限的时候,调用awscli命令让Virtual IP实际指向本服务器。这个逻辑是核心逻辑。亚马逊云虽然不允许广播ARP,但可以用命令行指定网卡(ENI)的Secondary-private-ip-address。这个命令的具体形式如下:
su - ubuntu -c "aws ec2 assign-private-ip-addresses --network-interface-id $ENI --private-ip-addresses $VIP --allow-reassignment"
ip address add $VIP/20 dev eth0
$ENI指的是网卡的ID,$VIP是虚拟IP,分配Private IP后,必须用ip命令把它启用(OS 能识别出这个变化) (具体原因的官方解释)
【已知问题】keepalived 被停掉后,因script 无法被调用,导致本机VIP无法被删除,于是本机的VIP连接继续指向本地,其它服务器不受影响。也就是说本机Mysql继续认为自己是主服务器,但由于没有外部数据写入,虽然它是错的,但也没有实质的影响。
【注】使用EIP无此问题。(直接从AWS云平台获取Public IP,没有到OS这一级)
如果把外网EIP作为VIP,则:
aws ec2 disassociate-address --public-ip $EIP
aws ec2 associate-address --public-ip $EIP --instance-id $INSTANCE_ID
EIP(Elastic IP) 是外网IP,先释放,再分给某个instance
安装步骤
在ubuntu14平台,两台Mysql Server所在的服务器都安装和配置KeepAliveD。
安装依赖
$ sudo apt update
$ sudo apt install libssl-dev gcc make awscli daemon
下载源包并编译
$ wget http://www.keepalived.org/software/keepalived-1.3.9.tar.gz
$ tar zxf keepalived-1.3.9.tar.gz
$ cd keepalived-1.3.9
$ ./configure --prefix=/usr/local/keepalived --sysconf=/etc
编译结果:
Keepalived configuration
------------------------
Keepalived version : 1.3.9
Compiler : gcc
Preprocessor flags :
Compiler flags : -Wall -Wunused -Wstrict-prototypes -Wextra -g -O2
Linker flags :
Extra Lib : -lcrypto -lssl
Use IPVS Framework : Yes
IPVS use libnl : No
IPVS syncd attributes : No
IPVS 64 bit stats : No
fwmark socket support : Yes
Use VRRP Framework : Yes
Use VRRP VMAC : Yes
Use VRRP authentication : Yes
With ip rules/routes : Yes
SNMP vrrp support : No
SNMP checker support : No
SNMP RFCv2 support : No
SNMP RFCv3 support : No
DBUS support : No
SHA1 support : No
Use Debug flags : No
Use Json output : No
Stacktrace support : No
Memory alloc check : No
libnl version : None
Use IPv4 devconf : No
Use libiptc : No
Use libipset : No
init type : upstart
Build genhash : Yes
Build documentation : No
*** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
Install
$ make
$ sudo make install
针对ubuntu 修改配置:
$ sudo cp keepalived/etc/init.d/keepalived /etc/init.d
$ sudo vi /etc/init.d/keepalived
修改启动脚本 /etc/init.d/keepalived
. /etc/rc/d/init.d/functions #注释这句,新增下行
. /lib/lsb/init-functions
daemon keepalived ${KEEPALIVED_OPTIONS} #注释该行,新增下行
daemon keepalived start
$ sudo mkdir -p /var/lock/subsys
拷贝运行的核心文件
$ sudo cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
$ sudo vi /etc/keepalived/keepalived.conf #运行的配置文件
For master:
配置分为三部分:
global_defs 全局配置
vrrp_script 服务健康检查脚本
vrrp_instance 完成keepalived 服务健康检查,VIP切换
global_defs {
router_id backup_cluster # 标识本节点的字符串,通常为hostname,但不一定非得是hostname,故障发生时,邮件通知会用到
}
vrrp_script chk_mysql {
script "killall -0 mysqld" # 监控服务脚本,尽量简单,判断返回值0 或非0
interval 2 # check every 2 seconds
fall 2 # require 2 failures for KO
rise 2 # require 2 successes for OK
}
vrrp_instance VI_1 { # 实例名称
state BACKUP # 可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER
interface eth0 # 节点固有IP(非VIP)的网卡,用来发VRRP包做心跳检测
priority 100 # 用来选举master的,要成为master那么这个选项的值最好高于其他机器50个点,该项取值范围是1-255(在此范围之外会被识别成默认值100)
nopreempt # 服务恢复后成为backup, 不会抢回master避免频繁切换
virtual_router_id 51 # 虚拟路由ID,取值在0-255之间,用来区分多个instance的VRRP组播,同一网段内ID不能重复;主备必须为一样;
unicast_src_ip 172.31.19.247 # AWS中组播被禁,采用点对点通信。 这是本机IP
unicast_peer {
172.31.21.194 # 这是另一台keepalive server IP
}
advert_int 1 # 检查间隔默认为1秒,即1秒进行一次master选举
authentication { # 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)
auth_type PASS # 默认是PASS认证
auth_pass MrUse # PASS认证密码
}
track_script {
chk_mysql
}
notify /etc/keepalived/failover.sh
}
For Backup:
global_defs {
router_id backup_cluster # 标识本节点的字符串,通常为hostname,但不一定非得是hostname,故障发生时,邮件通知会用到
}
vrrp_script chk_mysql {
script "killall -0 mysqld"
interval 2
}
vrrp_instance VI_1 { # 实例名称
state BACKUP # 可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER
interface eth0 # 节点固有IP(非VIP)的网卡,用来发VRRP包做心跳检测
priority 40 # 用来选举master的,要成为master那么这个选项的值最好高于其他机器50个点,该项取值范围是1-255(在此范围之外会被识别成默认值100)
virtual_router_id 51 # 虚拟路由ID,取值在0-255之间,用来区分多个instance的VRRP组播,同一网段内ID不能重复;主备必须为一样;
unicast_src_ip 172.31.21.194 # 跟master 设置反过来
unicast_peer {
172.31.19.247
}
advert_int 1 # 检查间隔默认为1秒,即1秒进行一次master选举
authentication { # 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)
auth_type PASS # 默认是PASS认证
auth_pass MrUse # PASS认证密码
}
track_script {
chk_mysql
}
notify /etc/keepalived/failover.sh
#notify_master /etc/keepalived/master.sh
#notify_backup /etc/keepalived/backup.sh
#notify_fault /etc/keepalived/fault.sh
}
Keepalived notify脚本
notify脚本是keepalived集群管理脚本,当keepalived角色state状态发生变化时都会执行这个脚本。 AWS中默认方法不可行,只能靠它来实现IP切换。
配置aws cli:
获取网卡 eni 信息:
$ aws ec2 describe-instances --instance-ids i-0f530d6377bcd4db9 --query Reservations[].Instances[].NetworkInterfaces[].NetworkInterfaceId
[
"eni-ee4c45c6"
]
or
$ aws ec2 describe-instances --instance-ids i-0f530d6377bcd4db9 | grep eni
网页上也能查到:
Snip20180611_3.pngVIP 切换脚本:
failover.sh
#!/bin/bash
VIP=172.31.31.31
ENI=eni-8df310ac ## 这是本机eth0 网卡的ID,另一server不同
LOG=/etc/keepalived/failover.log
TYPE=$1
NAME=$2
STATE=$3
echo -e "\n##### failover to $STATE status ######" >> ${LOG}
date >> ${LOG}
case $STATE in
"MASTER")
su - ubuntu -c "/usr/bin/aws ec2 assign-private-ip-addresses --network-interface-id $ENI --private-ip-addresses $VIP --allow-reassignment" >> ${LOG} 2>&1
ip address add $VIP/20 dev eth0 >> ${LOG} 2>&1
echo -e "##### complete master script for ${NAME} ######\n" >> ${LOG}
;;
"BACKUP"|"FAULT")
ip address del $VIP/20 dev eth0 >> ${LOG} 2>&1
echo -e "##### complete $STATE script for VRRP ${TYPE} ${NAME} ######\n" >> ${LOG}
;;
*)
echo "unknown state ${STATE} for VRRP ${TYPE} ${NAME}"
exit 1
;;
esac
后续服务启动和检查
添加为系统服务
$ sudo update-rc.d keepalived defaults
启动keepalived
$ sudo /etc/init.d/keepalived start
查看keepalived 日志
$ tail -f /var/log/syslog
查看自定义脚本生成的日志
$ tail /etc/keepalived/failover.sh
mysql 连接测试
$ mysql -uhive -phive -h172.31.31.31
网友评论