问题描述
正常情况下,TCP 传输的报文应该不会超过 MTU 的大小,一般是1500 bytes,但我们通过 tcpdump 抓包出来后,通过 wireshark 查看的话,有些 Len 远远大于了 MTU 值(这里说的不严谨,应该说是每个数据包的Len 不应该大于 MSS),这是为什么呢?难道说,我们的MTU 不是1500,还是?去服务器上面查看下 MTU值
[root@vm-os-centos7 ~]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 8844038 0 0 0 156604 0 0 0 BMRU
lo 65536 626 0 0 0 626 0 0 0 LRU
[root@vm-os-centos7 ~]#复制
发现MTU确实是1500个字节,按理说,抓包工作不会出现大于1500的Len,才符合 TCP 协议规范。如下图,是 Len 远远大于 MSS 的抓包截图。
(图:Len 远远大小 MSS)
原因分析
这是由于服务器网卡开启了 TCP Segment Offload, TSO 选项导致,在支持 TSO 的网卡上,为了降低 CPU 的负载,提高网络的出口带宽,TSO 提供一些较大的缓冲区来缓存 TCP 发送的包,然后由网卡负责把缓存的大包拆分成多个小于 MTU/MSS 的包,简单来说就是,原本由内核处理的拆包,交给了网卡来处理,而我们通过 tcpdump 抓包工具抓取的是从内核到网卡路径上的数据包,所以会存在上述问题,如果在交换机处抓包,那么对应的大小为MSS值或小于 MSS 值。那么什么是 TSO 呢?
Segmentation offloading 技术
说到 TSO 那么就不得不讲下 Segmentation offloading 技术?随着网络带宽的提升,以太网从最开始的 10M 到现在 100G,提升了10000倍,虽然 CPU 这些年,也有很大的发展,但是单核 CPU 的频率并没有太多的提升,有人会说 CPU 核心数增加了很多,但是把一个网络数据流交给多个 CPU 核心去处理本身有一定的挑战,另一方面计算机需要处理的任务也越来越复杂,尤其是引入了虚拟化之后,计算机上不仅跑应用程序,还需要跑容器、虚拟机、CPU 本身的负荷可以就已经很重。由于 TCP 是双向通信的,大约发送或者接收 1 bit/s 的数据需要 1 赫兹的 CPU 处理能力,当发送和接收各 10 Gbit/s (吞吐量就是 20Gbit/s=20GHz)时,大概需要 8 个 2.5 GHz 的 CPU 内核,如果完全由 CPU 来校验、计算、验证、分包、和组包的话,消耗 CPU 还是相当可观的,为了解决问题,越来越多的技术出现来适应技术的变迁,其中网卡就能够支持将某些 Linux 内核协议栈所承担的计算任务,从协议栈 offload (卸载)到物理网卡。
MSS(Maxium Segment Size):MSS 是 TCP 数据段每次能够传输的最大数据分段的长度。为了达到最佳的传输效能,TCP 协议在建立连接的时候通常要协商双方的 MSS 值,这个值 TCP 协议在实现的时候往往用 MTU 值代替( MSS = MTU - IP 数据包包头大小20Bytes - TCP 数据段的包头大小20Bytes),所以在默认以太网 MTU 为 1500 bytes 时,MSS为 1460。
TCP 分段:当应用程序发给 TCP 的 message 的长度超过 MSS 时,TCP 会对它按照 MSS 的大小将其分为多个小的 packet,并且在每个 packet 上添加 TCP Header 成为一个 TCP 段(segement)。
TSO 是一种利用网卡分割大数据包,减小 CPU 负荷的一种技术,也被叫做 LSO (Large segment offload) ,如果数据包的类型只能是 TCP,则被称之为 TSO,如果硬件支持 TSO 功能的话,也需要同时支持硬件的 TCP 校验计算和分散 - 聚集 (Scatter Gather) 功能。
TSO 就是将由 TCP 协议栈所做的 TCP 分段交给具有这种能力的物理网卡去做,因此网卡具有如下特性:
1. 物理网卡支持;
2. Linux 网卡驱动支持(ethtool -K ethX tso on 命令打开网卡和驱动对 TSO 的支持);
3. 需要 Net:TCP checksum offloading and Net:Scatter Gather 支持。
TSO 就是将 TCP Segmentation 的工作,卸载(offload)到网卡来完成。有了TSO,操作系统只需要传给硬件网卡一个大的 TCP 数据(当然是包在 Ethernet Header和IP Header内,且不超过64K )。网卡会代替 TCP/IP 协议栈完成 TCP Segmentation。这样,就消除了 TCP Segmentation 带来的 CPU 负担。支持TSO的网卡,仍然会按照TCP/IP协议将网络数据包生成好并发送出去,对于外界系统来说,感受不到TSO的存在,下图是使用 TSO 和不使用 TSO 的情形的对比。
(图:使用TSO与不使用TSO对比图 来源网络)
从上图可以看到 TSO 带来的提升是明显的,一方面,更多的 CPU 被释放出来完成别的工作,另一方面,网络吞吐量(throughput)不受 CPU 负荷的影响,如果没有 TSO,当 CPU 性能不好或者 CPU 本身负荷已经较大时,CPU 将来不及处理足够的网络数据,会导致网络吞吐量下降,延时上升。
其中大部分的优化是将本来由内核做的操作,交给了网卡,例如 TSO、UFO 和 GSO 是对应网络发送,在接收方向上对应的是 LRO、GRO ,具体含义的话还是自己看吧。
offload | 传输段还是接收段 | 针对的协议 | Offloading的位置 | 网卡/linux内核支持情况 | 备注 |
TSO(tcp-segmentation-offload) | 传输段 | TCP | NIC | Linux 内核从 2.5.33 引入 (2002)网卡普遍支持 | TSO,是一种利用网卡对TCP数据包分片,减轻CPU负荷的一种技术,有时也被叫做 LSO (Large segment offload) ,TSO是针对TCP的,UFO是针对UDP的。如果硬件支持 TSO功能,同时也需要硬件支持的TCP校验计算和分散/聚集 (Scatter Gather) 功能。命令:ethtool -K eth0 tso on|off 在不支持TSO的网卡上,TCP层向IP层发送数据会考虑mss,使得TCP向下发送的数据可以包含在一个IP分组中而不会造成分片, mss是在TCP初始建立连接时由网卡MTU确定并和对端协商的,所以在一个MTU=1500的网卡上,TCP向下发送的数据不会大于min(mss_local, mss_remote)-ip头-tcp头。 网卡支持TSO时,TCP层会逐渐增大mss(总是整数倍数增加),当TCP层向下发送大块数据时,仅仅计算TCP头,网卡接到到了IP层传下的大数据包后自己重新分成若干个IP数据包,添加IP头,复制TCP头并且重新计算校验和等相关数据,这样就把一部分CPU相关的处理工作转移到由网卡来处理。 |
UFO(udp-fragmentation-offload) | 传输段 | UDP | NIC | linux 2.6.15 引入 (2006)网卡普遍不支持 | UFO,是网卡对udp提供的类似TSO的技术。 命令:ethtool -K eth0 ufo on | off |
GSO(generic-segmentation-offload) | 传输段 | TCP/UDP | NIC或者 离开IP 协议栈进入网卡驱动之前 | GSO/TCP: Linux 2.6.18 中引入(2006) GSO/UDP: linux 3.16 (2014) | GSO,它比TSO更通用,基本思想就是尽可能的推迟数据分片直至发送到网卡驱动之前,此时会检查网卡是否支持分片功能(如TSO、UFO), 如果支持直接发送到网卡,如果不支持就进行分片后再发往网卡。这样大数据包只需走一次协议栈,而不是被分割成几个数据包分别走,这就提高了效率。命令:ethtool -K eth0 gso on | off |
LRO(large-receive-offload) | 接收段 | TCP | NIC | Linux 内核 2.6.24 引入(2008)网卡普遍支持 | LRO,通过将接收到的多个TCP数据聚合成一个大的数据包,然后传递给网络协议栈处理,以减少上层协议栈处理 开销,提高系统接收TCP数据包的能力。 |
GRO(generic-receive-offload) | 接收段 | TCP | NIC或者离开网卡驱动进入IP协议栈之前 | Linux 内核 2.6.18 引入(2006)网卡普遍支持 | GRO,基本思想跟LRO类似,克服了LRO的一些缺点,更通用。后续的驱动都使用GRO的接口,而不是LRO。 |
实验验证 TSO
关闭发送方的 TSO 功能,如下所示:
[root@vm-os-centos7 ~]# ethtool -K eth0 tso off
[root@vm-os-centos7 ~]#复制
通过 ethtool -k 可以查看很多网卡的特性,这里我们查看下,上面设置是否生效;
[root@vm-os-centos7 ~]# ethtool -k eth0|grep tcp-segmentation-offload:
tcp-segmentation-offload: off
[root@vm-os-centos7 ~]#复制
上面设置已经生效,我们再进行实验,抓包分析如下:
(图:Len 大小约等于MSS)
再次抓包后,发现Len没有大于MSS的了,这里为1488,之所以是1488bytes,是因为 Len = 1500(MTU) - 20(IP Header)- 20(TCP Header) -12(TCP 选项) = 1448 bytes。
总结
本文件从原理实验的角度分析并验证了网卡的 TSO 的功能 ,并给出了其它 Segmentation offloading 技术在网卡上面的常用参数设置,例如 TSO、UFO 和 GSO 他们对应是网络发送路径上的优化参数,而在接收方向上对应的是 LRO、GRO ,下图来源于网络。
您的关注是我写作的动力
基础小知识
CentOS 7 下 yum 安装 MySQL 5.7 最简教程
kubernetes中部署 nacos,使用外部MySQL存储
专辑分享