虚拟路由冗余协议(virtual router redundancy protocol,简称VRRP),是由IETF提出的解决局域网中配置静态网关出现单点失效现象的路由协议,1998年已推出正式的RFC2338协议标准,VRRP广泛应用在边缘网络中,它的设计目标是支持特定情况下IP数据流量失败转移不会引起混乱,允许主机使用单路由器,以及及时在实际第一跳路由器使用失败的情形下仍能够维护路由器间的连通性。
虚拟路由器
VRID
Master路由器
Backup路由器
虚拟IP地址(VIP)
IP地址拥有者
虚拟MAC地址(VMAC)
优先级
非抢占方式
抢占方式
主备备份
主主备份
keepalived程序是vrrp协议在linux主机上以守护进程方式的实现,能够根据配置文件生成IPVS规则 ,并对各real server的健康做检测,以及Loadbalance主机和backup主机之间failover的实现,keepalived在Centos6.4+收录到了发行版光盘中。
/etc/keepalived/keepalived.conf
Global configuration : 全局配置
global_defs {
...
}
VRRP Configuration : 配置VRRP实例
vrrp_instance NAME {
...
}
LVS Configuration : IPVS的相关配置
virtual_server IP PORT {
...
real_server IP PORT {
...
}
}
notification_email {}
: 邮件通知的对象,收件人邮箱notification_email_from
: 发件人邮箱smtp_server
: 邮件发送服务器IP地址smtp_connect_timeout
: 连接邮件服务器的超时时长router-id HOSTNAME
: 物理节点的标识符,建议使用主机名vrrp_mcast_grou4 224.0.0.18
: vrrp的多播地址,IPV4,默认为224.0.0.18vrrp_mcast_group6 ff02::12
: vrrp的多播地址, IPV6vrrp_script NAME { }
: 定义脚本,可以在vrrp_instance中使用track_script引用
nopreempt
: 定义为非抢占模式preempt_delay TIME
: 定义为延迟抢占模式state MASTER | BACKUP
: 在当前VRRP实例中(虚拟路由器组)此节点的初始实例Interface IFACE_NAME
: vrrp用于绑定VIP的接口,各节点网卡接口名称需保持一致virtual_route_id #
: 虚拟路由器的ID(VRID),可用值为0-255,默认为51priority #
: 当前路由器节点的优先级,可用范围为0-255advert_in #
: 通告时间间隔,单位是秒种,默认是1秒authentication { }
: 定义认证的特殊引用段
virtual_ipaddress { }
: 定义集群中主机的特殊引用
notify_master |
: 当前节点转为主节点触发的脚本notify_backup |
: 当前节点转为备用节点触发的脚本notify_fault |
: 当前节点出现故障时触发的脚本notify |
: 一般情况下, 只使用上面三个, 或者只使用下面一个track_script { VRRP_SCRIPT_NAME }
: 使用此引用,可以调用vrrp_script定义的脚本并执行track_script { IFACE_NAME }
: 调用vrrp_script内置方法,可以判断主机的网络接口是否正常,如果不正常将自动降低其权重,转为backup模式delay_loop
: 延迟多长时间检测集群服务是否OKlb_algo rr|wrr|lc|wlc|lblc|sh|dh
: lvs的调度算法lb_kind NAT|DR|TUN
: lvs的类型,如需支持fullnat,需要打补丁persistence_timeout
: 持久时长,0表示不启用nat_mask 255.255.255.0
: IP掩码地址,此处的nat没有写错protocol TCP
: lvs调度的协议,默认是udp,如果是udp可以不用添加此指令virtual_host
: 对哪个虚拟主机做健康状态检测,可以不定义quorum
: 最少法定票数,判断realserver有几台才是OK的quorum_up
: 添加票数quorum_down
: 降低票数sorry_server
: 定义sorry serverreal_server IP PORT { }
:定义一个real_server主机
weight
: 权重inhibit_no_failure
: 如果检测失败,就把权重设置为0notify_up |
: realserver上线通知,依赖脚本完成notify_down |
: realserver下线通知,依赖脚本完成HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK
: 对后端的realserver主机,使用相应的方法做健康状态检测
url { }
: 对url做健康检测的特殊引用
path
: 检测的url路径status_code
: 依赖返回状态码进行检测digest
: 依赖页面的hash值进行检测,基于genhash命令完成hash值计算nb_get_retry
: get请求的重试次数delay_befor_retry
: 两次重试之间的时间间隔,要延迟多长时间,再retryconnect_ip
: 默认会按real server的IP做健康状态检测,一般不需要再写,但有的时候可能有一个IP专门做健康状态检测的IP,故要手动添加上去connect_port
: 连接的端口bindto
: 如果keepalived主机有多个IP,定义用哪个IP完成健康状态检测connect_timeout
: 连接超时时长,默认为5秒,但这个时长比较长, 建议调整至3秒warmup
: 做健康状态检测的延迟, 即keepalived服务起来后,等待多长时间再开始健康状态检测,有时候后端的real server还未启动完成,故需要等待一段时间TCP_CHECK { }
: 传输层健康状态检测
connect_timeout
: 连接超时时长connect_ip
: 检测的realserver的IP,一般不需要写,同url中的参数一样connect_port
: 检测的realserver的port,一般不需要写,同url中的参数一样bindto
: 同url中的参数一样bind_port
: 使用哪个端口做健康状态检测实验环境:
172.16.36.70
172.16.36.71
######172.16.36.70的配置
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id [email protected]
~]# vim /etc/hosts
172.16.36.71 Centos7.pc2
~]# ntpdate 172.16.0.1
~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived_admin@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id Centos7.pc1 #路由设备在网络中的名称,一般为hostname
}
######使用vrrp_script实现依赖脚本监测文件的存在性,来降低节点的优先级,以此实现主备模式的切换
vrrp_script chk_down {
script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
interval 1
weight -20
}
######监测web的访问返回结果,判断服务的可用性, 来了解你节点的优先级
vrrp_script chk_nginx {
script "curl -s 172.16.36.70 | grep 172 &> /dev/null"
interval 1
weight -20
}
######监控主机的nginx是否存在,0信号只是做进程探测的
vrrp_script chk_nginx2 {
script "killall -0 nginx"
interval 1
weigth -20
}
vrrp_instance VI_1 {
state MASTER
interface eno16777736
virtual_router_id 100
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 99999999
}
virtual_ipaddress {
172.16.36.100/16 dev eno16777736 label eno16777736:1
}
notify_master "/etc/keepalived/keepalived.sh master"
notify_bakcup "/etc/keepalived/keepalived.sh backup"
notify_fault "/etc/keepalived/keepalived.sh fault"
track_script {
chk_down
chk_nginx
eno16777736 #监控主机的网卡,如果出现故障可自动降低优先级。 此脚本调用不用定义,是vrrp_script内置的
}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
mailsubject="$(hostname) to be $1:vip floating"
mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
notify master
systemctl start nginx.service
exit 0
;;
backup)
notify backup
systemctl restart nginx.service
exit 0
;;
fault)
notify fault
systemctl stop nginx.service
exit 0
;;
*)
echo "Usage: $(basename $0) {master|backup|fault}"
exit
;;
esac
######172.16.36.71的配置
172.16.36.71
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id [email protected]
~]# vim /etc/hosts
172.16.36.70 Centos7.pc1
~]# ntpdate 172.16.0.1
~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived_admin@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id Centos7.pc2
}
vrrp_script chk_down {
script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
interval 1
weight -20
}
vrrp_script chk_nginx {
script "curl -s http://172.16.36.100 | grep 172 &> /dev/null"
interval 1
weight -10
}
vrrp_instance VI_1 {
state BACKUP
interface eno16777736
virtual_router_id 100
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 99999999
}
virtual_ipaddress {
172.16.36.100/16 dev eno16777736 label eno16777736:1
}
notify_master "/etc/keepalived/keepalived.sh master"
notify_bakcup "/etc/keepalived/keepalived.sh backup"
notify_fault "/etc/keepalived/keepalived.sh fault"
track_script {
chk_down
chk_nginx
}
}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
mailsubject="$(hostname) to be $1:vip floating"
mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
notify master
systemctl start nginx.service
exit 0
;;
backup)
notify backup
systemctl restart nginx.service
exit 0
;;
fault)
notify fault
systemctl stop nginx.service
exit 0
;;
*)
echo "Usage: $(basename $0) {master|backup|fault}"
exit
;;
esac
//Nginx Web服务的守护脚本
#!/bin/bash
while true
do
if [ $(netstat -tlnp|grep nginx|wc -l) -ne 1 ]
then
/etc/init.d/keepalived stop
fi
sleep 2
done
问题:keepalived 一个作为 master,另一个做为backup 。当 master 挂了后,backup 接管。但存在一个问题,当 master 恢复了后,master 又会接管会来,这个频繁切换对于业务来说是不好的,再快的切换也会有影响。
解决方案:两个配置都使用backup,然后权重高的使用nopreempt,也就是不抢占的意思,这样子,就不会有两次切换的操作了。
在高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障。两个节点上的HA软件像“裂脑人”一样,争抢“共享资源”、争起“应用服务”,就会发生严重后果——或者共享资源被瓜分、2边“服务”都起不来了;或者2边“服务”都起来了,但同时读写“共享存储”,导致数据损坏。
(1)高可用服务器对之间心跳线链路发生故障,导致无法正常通信。
(2)因心跳线坏了(包括断了,老化)。
(3)因网卡及相关驱动坏了,ip配置及冲突问题(网卡直连)。
(4)因心跳线间连接的设备故障(网卡及交换机)。
(5)因仲裁的机器出问题(采用仲裁的方案)。
(6)高可用服务器上开启了 iptables防火墙阻挡了心跳消息传输。
(7)高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败。
(8)其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件Bug等。
Keepalived配置里同一 VRRP实例如果virtual_router_id两端参数配置不一致也会导致裂脑问题发生。
keepalived 进程被强制kill后,虚拟 ip 移除不掉,导致脑裂的现象。
在实际生产环境中,可以从以下几个方面来防止裂脑问题的发生:
(1)同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了,另一个还是好的,依然能传送心跳消息。
(2)当检测到裂脑时强行关闭一个心跳节点(这个功能需特殊设备支持,如Stonith、feyce)。相当于备节点接收不到心跳消患,通过单独的线路发送关机命令关闭主节点的电源。
(3)做好对裂脑的监控报警(如邮件及手机短信等或值班).在问题发生时人为第一时间介入仲裁,降低损失。例如,百度的监控报警短倍就有上行和下行的区别。报警消息发送到管理员手机上,管理员可以通过手机回复对应数字或简单的字符串操作返回给服务器.让服务器根据指令自动处理相应故障,这样解决故障的时间更短。
#!/bin/bash
while true
do
Master=10.0.0.10
Backup=10.0.0.11
Vip=10.0.0.100
M_num01=/bin/ping -c 2 -W 3 $Master >/dev/null 2>&1 ; echo $?
B_num01=/bin/ping -c 2 -W 3 $Backup >/dev/null 2>&1 ; echo $?
if [ "B_num01" -ne 0 ];then
exit 1
fi
M_num02=ssh $Master ip addr | grep $Vip | wc -l
B_num02=ssh $Backup ip addr | grep $Vip | wc -l
if [ "$M_num02" -ne 0 -a "$B_num02" -ne 0 ];then
echo "The server suffered a brain fracture"
else
echo "Server normal"
fi
done
上边脚本检测,但如果使用iptables把vrrp的output禁止掉,也会脑裂,因为ping是通的,但vrrp包发不出去,另外一台虚拟ip也会起来, 当检测到虚拟ip的arp响应时,就把虚拟ip给delete掉,可以再加上kill掉keepalived。
当在同一个局域网内部署了多组Keepalived服务器对,而又未使用专门的心跳线通信时,可能会发生高可用接管的严重故障问题。之前已经讲解过Keepalived高可用功能是通过VRRP协议实现的,VRRP协议默认通过IP多播的形式实现高可用对之间的通信,如果同一个局域网内存在多组Keepalived服务器对,就会造成IP多播地址冲突问题,导致接管错乱,不同组的Keepalived都会使用默认的224.0.0.18作为多播地址。此时的解决办法是,在同组的Keepalived服务器所有的配置文件里指定独一无二的多播地址,配置如下:
global_defs { #全局配置
router_id LVS_19 #服务标识
vrrp_mcast_group4 224.0.0.19 #这个就是指定多播地址的配置
}
#提示:
1)不同实例的通信认证密码也最好不同,以确保接管正常。
2)另一款高可用软件Heartbeat,如果采用多播方式实现主备通信,同样会有多播地址冲突问题。
————————————————————
来源:公众号LINUX运维ZHAO,运维部落