问题还原
公司有业务在苹果设备为客户端的设备上访问时,偶尔会出现访问超时的情况,刚开始概率还少以为是本地网络问题,随之出现概率越来越多,问题就变的越发严重了
开始使用iPhone 12以下4G网络(iPhone 12以上的设备才有5G)测试复现了这个问题,偶尔性超时,但是使用5G网络又没有这种情况出现,开始判断是设备问题,因为这个问题只出现在了苹果设备上
使用iPhone12及以上wifi测试又复现了这个问题,1推测的设备问题没有得到验证
由于我们没有更多的iPhone设备去测试.所以无法验证问题.所以怀疑是dns的问题,然后在客户端设备上抓包确实有发现是dns没有解析成正常ip的情况,选择换运营商(移动+电信+联通)再试,还是有超时情况出现,这种就不太可能是dns的问题,又怀疑是云厂商的问题,由于没有能拿出更多证据,云厂商无法配合查询
最终也无法定位到问题
终极大招:
由于一直无法定位问题,找到cp公司把相关人员全部拉进一个群: (客户端+网络+安全+系统)的同学,由于他们有更多的iPhone设备,最终发现mac+ios等等所有和iPhone相关的设置都出现超时情况,而且我们处在不同的地区,自然排除了dns的问题,那最后只能通过客户端与服务器进行同时抓包了
# 服务器端抓包
# 指定客户端ip抓包
tcpdump host xxx -nnnn -v -w /tmp/server_xxx.pcap
# 指定接口抓包
tcpdump -i eth0 host xxx -nnnn -v -w /tmp/server_xxx.pcap
服务端抓包结果:
pcap.png
客户端需要使用抓包工具,这里就不演示了
破案: 当发生超时时,服务端没有进行tcp三次握手建立连接,服务端没回syn-ack
赶紧查看服务器内核配置
[........]# cat /etc/sysctl.conf |grep net.ipv4.tcp_tw
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
这里解释一下这两个参数什么意思:
net.ipv4.tcp_tw_reuse = 0 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 0 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_timestamps = 1 #默认值为1,连接报的时间戳
这两个参数是用于服务器内核优化高并发,高复用的一个调优方法,但是问题也就出现在这里
当服务器内核参数: net.ipv4.tcp_tw_recycle 和net.ipv4.tcp_timestamps 的值都为1,表示服务端会检查每一个TCP连接报文中的时间戳,当时间戳(timestamps)不是递增关系则不会响应这个报文
什么意思呢,简单点来说就是: 因为net.ipv4.tcp_timestamps=1 标记了时间戳,如果有一个用户的时间戳大于这个链接发出的syn中的时间戳,服务器上就会忽略掉这个syn,不返会syn-ack消息,表现为用户无法正常完成tcp3次握手,从而不能打开web页面
那问题找到了,接下来就是如何去修改了,在我们需要保证服务器一定的高并发的情况下那我们只修改: net.ipv4.tcp_tw_recycle就可以了
[......]# vim /etc/sysctl.conf
net.ipv4.tcp_tw_recycle = 0
# net.ipv4.tcp_tw_recycle为0(关闭状态时)net.ipv4.tcp_timestamps是不生效的,这样就统一修改一下
net.ipv4.tcp_timestamps = 0
# 配置立即生效
[......]# sysctl -p
到此问题解决,在这里反思一下自己几个问题
一开始出问题的时候被局限了思维,一直认定是设备问题,直到问题解决才发现这个内核参数和设备没有关系,那么这里解释一下之前为什么只有iPhone设备才出问题,因为这个tcp_timestamps是一个双向的选项,当一方不开启时,两方都将停用timestamps,所以猜测大概率是安卓等其他设备没有开启这个timestamps所以服务器端也不存在这个检查,也就不存在这个syn-ack不响应问题了
知识存淀太少了,这个问题一开始就应该想到抓包分析,也不是一味的靠猜测
在内核调优时不应该一味在追求高并发,或者是看标准的调优方案而是要结合实际情况,