1.问题描述
某V2X平台进行性能升级优化,在压测50万车的过程中,发现部分车辆出现延迟上线的问题,经反复验证后,该问题仅在部分网络环境下复现。
2.排查过程
对延迟上线的终端进行了重启,在接收报文的服务器上使用tcpdump命令抓取TCP报文,并将报文导出,本地使用wireshark进行分析,检查后发现部分报文校验存在问题,问题报文占比不大,不大可能是问题所在,还有一个问题就是重新建立连接时间比较长,除此之外未检查到其他问题。排查陷入僵局,但TCP建立连接时间过长,不应该触发超时重传吗?此时发现TCP抓包存在问题,没有抓到想要的TCP报文,最初是怀疑防火墙问题,但报文并未抓到防火墙的相关的报文,不太可能是防火墙问题,于是开始怀疑内核参数问题,有可能是内核参数配置存在问题,使用cat proc/version查看linux内核版本为3.10,如图所示:
使用cat /proc/sys/net/ipv4/tcp_tw_recycle和cat /proc/sys/net/ipv4/tcp_timestamps发现均被开启,检查TCP包的丢弃情况,如图所示:
有大量的报文因时间戳问题被丢弃,导致tcp断连,车辆延迟上线,后续查找部署文档发现内核参数因高并发优化而设置成这样,最终导致此问题,问题参数如下所示:
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
在《Linux内核协议栈丢弃SYN报文的主要场景剖析》一文中对无法建立连接和丢包问题进行了详细的解答,简单来说就是同时开启recycle和timestamps的选项,会使用per-host PAWS机制(序列号防缠绕)进行开始回收,在Linux发明这个per-host PAWS机制来让TIME-WAIT状态快速回收时,认为这是"clever way",是基于IPv4地址池数量充足的网络环境下来做的解决方案。而随着Internet的快速发展,NAT的应用越来越普遍,客户端在SNAT设备内部的来访问同个服务器的环境非常普遍,报文被per-host PAWS机制丢弃,per-host, 是相对per-connection来讲的,就是对对端主机IP做检查而非对IP端口四元组做检查,在NAT环境下,外网IP重复是很常见的情况,无法满足timestamp的单调增长,导致部分报文被丢弃。另外说明一下抓取报文未发现问题的可能原因,由于tcpdump命令是通过内核抓取报文的,而内核可能先一步将不符合机制的报文丢弃了,导致最终的抓包结果是正常的。如果想要抓取被丢弃的报文的话,可能需要到网关进行抓包。3.解决方案
1. 使用vi /etc/sysctl.conf修改内核参数文件,将内核参数进行修改,修改net.ipv4.tcp_tw_recycle = 0,修改net.ipv4.tcp_timestamps = 0,若缺失参数则自行追加。
2. 使用sysctl -p重新加载内核参数。
3. 使用sysctl -w net.ipv4.route.flush=1命令,会刷新路由缓存,此时参数即可立即生效。
4. 使用cat /proc/sys/net/ipv4/tcp_tw_recycle和cat /proc/sys/net/ipv4/tcp_timestamps这两个命令执行后,均输出0则已全部关闭,此时已修复完成。