4

腾讯云和阿里云tcp三次握手的区别

 2 years ago
source link: https://blog.51cto.com/u_15543206/5094078
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

腾讯云和阿里云tcp三次握手的区别

原创

wx62296eeeca632 2022-03-11 09:55:56 博主文章分类:网络 ©著作权

文章标签 腾讯云 tcp 文章分类 通信技术 网络/安全 阅读数452

近日同事遇到一个诡异的问题,帮忙进行了排查,好家伙不查不知道,一查让我知道了,腾讯云和阿里云TCP三次握手居然还有差异,没有想到云厂商这种Iass级别的服务,还有不同的标准~

  • 客户是半托管客户,我们部署服务请求阿里云的nginx,nginx作为LB,反向代理了N个java服务,Java服务入库.请求链路如下:
    客户物理机Java->阿里云 nginx->阿里云Java
  • 从客户物理机请求阿里云的nginx的时候,出现了包太大,读取超时,包小,则无问题。从 物理机到-腾讯云的nginx->Java服务 包大和包小都没有问题。

半托管Java错误日志如下:
腾讯云和阿里云tcp三次握手的区别_腾讯云

nginx日志出现408

  • 阿里云nginx也有其他客户在用,没有出现408错误,就这个客户出现
  • 根据日志,复原请求内容,在物理机上直接curl 阿里云的机器也是同样的问题,同样的请求,curl腾讯云的服务器没有问题,同样请求不在客户的物理机,在本地请求阿里云的机器没有问题。
  • 据运维说,这台物理机坏过,客户那去维修后,重新部署就出现这个问题,维修前没有这个问题
  • 物理机直接把请求送给阿里云的Java服务,也是同样的问题 物理机–》阿里云Java服务
  • 询问客户,维修后就装了个centos系统,配置了网络,其他什么都没有动
  • 询问运维,只部署服务,配置和以前一样

nginx 408

通常产生408错误有两个地方的配置会导致:client_body_timeout和client_header_timeout。

这两个超时时间默认都是60s。

client_body_timeout:定义读取客户端请求正文的超时。超时是指相邻两次读操作之间的最大时间间隔,而不是整个请求正文完成传输的最大时间。 如果客户端在这段时间内没有传输任何数据,nginx将返回408 (Request Time-out)错误到客户端。

client_header_timeout:定义读取客户端请求头部的超时。如果客户端在这段时间内没有传送完整的头部到nginx, nginx将返回错误408 (Request Time-out)到客户端。

网上都说是要配置这2个参数,但是我们同样的请求内容,在腾讯云的nginx上是没有问题的,腾讯云nginx和阿里云的nginx版本和配置是完全能一致的。所以不会是nginx参数配置的问题,而且直接送阿里云的Java服务,也是读取超时,所以基本上可以排除是nginx的问题

我们可以看到408都是读取超时,那么请求到底送没送到nginx,这个才是关键点。

遇事不决,我们抓个包看看

  • 本次抓包 物理机–》阿里云nginx

物理机抓包

tcpdump -i em1 host ali-nginx-ip -w btg.pcap

ali-nginx抓包

tcpdump -i eh1 host btg.ip -w ali-nginx.pcap

使用wireshark分析抓包文件

腾讯云和阿里云tcp三次握手的区别_腾讯云_02

从图中可以看出三次握手是成功了的,在发送http报文的时候,出现了以下错误。

  • TCP dup ack XXX#X是nginx给物理机返回的,就是重复应答#前的表示报文到哪个序号丢失,#后面的是表示第几次丢失

  • TCP Out_of_Order的原因分析:
    一般来说是网络拥塞,导致顺序包抵达时间不同,延时太长,或者包丢失,需要重新组合数据单元,因为他们可能是由不同的路径到达你的电脑上面。

  • TCP Retransmission原因分析:
    很明显是上面的超时引发的数据重传

  • nginx上的抓包内容如下

腾讯云和阿里云tcp三次握手的区别_tcp_03

nginx上抓包就更简单了,上面物理机发送的http报文,在nginx上居然没有捕获到,难道是偶然的?然后又重新试了几次,在nginx上都没有捕获到。到这里,就能确定了,物理机到阿里云的网络链路有问题,出现丢包了。

检查网络链路

  • 长ping阿里云的nginx
ping aliyun-nginx-ip

没有发现丢包,网络很稳定

联想到只有包特别大才会出问题,所以在ping上加了参数

ping -s 4000 aliyun-nginx-ip

发现到了4000的时候,ping就丢包了,推测是数据太大,客户那边做了白名单限制,联系客户的网工,进行加白后,测试ping是正常了。

这样就以为搞定了?那就错了。客户加白后,ping是没有问题了,但是http请求一样,上面的问题还是一样,加不加白,对这个问题没有什么影响。

重新理下思路,只有这个客户出现问题,那这个客户本身网络问题,嫌疑比较大。询问客户网工,网络架构是怎么搭建的,结果一问三不知。

只有大包才会出现问题,那么很可能和分包有关系,马上查看客户网卡信息,发现MTU的值是1500,没有改过,而且是生产环境,总不能直接改MTU的值吧,但是另外一个线索引起了注意。

腾讯云和阿里云tcp三次握手的区别_tcp_04
监控下网卡信息

watch netstat --interfaces

是的,没有看错,dropped数据一直在增加。

RX==receive,接收,从开启到现在接收封包的情况,是下行流量。

TX==Transmit,发送,从开启到现在发送封包的情况,是上行流量。

讲道理,我们的问题也应该是TX,但是他RX一直在丢包。

查看网卡的ring buffer

ethtool -g em1
Ring parameters for em1:
Pre-set maximums:
RX:             2040
RX Mini:        0
RX Jumbo:       8160
TX:             255
Current hardware settings:
RX:             2040
RX Mini:        0
RX Jumbo:       0
TX:             255

已经设置最大了,所以不是ring buffer的问题。

我们通过 linux源码可以知道,Linux支持的协议都在这里定义了,如果协议不被linux支持,会直接drop,导致上面网卡的drop数一直在增加。

通过上面可以linux源代码可以看到,我们的tcp/ip肯定是受支持的,所以drop这个和我们这个问题没什么关系。

但是我还是很好奇,是什么协议导致了Linux内核不支持,我们可以通过以下方式判断。

tcpdump -i em1 -e | grep -v -E 'ARP|IP|802.1Q|802.1ADP'

打印出包的ether type,然后过滤掉操作系统支持的包,剩下的就是丢掉的包

listening on em1, link-type EN10MB (Ethernet), capture size 262144 bytes
17:31:55.517403 0c:38:3e:3f:aa:cf (oui Unknown) > 01:80:c2:00:00:0e (oui Unknown), ethertype LLDP (0x88cc), length 207: LLDP, length 193: X3SG
17:31:58.242948 0c:38:3e:3f:b1:31 (oui Unknown) > 01:80:c2:00:00:0e (oui Unknown), ethertype LLDP (0x88cc), length 207: LLDP, length 193: X3SG
17:31:58.318690 0c:38:3e:3f:b1:2f (oui Unknown) > 01:80:c2:00:00:0e (oui Unknown), ethertype LLDP (0x88cc), length 207: LLDP, length 193: X3SG
^C141 packets captured399 packets received by filter

我们在linux代码搜以下LLDP协议,发现并没有。
 ethertypes发现他的定义是数据链路层协议。所以结果很明显了。

网卡丢包问题和我们前文提到的问题无关。

修改MTU

到这里,我们的怀疑点就只有MTU了,通过ping设置不允许分包来手工探测MTU值
物理机上

ping -s 1472 -M do aliyun-nginx-ip

1500-8(icmp头部)-20(ip头)=1472
ping不通,自己电脑上在来试试,是ok 的,那么结论很明显了,就是客户机器上中间链路上有小于1500的mtu设备。

继续减少字节数,临界点在1465是可以通的,超过1465就不行
那么最佳的mtu的值,等于=1465+8+20=1493

接下来就是改设备的MTU值进行测试了

ifconfig em1 mtu 1493

ps:这么修改mtu值,只要重启机器,就会失效,要研究修改mtu的值

vim  /etc/sysconfig/network-scripts/ifcfg-em1

增加如下内容

MTU="1493"
service network restart

改完进行curl测试,发现请求阿里云的nginx是没有问题了。

到这里问题就已经解决了,但是有个疑问为什么没有改mtu值前,腾讯的可以,阿里的不行?

腾讯和阿里 tcp三次握手的区别

带着疑问,在腾讯的云主机和物理机上抓了个包,来和阿里云的进行对比。
以下抓包文件,是以MTU为1500的为例

腾讯云和阿里云tcp三次握手的区别_腾讯云_05
发往腾讯云的SYN包当中,MSS值为1460=(1500-20(tcp头部字节)-20(ip头部字节))1460其实是一个默认的规范
而腾讯回的SYN,ACK包当中,MSS值为1424,比常规的1460,少16个字节,当然这16个字节是减了个啥,我也不知道。

回到上面,我们说中间链路有设备MTU的值不是1500,最大的为1493.
1493-20-20=1453,1453才应该是物理机的MSS值,而常规的1460比1453大,会导致丢包,而按照1424发包,则是没有问题的。

所有的一切都能解释的通了。

腾讯云的机器MTU值不是默认的1500吗?

不,他就是默认的1500,那1424的逻辑肯定不是我们腾讯机器加的,为了确认这个猜想,我们在腾讯云上进行了抓包,由于机器是NAT机器,腾讯云并没有绑定公网ip,我们抓的包为nginx代理阿里的java服务的三次握手

腾讯云和阿里云tcp三次握手的区别_腾讯云_06
可以看到,nginx去和java建立连接的时候使用的是1460,也就是说,1424这个逻辑在进入机器网卡前发生的。
而阿里的java服务,回的是1460,说明在出去的时候,腾讯也把mss改为1424了。

到这里,基本上解决了我们的所有疑问。

我们在和客户的网共,沟通后发现1493是他们那边设置的,而他没有改过,以前就是用的这个。而我们的运维说也没改过。那就奇怪了~

沟通后,客户的网工设置mtu值为1560,说是最大的值,我其实想让他改1500的,但是不听我的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK