前段时间线上环境遇到一个问题,在 POST
数据经过 LVS
的时候,会特别慢,100K 的数据往往超过 5 秒,后来研究发现 LVS
在 Centos6(2.6.29-2.6.39)
下,如果开启 GRO
,会大量丢包。
1 问题现象
线上服务器采用 LVS
作为负载均衡和高可用,LVS
用的是 DR
模式。新建 LVS
使用后发现,在上传数据时,小数据会很快,大数据会很慢。如果绕过 LVS
直接到后端,就没有这个问题,所以问题定位在 LVS
所在的服务器。
现在测试环境重现如下,上传两个文件,一个 10k,一个 100k,10k 的只需要 0.009
秒,100k 竟然要接近 10
秒:
[root@chengqm test_upload]# ll -h
total 112K
-rw-r--r--. 1 root root 100K Mar 31 21:26 100k_file
-rw-r--r--. 1 root root 10K Mar 31 21:25 10k_file
[root@chengqm test_upload]# time curl 10.0.1.188:22333/upload -F "myfile=@./10k_file"
ok
real 0m0.009s
user 0m0.001s
sys 0m0.003s
[root@chengqm test_upload]# time curl 10.0.1.188:22333/upload -F "myfile=@./100k_file"
ok
real 0m9.785s
user 0m0.000s
sys 0m0.006s
2 定位原因
在 LVS
服务器上执行 tcpdump host 10.0.1.188 -w lvs.pcap
捉包,并用 Wireshark
打开,发现有大量的重传现象和 Fragmentation needed
要求分片的控制报文。
接着使用 netstat -i
检查 Client
和 LVS
网卡的 MTU
是否一致,发现相关服务器的 MTU
值均为 1500
,网络工程师告知网络设备 MTU
没有改动,排除机器 MTU
不一致引起的问题。
搜索关键词 lvs fragmentation needed
发现一个叫 GRO
的功能可能会引起 LVS
机器丢包
使用 ethtool -k 网卡名
查看网卡配置,对比正常 LVS
的网卡,发现有问题的网卡确实开启了 GRO
功能
[root@chengqm-lvs ~]# ethtool -k eth0| grep 'generic-receive-offload'
generic-receive-offload: on
手动关闭 GRO
功能
[root@chengqm-lvs ~]# ethtool -K eth0 gro off
再次上传数据
[root@chengqm test_upload]# time curl 10.0.1.188:22333/upload -F "myfile=@./100k_file"
ok
real 0m0.031s
user 0m0.001s
sys 0m0.009s
问题解决,恢复正常
3 问题产生原因
MTU 一般都是 1500 字节,如果一个包超过了 MTU ,就会被分片,对于当前网卡性能来说,这个数值太小了,现在 10Gbps 的网卡都普遍使用了,如果 10Gbps 的网卡满载地来跑,一个完整的数据包会被分片 800w 片。我们可以通过修改 MTU 来减少分片,但是修改 MTU 涉及的设备就多了,不可控。于是有了通过网卡来间接实现提高 MTU 的方案,这就是 GRO
。
如果开启 GRO
,在网卡中将满足一定的条件的包,将分片的包组装合并了,才一次性交给上面的协议栈。在 2.6.29
后 如果网卡和驱动都支持,那么会默认开启 GRO
功能。
据说在 2.6.29-2.6.39
版本中, LVS 内核模块在处理>MTU
的数据包时,会丢弃,所以才能看到一堆重发的包和fragmentation needed
。
4 有没有其他解决方案
- 调整相关设备的
MTU
值。 - 升级
LVS
所在机器的系统内核。
遵从先恢复正常使用的原则,我们直接关闭了 GRO
,上述两个方案可作为后续调整的方向。方案 1 涉及的设备比较多,难以评估风险和影响,所以暂不考虑。方案 2 可作为后期调整方向。
需要注意的一个地方是,如果使用的是云服务器,需要同时关闭宿主机的 GRO
,如果网卡有做 bond
,需要在真实网卡中关闭 GRO
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。