问题现象
在某一台服务器无法访问另一台服务器的https服务,telnet检测端口发现端口无法连接:
[root@020113 ~]# telnet 192.168.5.27 443
Trying 192.168.5.27...
问题分析
第一步:网络检查
同网段其他主机访问服务端是正常的,因此网络问题可以排除
第二步:查看防火墙
步骤略,这里检查双方iptables规则均无问题
第三步:抓包分析
服务端抓包并将结果保存,因为443端口连接较多,有一些其他干扰,因此抓22端口:
root@005027 tcpdump host 192.168.20.113 and port 22 -w dump.pcap
客户端同时连接服务端的22端口:
[root@020113 ~]# telnet 192.168.5.27 22
dump.pcap文件拿到本地用wireshark打开分析:
抓包的结果可以看出,客户端(20.113)发起SYN请求后,即使多次重传,服务端也没有回复过带SYN, ACK标志位的响应,那么看来问题出现在服务端。这时隐隐有了一些猜测,很有可能是之前碰到过的一个问题导致的,在此前的文章也有写过:
Kubernetes踩坑(二): Service IP(LVS)间断性TCP连接故障排查
为了印证自己的猜测,检查一下状态:
root@005027:~# netstat -s | grep timestamp
2984 packets rejects in established connections because of timestamp
果然,提示有一些包因为时间戳问题丢弃了。
解决:
查看内核参数配置:
net.ipv4.tcp_tw_recycle = 1
果然是打开状态,将其改成0, sysctl -p使其生效后,问题解决。
深挖
为什么会出现这种情况呢?这里再次回顾一下linux内核时间戳相关的3个参数:
# 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1
# 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_tw_recycle = 1
# tcp缓存时间戳,RFC1323中描述了,系统缓存每个ip最新的时间戳,后续请求中该ip的tcp包中的时间戳如果小于缓存的时间戳(即非最新的数据包),即视为无效,相应的数据包会被丢弃,而且是无声的丢弃。在默认情况下,此机制不会有问题,但在nat模式时,不同的ip被转换成同一个ip再去请求真正的server端,在server端看来,源ip都是相同的,且此时包的时间戳顺序可能不一定保持递增,由此会出现丢包的现象,因此,如果是nat模式工作,建议关闭此选项。
net.ipv4.tcp_timestamps = 0
说明:
设计这几个参数是为什么呢?在tcp四次挥手完成之后,服务端会有一个TIME_WAIT的时间等待释放sock连接的端口,默认为2*MSL(60s),而端口资源是有限的,在繁忙的服务器了,等待这么长的时间是非常低效的,因此为了加速这个效率,linux内核设计了tcp_tw_reuse和tcp_tw_recycle这两个参数,这两个参数一般都是一起使用的,开启后允许time_wait状态(后面简写tw)的端口被回收并重用。但是,回收重用容易引发一个问题,就是可能导致回收的端口收到了来自之前的对端连接的数据,因此为了避免这个问题,又设计了另一个参数tcp_timestamps,在上面的注释中也说明了,非最大时间戳的包会丢弃。
因此,郑重建议: 这3个参数建议不要同时开启,要么干脆不开启回收重用,要开启的话,建议不要开始时间戳标记。