前言
开心一刻
医院里,一母亲带着小女孩打针。小女孩:“妈妈我不想打针,疼!”妈妈:“宝贝儿听话,这里这么多护士阿姨,咱们找个打针不疼的。”小女孩:“那哪个阿姨打针不疼呢?”妈妈:“妈妈也不知道,咱们试试看吧。”小女孩高兴的点了点头。。。
路漫漫其修远兮,吾将上下而求索!
github:https://github.com/youzhibing
码云(gitee):https://gitee.com/youzhibing
问题背景
Mycat - 实现数据库的读写分离与高可用写完之后,本以为一两天就能写完Mycat - 高可用与负载均衡实现,满满的干货!,可事实是却用了一个星期;期间虽然产生了一系列的问题,但主要还是卡在了keeplaived实现mycat的高可用,那时候两台keepalived服务器的keepalived.conf内容如下
细心的朋友应该已经找到问题了,不管你找没找到问题,都可以准备好花生、瓜子和啤酒,且看我是如何埋雷和扫雷的
vip查看问题
个人一直用ifconfig命令来管理linux的网络配置,但是keepalived启动之后通过ifconfig命令却看不到vip。ifconfig是net-tools中已被废弃使用的一个命令,许多年前就已经没有维护了。iproute2套件里提供了许多增强功能的命令,ip命令即是其中之一,大多数Linux发行版已经预装了iproute2工具,而没有预装net-tools,ip命令功能更强大,旨在取代ifconfig。我们可以用ip命令查看vip的绑定情况,具体如下
这个问题还真卡了我一会,一直以为vip绑定失败,但是看/var/log/message,又没发现有什么问题,并且还能ping通vip。我这个无知者是有多无畏、多自信呀!
更多关于ifconfig、ip的信息,大家可以去网上查阅,这里我就不细讲了(其实是不知道,)。
检测脚本问题
单独执行命令是正确的;命令放入检测脚本中,部分是正确的;检测脚本结合keepalived,正确的更少了,具体我们往下看
ps命令查询mycat进程
check_pid.sh具体配置如下
#!/bin/bash count=`ps -ef|grep mycat |grep -v grep | wc -l` time=$(date "+%Y-%m-%d %H:%M:%S") if [ $count = 0 ]; then echo "$time : count=$count, mycat is not running..." >> /var/log/keepalived_check.log exit 1 # 返回1说明脚本非正常执行,mycat不在运行中 else echo "$time : count=$count, mycat is running..." >> /var/log/keepalived_check.log exit 0 # 返回0说明脚本正常执行,mycat正在运行中 fi
ps -ef与ps aux效果一样,我就只演示一个了,结果如下
ps命令单独执行,当mycat没启动时,查询到的mycat进程数是0,当mycat在运行中,查询到的是2(大于0表示mycat在运行中),很正确,没毛病;可当ps命令放到check_pid.sh中,执行的结果却有点不一样,当mycat没启动时,查到的进程数竟然是2,而当mycat在运行中,查到的进程数是4,为什么是这种结果,至今我还没搞明白,表面上看着像是单独执行ps命令的翻倍,为什么翻倍,不得而知 。很显然,check_pid.sh这么写不行。
环境变量中mycat命令
既然ps命令查mycat进程数行不通,我们就用mycat命令(将MyCat配置到环境变量中在Mycat - 实现数据库的读写分离与高可用已讲过),check_pid.sh具体配置如下
#!/bin/bash count=`mycat status|grep "Mycat-server is running" | wc -l` time=$(date "+%Y-%m-%d %H:%M:%S") if [ $count = 0 ]; then echo "$time : count=$count, mycat is not running..." >> /var/log/keepalived_check.log exit 1 # 返回1说明脚本非正常执行,mycat不在运行中 else echo "$time : count=$count, mycat is running..." >> /var/log/keepalived_check.log exit 0 # 返回0说明脚本正常执行,mycat正在运行中 fi
测试结果如下
单独执行命令,结果是正确的,单独执行check_pid.sh,结果也是正确的,可偏偏check_pid.sh结合keepalived却出错了,这就难受了 。
绝对路径的mycat命令
虽然上述两个问题的原因未知,但我们最终的目的:keepalived结合check_pid.sh正确执行,还是要实现的,我们再换个方式试下,用mycat命令的绝对路劲行不行呢? 具体配置如下
#!/bin/bash count=`/usr/local/mycat/bin/mycat status |grep 'Mycat-server is running' | wc -l` time=$(date "+%Y-%m-%d %H:%M:%S") if [ $count = 0 ]; then echo "$time : count=$count, mycat is not running..." >> /var/log/keepalived_check.log exit 1 # 返回1说明脚本非正常执行,mycat不在运行中 else echo "$time : count=$count, mycat is running..." >> /var/log/keepalived_check.log exit 0 # 返回0说明脚本正常执行,mycat正在运行中 fi
单独执行命令与单独执行check_pid.sh我就不演示了,与上述:环境变量中mycat命令 无差,keepalived结合check_pid.sh测试结果如下
终于搞对了,就是你了:用绝对路径的mycat命令!此刻心情真的是。
在check_pid.sh中有两种做法可以满足keepalived进行vip转移的条件
1、推荐做法,返回mycat检测结果给keepalived
如果mycat不在运行中,则返回1,若mycat正在运行中则返回0,注意是使用exit 0或exit 1来返回检测结果,与我们平时理解的有些不一样。keepalived会根据这个返回结果相应的增减优先级,keepalived集群会根据各个节点的优先级重新选举master
keepalived优先级 = priority + weight * script的结果,脚本执行返回0,script则为true,否则script为false,权重大的抢占到vip,成为master
2、野蛮做法,直接杀掉keepalived进程
这是比较野蛮的做法,一旦检测到mycat进程不存在,则直接killall keepalived,这时候就不需要关注返回值了,相当于将当前keepalived踢出了keepalived集群。这么做有点不太好,就是当我们把mycat修复后,不但要重启mycat,也需要重启keepalived。
virtual_router_id问题
具体日志输出
Jan 17 09:53:44 localhost Keepalived_vrrp[1655]: ip address associated with VRID not present in received packet : 192.168.1.200 Jan 17 09:53:44 localhost Keepalived_vrrp[1655]: one or more VIP associated with VRID mismatch actual MASTER advert Jan 17 09:53:44 localhost Keepalived_vrrp[1655]: bogus VRRP packet received on eth0 !!! Jan 17 09:53:44 localhost Keepalived_vrrp[1655]: VRRP_Instance(VI_1) Dropping received VRRP packet...
意思是说virtual_router_id重复了,当时还愣了一下:virtual_router_id不是应该一致吗? 主从热备+负载均衡(LVS + keepalived)中配置的就是一致,当时没去细想,既然日志提示重复了,那就改一个让其不重复呗,一个virtual_router_id值设置成66,一个virtual_router_id值设置成65,此提示消除,vip能够正常绑定上,但此时就出现了keepalived“脑裂”问题,两台keepalived服务器上都出现了vip,如下图
“脑裂”问题
何谓脑裂,指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。
vip出现了多个,我就主观的认为是keepalived出现了脑裂,上网查资料、提问求助、问好友、换centos系统版本、换keepalived版本、查阅keepalive的官网、等等,尝试各种方法(就是没有对比keepalived.conf,一直在copy错的keepalived.conf,),都没有找到答案,期间一度想放弃,可我一根筋的性格不允许我这么做;终于皇天不负有心人,无意之中我找到了问题所在,具体排查过程且听我慢慢道来。
防火墙是否放行vrrp
由于是本地测试,我一般都是关了防火墙的,生产环境不能直接关闭防火墙,而是设置防火墙来放行vrrp包;查看vrrp包情况:tcpdump -i eth0|grep VRRP
tcpdump命令若不存在,则可以执行命令:yum install -y tcpdump进行安装。如上图所示,两台keepalived服务器都是能正常收到彼此的vrrp包
selinux是否关闭
/usr/sbin/sestatus -v 查看selinux状态;/etc/selinux/config文件可以配置selinux开始与关闭,修改之后重启系统生效。
两台keepalived服务的selinux也是关闭的
keepalived官网查询信息
无奈之下我想到了官网,想看看官网中有没有提到脑裂问题,或者说是哪个版本修复了脑裂问题,changelog中查询split关键字,结果如下
貌似1.2.9版本有修复脑裂问题,而我的keepalived版本分别是:keepalived-1.2.13-5.el6_6.i686和keepalived-1.3.5-8.el7_6.x86_64,应该不是低版本的问题
博问求助
感觉形式越来越不利了,我想到了园子的博问,于是我在博问栏进行了提问:keepalived脑裂,有人浏览了,但没人回答,可能是问的姿势不对,亦或是未碰见有缘人
天无绝人之路
各方面都显示正确,可结果却不正确,真的让人很绝望!!!,此刻我的心情...... 你们懂的
山重水复疑无路,柳暗花明又一村。众里寻她千百度,蓦然回首,那人却在灯火阑珊处。拨开云雾见天日,守得云开见月明。......实在是装不下了......
不知道是上天眷顾,还是自己抽疯,竟然鬼使神差的去比较keepalived.conf文件,结果发现了惊天大幂幂,不对,是惊天大秘密:
此刻心情五味杂陈,怎么VIP一开始就配置的不一样,是不是室友趁我外出动了我代码?嗯,应该是的。看到vip的不同,让我看到了一丝曙光,更犹如看到刚出浴的美人一般,我牢牢抓住最后这根救命的稻草,重新展开部署与测试,终于出现了意料中的结果,此时我如释重负,瘫倒在床上思考了一会人生(,你为何如此美?)。keepalived.conf的正确配置,请查看Mycat - 高可用与负载均衡实现,满满的干货!。
这特么简直就是一个天大的乌龙! 我的这波操作真的是、、,太特么刺激了......,差点把自己玩死......
最佳实践
1、mycat存活检测脚本中,用绝对路径的mycat命令,不要用ps查询mycat进程,也不要用配置好的缩写mycat命令;当然了,如果我们用lvs实现了mycat的负载均衡,那么mycat检测脚本就可以省略了;
2、keepalived.conf写完之后用比较工具进行代码比较,可以防止少改、多改以及手抖的情况,避免出现本文的情况(mmp的);
3、在MASTER节点的 vrrp_instance中配置nopreempt,当它异常恢复后,即使它的priority更高也不会抢占,这样可以避免正常情况下做无谓的切换;
总结
1、环境搭建过程中一定要仔细小心,分步骤、环节,保证各个步骤、环节都正确,即使出现了问题,我们也能很快定位到是哪个步骤、环节出了问题,不至于出现类似本文的情况:明明不是脑裂问题,却死盯着脑裂不放,背道而驰,怎么解决的了?
2、如果确实是脑裂问题,我们可以从如下几个方面进行排查
防火墙是否放行vrrp包,推荐放行vrrp包,而不是野蛮式的关闭防火墙;keepalived配置问题,用文件比较工具比较keepalived.conf,不同之处非常少,很容易比较;selinux设置,这个我没研究过,也可作为一个排查点。一般而言从这三方面入手,基本能解决脑裂问题,实在是不行,则我们可以自写脚本,进行第三方仲裁。
3、虚拟路由编号(virtual_router_id),同集群,主备必须一致,不同集群不能相同;一般而言,我们只会有一个keepalived集群,所以配置成一样就没错,即使报了相关的错,也应该从其他方面找问题,而不是改动virtual_router_id。
参考
记一次keepalived脑裂问题查找