问题 :
- 什么是 MTU
- MTU 为什么是 1500 个字节
- ip 协议的分包
- 什么是 MSS
- tcp 协议的分段
概述
我们知道知道数据经过层层封装后最后通过数据链路层发往另外一个终端 , 那么当发往的数据的大小太大了,TCP/IP 就会通过分包(一个变多个),然后再传到链路层进行发送 .
我们先来看一下网络分层
什么是 MTU
MTU 最大传输单元(Maximum Transmission Unit,MTU) , 最大传输单元MTU(Maximum Transmission Unit,MTU),是指网络能够传输的最大数据包大小,以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。
如果MTU超过了接收端所能够承受的最大值,或者是超过了发送路径上途经的某台设备所能够承受的最大值,就会造成报文分片甚至丢弃,加重网络传输的负担。
如果太小,那实际传送的数据量就会过小,影响传输效率。在不同的协议中 MTU 的值是不同的 , 例如 :
如果IP层有一个数据报要传,而且数据帧的长度比链路层的MTU还大,那么IP层就需要进行分片( fragmentation),即把数据报分成干片,这样每一片就都小于MTU . 为了解释 MTU 的概念可以看下面的例子 ,
MTU 的值不是越大越好,更大的 MTU 意味着更低的额外开销,更小的 MTU 意味着更低的网络延迟。每一个物理设备都有自己的 MTU,两个主机之间的 MTU 依赖于底层的网络能力,它由整个链路上 MTU 最小的物理设备决定3,
如下图所示,网络路径的 MTU 由 MTU 最小的红色物理设备决定,即 1000:
图片来源 : https://draveness.me/whys-the-design-tcp-segment-ip-packet/
两台主机通信路径中的最小MTU,称为路径MTU( Path mtu,PMTU),也就是上面的这个 1000 个字节为该连接的 PMTU
你也看到了以太网MTU一般为 1500 个字节, 也就是说超过 1500 个字节的数据就会分包发送,那么我们反推一下 ,
下面两个章节来自 : https://info.support.huawei.com/info-finder/encyclopedia/zh/MTU.html 非原创
为什么以太网MTU通常被设置为1500?
RFC标准定义以太网的默认MTU值为1500。那么这1500的取值是怎么来的呢?
早期的以太网使用共享链路的工作方式,为了保证CSMA/CD(载波多路复用/冲突检测)机制,所以规定了以太帧长度最小为64字节,最大为1518字节。最小64字节是为了保证最极端的冲突能被检测到,64字节是能被检测到的最小值;最大不超过1518字节是为了防止过长的帧传输时间过长而占用共享链路太长时间导致其他业务阻塞。
所以规定以太网帧大小为64~1518字节,虽然技术不断发展,但协议一直没有更改。
以太网最大的数据帧是1518字节,这样刨去帧头14字节和帧尾CRC校验部分4字节,那么剩下承载上层IP报文的地方最大就只有1500字节,这个值就是以太网的默认MTU值。
这个MTU就是网络层协议非常关心的地方,因为网络层协议比如IP协议会根据这个值来决定是否把上层传下来的数据进行分片,如果单个IP报文长度大于MTU,则会在发送出接口前被分片,被切割为小于或等于MTU长度的IP包。
实际上,不同的厂商,甚至同一厂商的不同产品型号对MTU的定义也不尽相同,通常分为以下几种:
- MTU用以指示整个IP报文的最大长度(IP头+三层Payload),MTU是一个三层的定义,即MTU = IP MTU。例如在Huawei NetEngine系列路由、CloudEngine系列交换机上,MTU是三层的定义,指IP MTU。
- MTU的值等于IP报文与以太帧头的总和,即MTU = IP MTU + 14字节。例如在Cisco部分设备上,MTU是指IP MTU + 以太帧头。
- MTU的值等于IP报文与以太帧头、CRC部分的总和,即MTU = IP MTU + 18字节。例如在Juniper部分设备上,MTU是指IP MTU + 以太帧头 + CRC部分。
在实际设置MTU值时,需要特别关注各厂商、产品对于MTU的定义。
IP 分片
IP 报文格式
IP 分片过程
以太网缺省MTU=1500字节,这是以太网接口对IP层的约束,如果IP层有<=1500字节需要发送,只需要一个IP包就可以完成发送任务;如果IP层有>1500字节数据需要发送,需要分片才能完成发送。
以主机发送一个数据载荷长度为2000字节的报文为例说明其分片的过程(假设出接口的MTU值为1500)。在网络层会对报文进行封装,其结构组成:IP头部20字节+数据载荷长度2000字节,报文封装后,整个报文长度为2020字节。在出接口进行转发的时候,发现IP报文的长度超过了MTU的值1500,因此要进行分片处理,详情见下图。
第一片报文,IP报文头固定20字节,数据载荷可以封装1480字节(MTU值1500字节-IP报文头20字节,数据载荷长度须是8的倍数);
第二片报文,复制第一片的IP头,IP报文头固定20字节,数据载荷为剩余的520字节(总数据载荷长度2000字节减去第一片中已封装的1480字节)。如果最后一片报文的长度不足46字节,会自动填充至46字节。
所有分片报文在发送至目的主机后,在目的主机进行分片重组,恢复为原报文。在进行重组时,通过IP标志位中的MF用来分辨这是不是最后一个分片,片偏移用来分辨这个分片相对原数据报的位置。通过这几个字段,可以准确的完成数据报的重组操作。
PMTU
顾名思义,Path MTU就是指传输路径的MTU,无需分片就能穿过某路径的数据包最大长度。在从发送端到接收端的传输路径上,如果网元的MTU设置不一致,则决定该路径可用MTU的,其实是整条路径上的最小MTU值。以Path MTU作为IP包长发送数据,既高效又能避免分片。
看一个例子
例子来源 : https://zhuanlan.zhihu.com/p/139537936
MSS(Maximum Segment Size,最大报文长度),是TCP协议定义的一个选项,MSS选项用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度
一旦DF位置一,(DF位为1的话则不允许分片)将不允许中间设备对该报文进行分片,那么在遇到IP报文长度超过中间设备转发接口的MTU值时,该IP报文将会被中间设备丢弃。在丢弃之后,中间设备会向发送方发送ICMP差错报文(告诉发送者,你发送的数据大小超过了我的MTU , 需要发小点体积的数据).这个过程如下 :
通过抓包
我们可以看到其差错类型为3,代码为4,并且告知了下一跳的MTU值为1478。在ICMP差错报文里封装导致此差错的原始IP报文的报头(包含IP报头和四层报头)。
一旦出现这种因DF位置一而引起丢包,如果客户端无法正常处理的话,将会导致业务应用出现异常,外在表现为页面无法打开、页面打开不全、某些大文件无法传输等等,这将严重影响业务的正常运行。
那么客户端如何处理这种状况呢?
TCP主要通过两种方式来应对:
- 协商MSS,在交互之前避免分片的产生
- 路径MTU发现(PMTUD)
PMTUD
这里引用来自 : https://draveness.me/whys-the-design-tcp-segment-ip-packet/ 的例子 ,非原创
步骤一 : 向目的主机发送 IP 头中 DF 控制位为 1 的数据包,DF 是不分片(Don’t Fragment,DF)的缩写;路径上的网络设备根据数据包的大小和自己的 MTU 做出不同的决定:
(1) 如果数据包大于设备的 MTU,就会丢弃数据包并发回一个包含该设备 MTU 的 ICMP 消息;顺便带回去建议的MTU 大小
(2) 如果数据包小于设备的 MTU,就会继续向目的主机传递数据包;
步骤二 : 源主机收到 ICMP 消息后,会不断使用新的 MTU (根据带回来别人建议的 MTU 大小)发送 IP 数据包,直到 IP 数据包达到目的主机;
然后这里看一下我自己做的抓包实验 :
可以看到这里就是置为 不分片
的情况 .
总结
TCP/IP 的 PMTU 的发现机制尽可能地为了减少分片的可能 , 我们在优化的时候要将这个原则考虑进去 .
参考资料
- https://mp.weixin.qq.com/s/RP6w69I-q5ai9Bx_SzjUfQ
- https://draveness.me/whys-the-design-tcp-three-way-handshake/
- https://zhuanlan.zhihu.com/p/139537936
- https://info.support.huawei.com/info-finder/encyclopedia/zh/MTU.html
百万连接 :