- 前言
- 读者对象
- 如何阅读本书
- 勘误和支持
- 致谢
- 第 1 篇 高性能网站构建
- 第 1 章 深入理解 DNS 原理与部署 BIND
- 第 2 章 全面解析 CDN 技术与实战
- 第 3 章 负载均衡和高可用技术
- 第 4 章 配置及调优 LVS
- 第 5 章 使用 HAProxy 实现 4 层和 7 层代理
- 第 6 章 实践 Nginx 的反向代理和负载均衡
- 第 7 章 部署商业负载均衡设备 NetScaler
- 第 8 章 配置高性能网站
- 第 9 章 优化 MySQL 数据库
- 第 2 篇 服务器安全和监控
- 第 10 章 构建企业级虚拟专用网络
- 第 11 章 实施 Linux 系统安全策略与入侵检测
- 第 12 章 实践 Zabbix 自定义模板技术
- 第 13 章 服务器硬件监控
- 第 3 篇 网络分析技术
- 第 14 章 使用 tcpdump 与 Wireshark 解决疑难问题
- 第 15 章 分析与解决运营商劫持问题
- 第 16 章 深度实践 iptables
- 第 4 篇 运维自动化和游戏运维
- 第 17 章 使用 Kickstart 完成批量系统安装
- 第 18 章 利用 Perl 编程实施高效运维
- 第 19 章 精通 Ansible 实现运维自动化
- 第 20 章 掌握端游运维的技术要点
- 第 21 章 精通手游运维的架构体系
最佳实践 24:注意网卡参数与 MTU 问题
MTU 的原理
MTU(Maximum Transmission Unit,最大传输单元)是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口有关(网络接口卡、串口等)。
以以太网传送 IPv4 报文为例。MTU 表示的长度包含 IP 包头的长度,如果 IP 层以上的协议层发送的数据报文的长度超过了 MTU,则在发送者的 IP 层将对数据报文进行分片,在接收者的 IP 层对接收到的分片进行重组。
这里举一个具体的例子说明 IP 包分片的原理。以太网的 MTU 值是 1500 bytes,假设发送者的协议高层向 IP 层发送了长度为 3008 bytes 的数据报文,则该报文在添加 20 bytes 的 IP 包头后 IP 包的总长度是 3028 bytes,因为 3028>1500,所以该数据报文将被分片,分片过程如下。
(1)首先计算最大的 IP 包中 IP 净荷的长度=MTU-IP 包头长度=1500-20=1480 bytes。
(2)然后把 3028 bytes 按照 1480 bytes 的长度分片,将要分为 3 片,3028=1480+1480+68。
(3)最后发送者将为 3 个分片分别添加 IP 包头,组成 3 个 IP 包后再发送,3 个 IP 包的长度分别为 1500 bytes、1500 bytes 和 88 bytes。
从以上分片例子可以看出第一、二个分片包组成的 IP 包的长度都等于 MTU,即 1500 bytes。
案例解析
下面从一个案例说起 LVS 与 MTU 的问题。
某日,某游戏项目反馈:有一台北京电信通服务器往 sood 上传文件慢。如图 4-9 所示,红框中时间差值变是上传所花费的时间,可以看到有将近 8 秒。
图 4-9 上传请求的时间消耗示意图
sood 是一套分布式文件存储系统,主要应用范围是小文件存储。支持高可用、动态添加节点等功能。它的系统架构图如图 4-10 所示。
图 4-10 sood 架构图
收到反馈后,运维人员马上针对系统各结点进行检查。
- LVS 服务器:Keepalived 工作正常、日志无异常。
- sood 索引服务器:apache 和 sood 索引程序工作正常、日志无异常。
- 存储服务器:sood 存储程序工作正常。
应用层面没有发现任何异常情况,初步怀疑是网络问题造成的延时。分别在 LVS、Web 及 Client 服务器上同时抓包,发现以下几个现象。
现象一(文件:LVS_LoadBalancer_MTU.pcap,Frame 29、30):LVS 收到的数据长度 2920(见图 4-11 中所示)超过 MTU,LVS 给 Client 发了一个 ICMP 包要求分片(见图 4-11 中
、
所示),如图 4-11 所示。
图 4-11 LVS 上发送 ICMP MTU 过大反馈
现象二(文件:LVS_Client_MTU.pcap,Frame 364、488):Client 收到 ICMP 包(时间为图 4-12 中所示,内容为图 4-12 中
、
所示)后,过了 3.8s(时间为
所示)才进行重传,如图 4-12 所示。
图 4-12 Client 上的 TCP 重传现象
接下来来看下 Client 上和 LVS 上的数据包的序列号(Sequence)情况。
Client 上(文件:LVS_Client_MTU.pcap,Frame 361)的序列号如图 4-13 中所示。
图 4-13 Client 上发送的数据包的序列号
LVS 上收到的序列号(文件:LVS_LoadBalancer_MTU.pcap,Frame 29)如图 4-14 所示。
图 4-14 LVS 上收到的数据包的序列号
上图分别为 Client 和 LVS 上,请求分片的 ICMP 包之前发送和收到的数据包,可以看到,Sequence Number 相同的两个包(图 4-13 中的和图 4-14 中的
),长度却不同,下一个包的 Sequence Number 也不同(图 4-13 中的
和图 4-14 中的
)。说明在接收端,将两个数据包进行了合并操作,而合并后的数据包长度超过了 MTU。
再来看 Client 服务器上的这个包(文件:LVS_Client_MTU.pcap,Frame 362),很明显这个 Sequence Number 为 3309860110(图 4-15 中的)的包是上个 Sequence Number 为 3309858650 的包的后续,而到了 LVS 服务器上,这两个包被合并了。长度也刚好吻合(1460+1460=2920)。
Client 发送的连续 2 个 TCP 包的序列号分别是 3309858650(图 4-14 中的)和 3309860110(图 4-15 中的
),Next sequence number 是 3309861570(图 4-15 中的
)。正好等于 LVS 上收到的序列号 3309858650(图 4-13 的
),Next sequence number 是 3309861570(图 4-13 中的
)。
注:需要在 Wireshark 配置中,将 Relative Sequence Number 的勾选去掉。这样才能在 Client 和 LVS 服务器上找出相对应的数据包,如图 4-16 所示。
图 4-15 Client 上发送的 362 号数据包的序列号
图 4-16 Wireshark 取消设置相对序列号
到了这里,解决上传慢的问题已经有了眉目,解决问题有以下两个方向。
- 加快 Client 收到 ICMP 请求分片后的响应速度。
- 禁止 LVS 服务器合并数据包的操作,以避免发送 ICMP 请求分片。
对于第一种方案,进行了大量测试,发现 Linux 服务器对这类请求响应速度非常快,Windows 服务器则参差不齐,有的快,有的慢。非常不可控,而且短时间内也无法查明原因。
对于第二种方案,合并操作是和网卡、内核的特性有关。
高速网卡设备不仅可以自动计算数据包的校验和,而且可以根据不同的协议自动对数据包进行分片。由于 MTU 的限制,原先只能通过 IP 协议对大的数据包进行分片,现在网卡设备硬件本身就可以分片,并自动计算出校验和。在较新的 Linux 内核中,也加入了类似的功能,通过内核来分片而不是协议栈。同时,在接收处理方面,也有一些对应的功能,可以合并数据包,接收大的数据包。图 4-17 所示为某网卡的参数设置。
图 4-17 网卡参数获取
这 4 个参数就是合并操作最主要的参数了。从上到下缩写依次为 TSO、UFO、GSO、GRO。
UFO 是专门针对 UDP 协议的,使用了这个特性,用户层就可以发送大的数据包(最大长度是 64KB),而不需要由 IP 协议来分片。UFO 与 TSO、GSO 没有任何的联系,但是却需要 tx-checksumming 和 scatter-gather 这两个特性的支持。遗憾的是,现在还没有看到有网卡支持 UFO。所以,默认情况下,该功能的状态是 off。当前 UFO 被应用在虚拟设备(比如虚拟的 bridge 设备、bond 设备)上。
TSO 是专门针对 TCP 协议的,与 UFO 一样,使用了这个特性,用户层就可以发送大的数据包。TSO 的启用也需要 tx-checksumming 和 scatter-gather 这两个特性的支持。
GSO 是针对所有协议而设计的。但是,与 UFO、TSO 不同的是,分片的动作不是硬件来完成的,而是以软件的方式来完成的(即内核完成)。从用户层的角度看,用户仍然是可以发送大数据包。GSO 与 TSO、UFO 没有任何的联系,同样需要 tx-checksumming 和 scatter-gather 这两个特性的支持。
GRO 是针对网络接受包的处理的,并且只是针对 NAPI 类型的驱动,因此如果要支持 GRO,不仅要内核支持,而且驱动也必须调用相应的接口,GRO 类似 TSO,可是 TSO 只支持发送数据包,这样 TCP 层大的段会在网卡被切包,然后再传递给对端,而如果没有 GRO,则小的段会被一个个送到协议栈,有了 GRO 之后,就会在接收端做一个反向的操作(相对于 TSO)。也就是将 TSO 切好的数据包组合成大包再传递给协议栈。
经过上述介绍,可知合并数据包的关键参数就是 GRO,尝试将该参数设 off。使用的命令如下:
命令为: ethtool -K eth0 gro off (-k 是查看参数、-K 是设置参数)
之后测试,上传速度很快很和谐。再经过抓包分析,果然 ICMP 请求分片消失,也没有之前所描述的数据包合并现象。
在 ip_vs 模块源代码中,可以看到有 MTU 检测的相关代码,当 DF 标志为 1 且 len 超过 MTU 时,发送 ICMP_FRAG_NEEDED。
网卡的参数可能会影响到 LVS 的正常工作,在上线前需要进行多次测试,以验证可行性。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论