配置
使用keepalived做主备,其中一台设置为master,一台设置为backup。当master出现异常后,backup自动切换为master。当backup成为master后,master恢复正常后会再次抢占成为master,导致不必要的主备切换。因此可以将两台keepalived初始状态均配置为backup,设置不同的优先级,优先级高的设置nopreempt解决异常恢复后再次抢占的问题。
有如下配置表示意思也比较简单,VIP为192.168.0.18,2台机器的初始state都是BACKUP,machineA的优先级是15,machineB的优先级是13,配置了/root/1.sh
这个来检测服务是否正常。
machineA机器配置:
1 | [root@iloqg8n3yb9mje ~]# cat /etc/keepalived/keepalived.conf |
machineB配置:
1 | global_defs { |
/root/1.sh配置如下:这个脚本用来检测服务是否正常,这个为了测试,设置当 /etc/keepalived/down
这个文件存在返回值为0,反之为1
1 |
|
vrrp_script
配置
vrrp_script是指通过脚本来检测服务是否正常,通过 man keepalived.conf
查看其参数的意思。
1 | vrrp_script <SCRIPT_NAME> { |
以上文的配置:
1 | vrrp_script check_mysql { |
我们把/etc/keepalived/down目录删除之后,machineA,17:45:06
有第一次检测异常,后面再过了20秒之后,直接提示了failed,同时优先级从20减为了15。说明需要达到fall的次数之后才会切优先级。以下是从message日志里面看到的:
1 | Dec 24 17:45:06 iloqg8n3yb9mje Keepalived_vrrp[109141]: Script `check_mysql` now returning 1 |
machineB,17:44:45检测到正常之后,就直接调整优先级了,说明rise的默认值为1。
1 | Dec 24 17:44:15 4n1eq6wnfvdwvj Keepalived_vrrp[51077]: /root/1.sh exited with status 1 |
日志显示优先级有做了切换,但是其他事情都没有做,VIP未没有正常切换。这是为什么呢?
原因分析
参考 keepalived之vrrp_script详解 的说法:
vrrp_script 里的script返回值为0时认为检测成功,其它值都会当成检测失败;
- weight 为正时,脚本检测成功时此weight会加到priority上,检测失败时不加;
- 主失败:
- 主 priority < 从 priority + weight 时会切换。
- 主成功:
- 主 priority + weight > 从 priority + weight 时,主依然为主
- 主失败:
- weight 为负时,脚本检测成功时此weight不影响priority,检测失败时priority – abs(weight)
- 主失败:
- 主 priority – abs(weight) < 从priority 时会切换主从
- 主成功:
- 主 priority > 从priority 主依然为主
- 主失败:
实测并不是这个结论,比较怀疑是版号不一致导致出现的结论不一样,但不管怎么说,VIP并未发生切换,所以跟想像中的不一样。
突发奇想,如果在vrrp_script不配置weight值,会怎么样呢?以下都是在machineA上面显示的日志:
1 | # 当脚本check_mysql检测失败的时候,VI_1这个实例就进入了FAULT状态 |
由此,可以说明 vrrp_script可以不配置weight值
,并且也不需要配置这个值,以避免意外情况发生。
另外,如果有遇到如下报错:
1 | Dec 24 17:41:50 iloqg8n3yb9mje Keepalived_vrrp[108697]: WARNING - default user 'keepalived_script' for script execution does not exist - please create. |
应该不会影响,但是可以在global配置项里面加上之后就不会有这个提示了。
1 | script_user root |
那么直接在vrrp_script下面写成 script "test -f /etc/keepalived/down && exit 0 || exit 1"
是否可以呢?经测试是有问题的。
notify
notify的用法:
- notify_master:当当前节点成为master时,通知脚本执行任务(一般用于启动某服务,比如nginx,haproxy等
- notify_backup:当当前节点成为backup时,通知脚本执行任务(一般用于关闭某服务,比如nginx,haproxy等)
- notify_fault:当当前节点出现故障,执行的任务;
- notify
表示只要状态切换都会调用的脚本,并且该脚本是在以上三个脚本执行之后再调用的
根据文档所写,notify会自动传以下参数:
1 | $1 = "GROUP"|"INSTANCE" |
所以要使用notify时,不需要接参数,跟其他的三个是有所区别的。
1 | notify_master "/root/2.sh master" |
脚本内容很简单,只是打印日志出来而出,如下:
1 | [root@4n1eq6wnfvdwvj ~]# cat 2.sh |
输出的日志如下:
1 | 2020-12-27 22:31:12 backup |
可以看到,notify的通知在notify_backup的后面。
脑裂问题
上文所述的都是业务服务异常了,导致的切换。那主备2台机器不通的情况下,keepalived会做什么操作呢?
VRRP控制报文只有一种:VRRP通告(advertisement),使用通过advert_int 1
这个参数来发送通告包的时延,默认是1秒发一次通告包。使用IP多播数据包进行封装,组地址为224.0.0.18,发布范围只限于同一局域网内。这保证了VRID在不同网络中可以重复使用。为了减少网络带宽消耗只有主控路由器才可以周期性的发送VRRP通告报文。备份路由器在连续三个通告间隔内收不到VRRP或收到优先级为0的通告后启动新的一轮VRRP选举。
一般情况下,只有主服务器会发VRRP的通告。
1 | [root@4n1eq6wnfvdwvj ~]# tcpdump -i any -nns0 vrrp |
如果在主服务器上设置iptables规则,date +"%F %T";iptables -I OUTPUT -p vrrp -j DROP
将vrrp协议发出的包禁掉,命令运行的时间为 2020-12-27 22:53:50
,那么观察下备服务器的进入MASTER的时间:
1 | Dec 27 22:53:54 iloqg8n3yb9mje Keepalived_vrrp[123054]: (VI_1) Receive advertisement timeout |
从上可以看出,vrrp的通告包超时了,节点进入了MASTER状态,那VIP生效的时间会延迟一秒:
1 | [root@iloqg8n3yb9mje ~]# for i in `seq 1 100`;do ip -4 -o addr |grep 192.168.0.18 -q && echo "`date +"%F %T"` have 192.168.0.18" || echo `date +"%F %T"` no~~~;sleep 1;done |
所以一般脑裂问题的排查思路有:
- virtual_router_id必须一样
- 防火墙将vrrp广播包给过滤掉了
- 机器负载异常,导致机器无法正常发送、或者收到vrrp包之后没有足够的时间进行CPU的处理,这样建议可以尝试增加advert_int时间
- 网卡异常等