诡异的网络故障排查过程
TCP/IP协议是个伟大的发明,如果你在用电脑、手机电子设备、智能终端等,你就无时无刻不在使用TCP/IP协议,当然对于coding的人来说,如果能够深入的学习TCP/IP协议,会对你的技术水平有个质的提升。三次握手、四次挥手、中间状态转化、慢启动、拥塞算法、滑动窗口等,这些算法和设计都被应用到了很多计算机系统设计中。
那么今天的问题是网络问题,既然是网络问题,就离不开TCP/IP协议。大家可能都比较清楚TIME_WAIT问题了,TIME_WAIT的问题已经讨论过很多了,那么今天的问题跟TIME_WAIT没关系,但是又感觉有些关系。
问题追查和解决过程
-
2017年底,xxx业务线服务做了一次小的部署调整(本来部署在首鸣机房的10.10.21.93/94/95,调整到了10.10.21.94/95/181),调整完成以后出现了一个诡异问题,从10.10.21.181访问10.10.21.251(lvs的vip地址,lvs可以理解成是一个四层<网络分为七层,其实第四层是TCP/IP层传输层>的负载均衡器,我们大量的使用到了),访问的过程中出现无规律的连接超时(内网环境按说不应该存在连接不上的情况),比例很高,大概占到了20%左右,当时通过ping来测试网络连通性是没问题的,但是通过http请求来测试tcp的端口连通性,发现大量的连接超时 connect timeout,当时着急解决问题,绕开了10.10.21.251,直接访问了当时xxx商城的vip(两台nginx通过keepalive做了一个HA高可用),算是解决了这个问题,为什么说是算是解决呢,是不出现connect timeout连接超时了,但是因为当时事情多,没有时间去追内网网络连接超时这个问题。
-
2018年初开始做支付模块的日志落地和kubernetes的精准调度(根据业务线做kubernetes逻辑的隔离调度,后边有问题会介绍),需要升级支付相关的服务,半夜升级pay服务,一升级完成立马报错了一堆connect timeout(连接内网的vip:10.10.21.251),当时正好赶上了一个其他的业务异常报警,以为connect timeout跟那个问题有关系,所以当时直接回滚服务,connect timeout消失。过后两天又进行服务落地,结果出现了同样的问题,已升级完成,立马报了很多connect timeout的错误。但是由于日志不全和部分丢失,也无法查看问题,当发现支付服务出现问题以后,立马进行了服务回滚,同样的connect timeout又消失了。。。
-
经过上两次问题,我们开会总结了一下,升级的时候一个节点一个节点的分批升级,这样快速定位问题,是不是单个节点出现问题了,从而能够更快的恢复和更好的排查问题。同样是在一个月黑风高的夜晚,运维同事A和开发同事B又开始搞事情了,一个节点一个节点的升级pay服务(总共六个pod节点),结果又一次出人意料,没有出现connect timeout,观察了一下没有问题,大家都很嗨皮的睡觉了。
-
升级以后的第二天没有问题,第三天的时候pay服务有个功能性的发版,结果通过发版平台进行服务升级发版的过程中,诡异的connect timeout又一次出现了,而且很多,这个时候运维能做的就是回滚,结果这次回滚没有起到预期的效果,回滚以后还是很多的connect timeout,检查日志发现connect timeout集中在一台物理机,那么要做的就是讲出问题的节点隔离重启。隔离以后短暂的恢复了,结果过了一会又开始出现超时,连续的重启回滚,算是临时止住了问题的继续爆发。
-
这个时候开始按照出问题的线索一点一点的检查,检查发现有两三台物理机连接10.10.21.251,无规律的超时,多么熟悉的旋律啊,这TM不是去年我遇到的问题么。好吧,该还的债少不了的。当时绕开了,这次不能再绕了。那么就开始查找问题。首先想到的是硬件问题,结果检查发现无太多的异样,其次想到了lvs的问题,当时lvs的资料很少,而且没有日志,所以从lvs端无从入手,那么就从网卡入手吧,ifconfig发现网卡drop包比较多
network-1.png
运维同学B查找资料发现可能是网卡参数有问题,需要调整一下,提升网卡的性能,通过ethtool命令可以设置网卡的buffer大小,当天晚上调整了网卡的buffer大小,结果调整以后drop无明显减小。 然后继续抓包发现drop的包都是VRRP(VRRP包的含义可以具体自己搜索)的包,其实是正常的丢弃,这个时候就排除了网卡的问题了。
network-2.png
-
后来有继续查找问题,运维同学B找到了一些资料,发现可能是操作系统的tcp参数引起的,这个参数就是tcp_tw_recycle和tcp_timestamps引起的,晚上调整了一下lvs接入服务器的tcp的参数,结果发现调整参数以后经常connect timeout的问题消失了,观察了几天发现问题确实解决。
原理追溯
-
为什么修改tcp_tw_recycle和tcp_timestamps能够解决connect timeout的问题呢?查阅一些文章说在用户的终端NAT的情况下会出现这种问题,NAT 后面的多个客户端的时钟不一定一致,fin 包有可能时间戳后退,就被抛弃了。
-
我们的lvs用的是DR模式,再一个因素,我们都是机房局域网访问,都是直接走交换机访问,不存在NAT的问题,所以这个一直没太想明白,也不确定是否真是这个原因引起的。后来又发现了两个诡异的问题,从10.10.2.77到10.10.2.7(10.10.2.61和10.10.2.58通过keepalive做了一个高可用,10.10.2.7是vip地址),可以ping通,但是telnet端口不通,也就是tcp/ip协议不通,但是同样的从其他的机器(10.10.2.82/21)到10.10.2.7可以通,多么熟悉的问题,又来了,但是这次是彻底不通,不是说概率性的不通,所以这次没有立刻的去调整参数,而且进行了抓包(抓取tcp/ip的包),在10.10.2.77和10.10.2.7上边同时抓包,抓包进行分析,发现了一个问题,就是从2.77发起tcp的握手,发送syn包以后确实没有回复ack,而是2.77进行了几次重试,最后连接超时connect timeout。跟网上介绍的一样:
network-3.png
那么这个时候就尝试调整了tcp_timestamps=0,立马解决了问题,不过修改tcp_timestamps=0可能会引起其他的问题,所以还是按照推荐的做为tcp_timestamps=1,tcp_tw_recycle=0。
-
其实这个时候还是面临的同样的问题,我们没有NAT环境,为什么会出现tcp的timestamp的时序问题,引起connect timeout呢?通过命令也能看到一些蛛丝马迹
network-4.png
再继续分析抓的包,最终还是找到了原因
network-5.png
network-6.png
network-7.png
上边的两个具体的tcp包,是我在同一个时间段间隔几秒钟的时间,在10.10.2.77上边抓取的,结果我们发现了两个timestamp,连接10.10.2.61的时间戳远大于连接10.10.2.7的时间戳,而这个时候10.10.2.7和10.10.2.61是同一台机器,因为192.168.2.7现在是192.168.2.61的vip,那么我们也就能够看出来为什么10.10.2.7一直连不上出现connect timeout了。而操作系统在发起tcp/ip协议包的时候,timestamp除了跟当前时间戳有关系,可能还跟对端ip有关系,这个具体需要去查看内核的文档或者是源码来查看。
总结
-
至此这个诡异的网络问题彻底解决,也彻底搞明白了TCP/IP协议跟操作系统结合过程中的这个小坑。
-
网络问题可能是搞计算机中问题最难解决的。
-
coding的闲余时间可以多看点计算机原理的东西,真的会有很大的帮助。
-
具体内核的文档和源码还需要继续追一下
网友评论