【tcp】MTU设置不合理,导致的链路不通问题的排查处理

一、现象

现象1

Server A 调用本机的接口能正常返回,调用Server B的接口总是超时。被调用接口是能正常执行的,而且有执行日志记录。
Server C 调用Server B的接口也能正常返回。

分析

根据以上,基本可以排除是Server B接口服务的问题导致超时,很有可能 Server A 与 Server B之间的网络有问题,于是决定通过抓包分析。

Server A 调用 Server B接口时,抓包情况如下:

image.png

可见,在调用Server B的接口时,重试很严重。见上图的黑色行。当 MTU 值或者 MSS 值设置不合适时,会导致这样的问题出现。

首先查看当前 MTU 的值是多少。

Linux 下查看方式如下:

image.png

再看这个 MTU 值设置多少合适。使用 ping 命令检测。

image.png

-s 参数说明包的大小,后面的 IP 可以设置为 任何一个可以 ping 通的 IP。

当返回值如下时,表示包的大小设置的过大,可以调小:

image.png

当出现如下的结果时,说明包大小设置的正常了。

image.png

解决

经过上面的 ping 测试,我们可以知道 原先的 MTU 值为 9001,设置的过大,应该改成 2000。

有多种修改的方式,下面就介绍一种。

image.png

设置完成后,再次抓包,情况如下:

image.png

拓展

MTU && MSS

MTU: Maxitum Transmission Unit 最大传输单元
MSS: TCP数据包每次能够传输的最大数据分段

为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时 候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。
通讯双方会根据双方 提供的MSS值得最小值确定为这次连接的最大MSS值。

现象2

在学校搭建好VPN服务,回到家却发现连上就上不了网!

在学校时科学上网没问题,回到家连接上了就上不了网。

用基本的测试方法ipconfig /all 看到有以太网网卡有ip,dns也正常,然后看看VPN连接状态,有ip,DNS8.8.8.8 ,突然发现没有网关。

然后尝试改网关,用route print 看看路由表的信息,然后用route change ip mask 掩码 网关。改好了,然后重启一下VPN 发现还是空,行不通。

上网查了下,需要取消√的VPN的”在远程网络上使用默认网关”。然后竟然成功了,在连接VPN的情况下可以上网了。

image.png

不过还是不能科学上网,后来咨询了大神,他告诉我PPP(点对点)不需要网关。

在服务器上执行如下命令。就可以科学上网了!

#  iptables -I FORWARD -p tcp --syn -s 10.82.88.0/24 -j TCPMSS --set-mss 1256

从家里出发有个路由器MTU不是1500,封装的数据包还是封装成1500,但是路径上有MTU小于1500的,数据包有不分包标记,然后那个数据包就被丢弃了,丢弃了 当然也就上不了网。

上面的命令就是改MSS为1256,加上包头,就等于间接把MTU改小成1256+包头,小于某路由的MTU,包就不会丢弃,然后就能顺利传输。

现象3

装完虚拟机( win )之后发现无法打开部分网站,以百度为例 www.baidu.com可以看到 302 消息,跳转后https://www.baidu.com就超时了,而另外一部分网站是正常的。

使用curl -v可以看到在收到服务器发来的 hello 后卡住不响应。

wireshark 抓包发现百度回复了几个包,其中有一条警告是Ignored Unknown Record ,猜测是包被拆分后出现了点问题所以不认识,搜索这个警告信息确实有类似的案例 HTTPS Websites Not Reachable

修改 MTU 后问题解决,同样的,在其他某些虚拟机上如果有不合适的 MTU 也会打不开百度。

MTU 不是只会影响性能速度吗,怎么这都影响到功能了?

MTU 不合适会直接丢掉包,不只是影响速度。
不过我见过的一般是丢掉第一个包,收到一条 ICMP 消息后重新协商。
你给的链接似乎是用了他家的产品才会有这样的问题。

家用所有设备设置 1480 保持 MTU 对齐就行了,1492 没必要提升不了什么网速,其实更希望运营商把局端和光猫之间的 MTU 改为 1528,这样直接 MTU1500+8pppoe 头,最标准的 MTU 了。

我碰到过因为 MTU 问题导致 https 地址不能访问的问题。
大致的问题是中间链路上某个设备不支持这么大的 MTU 的时候,会给源地址发一个 icmp 协议的包,让源拆成小包之后再发,但是很多设备对这个 icmp 的报文支持的并不友好,从抓包上看到一直重传,超过次数之后就放弃了。

MTU协商失败会导致 SSL 协商故障。

如果是 ipv6 的话可能会出现这个问题,因为 ipv6 在超出 mtu 以后不会像 ipv4 一样拆包重传,而是回一个 toobig 给发送方。
如果发送方(网站)配置不合理(特别是负载均衡配置不合理)不能正确转发/处理 toobig,同时你的运营商没有做 mssfix,就可能出现这个问题。

现象4

工作中遇到一件怪事,在服务端服务器上搭建好服务后(VPN服务,创建了虚拟网卡),服务器和客户端之间响应正常且很稳定。客户端也能正常通过服务器访问外网,但是访问个别网站时可以打开文字,但是部分图片打不开(也不是所有图片打不开)。

根据以上现象,基本排除了虚拟借口或者物理接口有问题,怀疑客户端和服务器之间的网络问题,或者服务器的物理网卡上的数据没有全部给虚拟网卡。所以在服务器的物理网卡和虚拟网卡上同时抓包,客户端的网卡上也抓包,看报文到底丢在哪里了

有三种丢包的可能:

1、客户端的加载图片的HTTP请求没有送到服务器,可能性较小,因为有些图片是可以打开的。

2、图片数据经过服务器的物理网卡eth0后没有正确传给虚拟网卡

3、服务器虚拟网卡在转发图片时丢包

分析

MTU是数据链路层的概念,表示接口的最大传输单元,一般情况下指的是接口所能传输IP报文的最大长度。

默认以太网接口MTU为1500,那么传输长度为1490大小的IP报文完全没有问题。

VPN隧道携带了一层层封装,比如IPsec报文。

这样就会导致封装过后的新IP报文长度可能会大于接口的MTU值, IPsec为了确保传输报文不大于物理接口的MTU值,所以规定了隧道自己的MTU值,即Path MTU,即要求被封装的报文长度不能大于这个值,否则将被分片处理。

Path MTU在ipsec sa中可以看到,这个值不是固定的,因为每个隧道使用的模式和算法不同。

很多业务类型是基于TCP的,TCP的IP报文header通常明确指定了本报文不能给分片(Don’t fragment)。
这样的话,就必须使得载荷为TCP业务的IP报文长度必须小于Path MTU,否则将被IPsec隧道丢弃,MTU check failure会一直增长。

IP报文不可以被分片,但是TCP 报文可以。
TCP三次握手的时候,头部会有协商MSS(Maximum segment size)的选项,在一长串网络设备中,以设置最小的MSS来传输TCP报文。
所以我们需要将TCP MSS调小以保证TCP报文长度变小,这样IP报文长度也会变小,经过IPsec隧道时就不会被隧道MTU限制。

TCP MSS设置为多少合适呢?
由于TCP业务报文的IP头和TCP头长度都是20字节,那么IP场景下 :
TCP MSS = Path MTU – IP Header – TCP Header = Path MTU – 40.
比如Path = 1428,那么在内外网口下设置TCP MSS为1388就可以,小一点也没关系,但是不能太小,否则TCP报文重组也会消耗一定性能。

综上,不能调整接口MTU,要调整只能调整TCP MSS。

二、设置MSS调整MTU

在实际环境中,往往出现在某个链路上MTU不规范,比正常的MTU(1500)要小。
从理论上讲,出现这种情况后,应由路由器发送ICMP告知发送端调整MTU,但是由于网络比较复杂,该告知无法到达发送者。

如下图所示,中间路由器的通路的MTU为1496。这导致网络两侧设备通讯时,小包可以通过,但是大包无法通过。

现象就是可以ping通,但是无法下载数据或者打开页面。

image.png

防火墙可以调整TCP通讯的MSS值,使得链路两端的设备通讯时不发送MTU为1500的数据包,从而避免丢包事件。

MTU: Maxitum Transmission Unit 最大传输单元
MSS: Maxitum Segment Size 最大分段大小

由于以太网EthernetII 最大的数据帧是1518Bytes这样,刨去以太网帧的帧头(DMAC目的地址MAC48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes(这个部分有时候大家也把它叫做FCS),那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes. 这个值我们就把它称之为MTU。

MSS就是TCP数据包每次能够传输的最大数据分段。
为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。

通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。也就是说,在上图的案例中MTU值为1496,那么我们可以通过调整MSS为1496-40=1456, 来达到调整发包大小满足MTU的要求。

当然如果不清楚中间链路的具体MTU,可以再往小处调整。该方法的缺点是需要调整所有的策略。

三、 关于 TCP segment of a reassembled PDU

windows下wireshark抓包经常会出现"TCP segment of a reassembled PDU"提示:

image.png

可通过wireshark的 Edit --> Preferences --> Protocols/TCP --> Allow subdissector to reassemble TCP streams 取消勾选该选项可消除提示:

image.png

网上大部分转载文章都在争论显示TCP segment of a reassembled PDU的ACK序号是一样的,所以显示提示,其实与ACK没啥关系。

问题的关键在于报文长度2194字节,已超出MTU的1500大小,所以提示TCP segment。

MTU Max Transmit Unit,1500,可通过ifconfig查看

MSS Max Segment Size,1460=1500-20-20

PDU Protocol Data Unit

NIC传输的最大报文长度为1514字节=MTU+Ether=1500+14

那问题来了,2194字节报文为什么是正常的,为何没有经过IP分片?

因为现代OS支持网络分载(TSO)功能,由NIC代替CPU实现packet的分段和合并,节省系统资源,让系统处理更多的连接。

TSO TCP Segment Offload

LSO Large Segment Offload

GSO Generic Segment Offload

LRO Large Receive Offload

RSC Receive Segment Coalescing

发送过程:

Many operating systems and NIC drivers support TCP Segmentation Offload (TSO) aka Large Segment Offload (LSO) aka Generic Segment Offload (GSO). What this means is that the TCP stack sends a chunk of data for the NIC to break up into Maximum Segment Size (MSS) pieces to send on the network. TCP might hand the NIC 16k of data and the NIC will break it into MSS sized bites: 11 segments of 1460 bytes and one segment of the remaining 324 bytes. This offloads the task to the NIC and saves overhead on the host’s resources. It’s a performance thing.

当TCP协议栈发送大块数据时,由NIC来进行分段。由于适配器硬件完成数据分段的速度比操作系统软件快得多,此功能可能会提高传输性能。此外,适配器使用的 CPU 资源较少。

接收过程:

Large Receive Offload (LRO) or Receive Segment Coalescing (RSC). The is the same thing but in reverse. The NIC coalesces TCP segments it receives from a remote host into larger packets before sending them up to the TCP stack.

过程与发送相反,NIC会将接收到的数据合并成大的数据包,然后发送至TCP/IP协议栈。

如图wireshark工作在NIC和协议栈之间,抓取的是网卡上的数据,此时数据包长度可能大于MTU。

image.png

四、 合理设置操作系统网卡的MTU值

当MTU不合理时会造成如下问题:

1.本地MTU值大于网络MTU值时,本地传输的”数据包”过大导致网络会拆包后传输,不但产生额外的数据包,而且消耗了“拆包、组包”的时间。

2.本地MTU值小于网络MTU值时,本地传输的数据包可以直接传输,但是未能完全利用网络给予的数据包传输尺寸的上限值,传输能力未完全发挥。

什么是合理的MTU值?

让本地MTU值与网络的MTU值一致,以致于不会出现数据包的大小超过网络传输的MTU值,而不得不进行拆包,然后组包,再进行转发,所谓合理的设置MTU值,就是让本地的MTU值与网络的MTU值一致,既能完整发挥传输性能,又不让数据包拆分。

怎么探测合理的MTU?

Linux下探测MTU值

ping -s 1460  -M  do baidu.com 

windows下探测MTU值

ping -f -l 1460 baidu.com

发送大小包大小是1460(+28)字节,禁止路由器拆分数据包。

回复结果

1.如果正常回复,说明网络允许最大MTU就是1500字节,与系统默认相同,只需将自己的路由的MTU也设置为1500即可。

2.如果没正常回复,说明数据包大小超过了网络限定的MTU大小。需要减小探测包大小再次尝试。

如何修改MTU值?

Linux临时修改 ifconfig eth0 mtu 1488 up

为什么mtu值是探测出来的值加上28?

因为ping使用icmp协议,你指定的探测值是数据包数据净荷的长度,还需要加上20字节的ip头部,和8字节的icmp封装。

MTU设置不正确可能会造成什么问题(平时都是默认1500)?

第一:使用pptp后,未将服务器上mtu改小,可能造成带宽跑不上去
第二:使用GRE后,未将服务器上mtu改小,可能造成部分网站无法打开,如百度,hao123等

五、 参考

为什么 TCP/IP 协议会拆分数据?
https://draveness.me/whys-the-design-tcp-segment-ip-packet/

TCP segment of a reassembled PDU
https://www.pudn.com/news/628f83ebbf399b7f351ec3ef.html

一次由于MTU设置不当导致的网络访问超时
https://weibo.com/ttarticle/p/show?id=2309404140904511340923

设置MSS调整MTU
http://www.easynetworks.com.cn/forum/topic/detail/id/19

防火墙外网口如何改MTU和TCP MSS值
https://zhiliao.h3c.com/Theme/details/152025

合理设置操作系统网卡的MTU值
https://tsov.net/uupee/56976

pppoe环境下的mtu和mss的配合问题
http://t.zoukankan.com/chenxiaomeng-p-12739395.html

HTTPS Websites not reachable - "Ignored Unknown Record" in WireShark
https://www.sonicwall.com/support/knowledge-base/https-websites-not-reachable-ignored-unknown-record-in-wireshark/170505539088634

How can I determine the MTU size of WAN interfaces to optimize throughput?
https://www.sonicwall.com/support/knowledge-base/how-can-i-determine-the-mtu-size-of-wan-interfaces-to-optimize-throughput/170504812146650

防止MTU设置不合理导致的链路不通问题
https://www.itdaan.com/blog/2014/06/30/8662574b43227368b681cd618506b2bd.html

ROS修改MTU和MSS解决上网慢和页面显示不全问题
https://mp.weixin.qq.com/s/gbWiWYjXj45Iie3P8sEgBw

你可能感兴趣的:(【tcp】MTU设置不合理,导致的链路不通问题的排查处理)