引言
最近购置了一批新服务器,扩展了一下计算集群。依旧没钱上 infinite band,就用的普通的千兆以太网。所有的子节点都是 DELL R740,但是主节点是 DELL T7920。R740 默认带的网卡是博通的 NetXtreme BCM5720,而 T7920 默认用的是 Intel I219-LM 和 Intel I210,两个都是单口网卡,我用的前者作为内网接口,Intel 的这个网卡这就为整件事情埋下了隐患。下文将简要记述遇到的问题,解决的尝试和可行的解决方案。
问题
配置好集群后,运行 iperf 来检查相应的带宽情况。我比较喜欢的检查方式是在一台服务器上开 iperf -s
,在另一台上开 iperf -c <ip> -r
,这样可以直接检验双向的 tcp 传输带宽。于是问题就出现了,结果显示,所有计算节点之间都可以跑满 1000Mbs,但是 master 和子节点之间不行。而且 master 和子节点之间的网速是不对称的,master 发送到子节点的带宽只有 667Mbs,而子节点发送到 master 依旧可以跑满带宽。
排查
首先,用自己的笔记本接到了集群交换机上,master 接口的位置,用来代替 master,再和子节点之间测试 iperf,速度可以双向跑满。之后,将笔记本通过网线直接接到 T7920 的内网网口上,跑 iperf,发现 master 到笔记本依旧只有 667Mbs,由此可以确定集群的硬件连接没有问题,问题完全出在 T7920 上。继续测试 T7920 的另一个网口,可以发现另一个网口也可以双向跑满千兆。通过 sudo lshw -c network
和 ethtool -i enp0s31f6
可以确定,有问题的网口对应的网卡是 Intel I219-LM。
由于全双工局域网以太网中,出现不对称网络性能相当诡异,因此直接搜索 asymmetry network performance 了好久都无果。转为搜索 slow tcp send by Intel I219-LM,出现了大量相关结果,这个网卡,实在是略坑。
解决
最早找到的相关就是这个帖子,顺藤摸瓜,很快找到解决方案,和问题所在。先说问题,问题出在了 linux kernel 里。具体地说,是这个 commit。简单讲,这个系列的网卡 DMA 读取(直接读内存)太快了,以至于可能出现问题,造成 TX hang。为了解决这一问题,kernel 特意进行了改进,把这一过程变慢了“一点”。但该亡羊补牢的方案,会损失掉一部分网卡 tcp 的发送速度(我们这里达到了1/3)。由此,就会造成 kernel 4.15 之后, 使用 I219 网卡的机器,发送 tcp 变慢。这一问题对应在这里的 specification update 文档, 5. Buffer Overrun While the I219 is Processing DMA Transactions。
这一问题解决要分两部分看。首先,如果该网卡是用于连接 Internet 的话,那么大多数情况(比如说百兆光纤),你不需要担心该网卡的性能下降,根本没有机会跑到网卡瓶颈带宽。如果该网卡是用于 LAN 的话,那么跑到千兆还是很有必要的,workaround 也很简单,就是 sudo ethtool -K enp0s31f6 tso off gso off
,其中 enp0s31f6 换成对应的网卡界面名字。ethtool 的-K
是用来调整网卡offload各项特性的开闭。这里我们关掉了相应网卡的 tso 和 gso 功能,也即 tcp segmentation offload。说白了,就是网卡可以硬件上把大的 tcp 包分成小的符合 mtu 的包,并且计算好 hash,从而缓解了 CPU 的工作量。CPU 只需要把很大的 tcp 数据直接扔给网卡就行了。gso 则是更通用的 segmentation offload。但因为这一功能受到了 kernel 降低该网卡 DMA 速度的影响,会造成 tcp 发送变慢。因此我们关掉 tso,还是把 tcp 包的分段交给 cpu 处理。这样我们就靠牺牲一点 CPU 性能(事实上,CPU 的消耗增加很轻微),同时满足了安全性(防止该网卡 DMA 读写过快造成 TX hang),和速度(防止 kernel 的补丁造成该网卡发送 tcp 速度的大幅下降)。注意该 ethtool 命令不是 persistent 的,电脑重启之后会重置,因此你需要将该命令加到开机启动项,无论是 rc.local, service, 还是简单的 crontab,选个自己喜欢的方式就好了。
额外收获
关闭 I219 的 tso 之后,再次测速,发现 master 发送到子节点的带宽已经来到了 940Mbs,和反向的 990 Mbs 还是有误差之外的不对称。然而我读上边说的那个 Intel 的 specification update 的时候,顺带看到了第三点:3. Performance Degradation is Possible with Streams of 9KB Jumbo Frame Packets。Intel 说
When a platform sends a long burst of back-to-back jumbo frames (size is 9 KB) and the Inter-Packet Gap (IPG) is minimal, the performance can be degraded with up to 1/2500 packets lost.
作为一个集群,内网当然 MTU 都设成 9000 了,设成这个数,是因为这是普通的网卡和交换机能够比较好兼容的 MTU 的最大值了。数字再大,就很难保证交换机和网卡可以支持了,除非挨个确认硬件的指标。理论上,只要中间不发生 packet 的二次分段,这个数应该越大越好。然而,Intel 的同款网卡,又有上述问题,MTU 到达 9K 会丢包。其给出的 workaround,是设置 MTU 到 8500。那就设呗,sudo ip link set enp0s31f6 mtu 8500
。将主节点和子节点的 mtu 都改到 8500,再次运行 iperf,大功告成,master 发送到子节点的带宽终于达到了 990Mbs,实现了对称性能。也就是说 mtu 9000 的性能损失在 5% 左右,intel 给出的掉包率有点委婉。
总结
没什么好说的,基本上就是 Intel 一块奇葩网卡引起的连环惨案。但由于这款网卡还挺常见的,还是记录下来,防止更多人踩坑。