默认802.3以太网帧大小为1518字节,或1522字节带有VLAN标记。 以太网报头使用此字节的18个字节(或22个带VLAN标记的字节),留下1500字节的有效最大有效载荷。 巨型帧是对以太网的非正式扩展,网络设备供应商已经做出了事实上的标准,将有效载荷从1500增加到9000字节。
对于常规的以太网帧,每个放置在线路上的1500字节数据有18字节的开销,或者1.2%的开销。使用巨帧,每个9000字节的数据放置在线上有18字节的开销,或0.2%的开销。以上计算假设没有VLAN标签,然而这样的标签将向开销增加4个字节,使得效率增益更加理想。当传输大量连续数据时,例如在两个系统之间发送大文件,可以通过使用巨帧获得上述效率。当传输少量数据(例如通常低于1500字节的web请求)时,可能没有从使用较大帧大小看到的增益,因为通过网络的数据将被包含在小帧内。对于要配置的巨帧,网络段(即广播域)中的所有接口和网络设备必须支持巨帧并启用增加的帧大小。
TCP Timestamps
TCP时间戳是TCP协议的扩展,定义在RFC 1323 - TCP Extensions for High Performance -
TCP时间戳提供单调递增计数器(在Linux上,计数器是自系统引导以来的毫秒),其可以用于更好地估计TCP对话的往返时间,导致更准确的TCP窗口和缓冲器计算。最重要的是,TCP时间戳还提供防止包装序列号,因为TCP报头将序列号定义为32位字段。给定足够快的链路,该TCP序列号可以包装。这导致接收器相信具有包装数的段实际上比其先前段更早到达,并且不正确地丢弃该段。在1吉比特每秒链路上,TCP序列号可以在17秒内换行。在10吉比特每秒的链路上,这被减少到少至1.7秒。在快速链路上,启用TCP时间戳应视为强制。 TCP时间戳提供了一种替代的非循环方法来确定段的年龄和顺序,防止包装的TCP序列号成为问题。
Ensure TCP Timestamps are enabled:
# sysctl net.ipv4.tcp_timestamps net.ipv4.tcp_timestamps = 1
If the above command indicates that tcp_timestamps = 0, enable TCP Timestamps:
# sysctl -w net.ipv4.tcp_timestamps=1
TCP SACK
基本TCP确认(ACK)仅允许接收器通知发送器已经接收到哪些字节。 当丢包发生时,这要求发送方从丢失点重传所有字节,这可能是低效的。 SACK允许发送方指定哪些字节已经丢失以及哪些字节已经被接收,因此发送方只能重传丢失的字节。 在网络社区有一些研究表明启用高带宽链路上的SACK可能导致不必要的CPU周期用于计算SACK值,降低TCP连接的整体效率。 这项研究意味着这些链路是如此之快,重传少量数据的开销小于作为选择性确认的一部分计算提供的数据的开销。 除非有高延迟或高数据包丢失,最有可能更好地保持SACK关闭在高性能网络。 SACK可以使用内核可调参数关闭:
# sysctl -w net.ipv4.tcp_sack=0
TCP Window Scaling
在原始TCP定义中,TCP段报头仅包含用于TCP窗口大小的8位值,这对于现代计算的链路速度和存储器能力是不足的。 引入了TCP Window Scaling扩展以允许更大的TCP接收窗口。 这是通过向在TCP报头之后添加的TCP选项添加缩放值来实现的。 真实的TCP接收窗口向左移位缩放因子值的值,最大大小为1,073,725,440字节,或接近1千兆字节。 TCP窗口缩放是在打开每个TCP对话的三次TCP握手(SYN,SYN + ACK,ACK)期间协商的。 发送方和接收方都必须支持“窗口缩放”窗口缩放选项才能工作。 如果一个或两个参与者在它们的握手中不公布窗口缩放能力,则会话回退到使用原始的8位TCP窗口大小。
默认情况下,在Red Hat Enterprise Linux上启用TCP窗口缩放。 窗口缩放的状态可以使用命令确认:
# sysctl net.ipv4.tcp_window_scaling
net.ipv4.tcp_window_scaling = 1
TCP窗口缩放协商可以通过捕获打开对话的TCP握手的数据包来查看。 在数据包捕获中,检查三个握手数据包的TCP选项字段。 如果任一系统的握手数据包不包含TCP窗口缩放选项,则可能需要在该系统上启用TCP窗口缩放。
TCP Buffer Tuning
一旦从网络适配器处理网络流量,就尝试直接接收到应用中。 如果不可能,数据在应用程序��套接字缓冲区上排队。 套接字中有3个队列结构
sk_rmem_alloc = { counter = 121948 },
sk_wmem_alloc = { counter = 553 },
sk_omem_alloc = { counter = 0
sk_rmem_alloc是接收队列
sk_wmem_alloc是发送队列
sk_omem_alloc是无序队列,不在当前TCP窗口内的skbs被放置在此队列中
还有sk_rcvbuf变量,它代表scoket可以接受的字节数。
例如:
当sk_rcvbuf = 125336