Virtio网卡百兆之谜:真相与修复

KVM虚拟机内ethtool显示网卡百兆,实际内部通信却达23Gbps?这并非硬件故障,而是Virtio半虚拟化网卡的速度显示占位值。本文深入排查vCPU队列、硬件卸载、物理网卡状态,给出启用TSO/SG、配置永久生效等核心修复方案,助你突破虚拟化网络性能瓶颈。

作者:zhuge··预计阅读 12 分钟·8 阅读·0 评论
Virtio网卡百兆之谜:真相与修复

引言

运维KVM虚拟化平台时,你是否遇到过这样的怪事:虚拟机里用 ethtool 查看网卡,速度显示只有 100Mb/s,可虚拟机到宿主机之间的数据传输却轻松跑出 23Gbps 的惊人速度?这种“百兆网卡”与“万兆吞吐”的矛盾,着实令人困惑。

作为一名长期与虚拟化打交道的博主,我决定抽丝剥茧,彻底还原这个问题的真相,并给出经过实战检验的修复方案。

问题现象:矛盾的指标

在一台运行着多个 KVM 虚拟机的宿主机上,我进入某台 Ubuntu 虚拟机执行:

ethtool eth0

输出显示 Speed: 100Mb/s。但当我从宿主机向这台虚拟机拷贝大文件,或使用 iperf3 测试内部带宽时,速度竟高达 23Gbps。显然,网卡真实性能远超“百兆”。

为什么 ethtool 会给出如此离谱的数值?这还得从 Virtio 的原理说起。

排查过程:从虚拟到物理,逐层击破

1. 确认 Virtio 多队列配置

首先检查虚拟机是否启用了多队列,这直接影响 vCPU 并发处理网络包的能力。在宿主机执行:

sudo virsh dumpxml 虚拟机名 | grep -A 15 "<interface"
sudo virsh vcpucount 虚拟机名

理想配置如下,其中 queues 应等于 vCPU 核数:

<interface type='bridge'>
  <model type='virtio'/>
  <driver name='vhost' queues='4'/>
</interface>

2. 安装诊断工具

在虚拟机内安装必要工具:

# Ubuntu/Debian
sudo apt install ethtool iperf3 -y

# CentOS/RHEL
sudo yum install ethtool iperf3 -y

3. 测试虚拟机内部通信

在目标虚拟机启动服务端,从另一台机器测试:

# 服务端
iperf3 -s

# 客户端
iperf3 -c 虚拟机IP

结果显示 23Gbps,说明虚拟机网络栈和 Virtio 驱动本身无问题。问题焦点转向外部访问路径。

4. 测试外部访问速度

从局域网另一台物理机测试:

iperf3 -c 虚拟机IP

速度骤降至 100Mbps 左右。至此,瓶颈锁定在物理网卡或网桥转发环节。

5. 检查物理宿主机网卡硬件卸载状态

在宿主机上查询网卡卸载能力:

sudo ethtool -k 物理网卡名 | grep -E "scatter-gather|tcp-segmentation|generic-receive"

典型的问题输出:

scatter-gather: off
tcp-segmentation-offload: off
generic-receive-offload: on

scatter-gathertcp-segmentation-offload 被关闭时,所有 TCP 分段和内存整理都由 CPU 软件处理,虚拟化环境下这种开销会被急剧放大。

6. 检查物理网卡协商速度

执行 ethtool 物理网卡名,确认物理网卡确实协商在千兆或更高,排除物理链路本身降速的可能。

解决方案:三步修复性能

方案一:立即启用硬件卸载(核心修复)

宿主机上执行(以 enp2s0 为例):

sudo ethtool -K enp2s0 sg on tso on gso on gro on

验证:

sudo ethtool -k enp2s0 | grep -E "scatter-gather|tcp-segmentation|generic-receive|generic-segmentation"

预期输出全为 on

方案二:配置永久生效

NetworkManager dispatcher 方式

sudo nano /etc/NetworkManager/dispatcher.d/99-enable-offload

写入(替换网卡名):

#!/bin/bash
if [ "$1" = "enp2s0" ] && [ "$2" = "up" ]; then
    ethtool -K enp2s0 sg on tso on gso on gro on
fi

赋予执行权限:

sudo chmod +x /etc/NetworkManager/dispatcher.d/99-enable-offload

rc.local 方式:编辑 /etc/rc.local,在 exit 0 前添加相同命令,并 chmod +x /etc/rc.local

方案三:优化网桥性能(可选)

sudo brctl setfd brg0 0
sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0
echo "net.bridge.bridge-nf-call-iptables=0" | sudo tee -a /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-ip6tables=0" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

原理说明:为什么显示百兆却跑出万兆?

Virtio 的“百兆”只是占位符

Virtio 是半虚拟化设备,不模拟物理网卡的链路协商。内核在无法获取真实链路速率时,会返回默认值 100Mb/s 作为占位。因此,ethtool 的速度显示在 Virtio 上毫无参考意义,唯一的真相只有 iperf3 实测带宽。

TSO 与 Scatter-Gather 为何关键?

  • TSO(TCP Segmentation Offload):将 TCP 分段工作从 CPU 卸载到网卡硬件,显著减少中断与协议栈开销。
  • Scatter-Gather:允许网卡直接跨不连续内存缓冲区收发数据,避免多次内存拷贝。

关闭这两项后,CPU 被迫处理所有分段和内存拼接,在虚拟化转发链路(虚拟机→vhost→网桥→物理网卡)中成为绝对瓶颈。

内部快、外部慢的本质

路径是否经过物理网卡主要开销速度表现
虚拟↔宿主机内存拷贝20Gbps+
虚拟↔外部物理网卡卸载能力100Mbps~900Mbps

内部通信不触碰物理网卡,自然不受 TSO/SG 影响;外部访问则完全取决于物理网卡的卸载功能是否开启。

最终验证与后续提醒

修复后再次从外部运行:

iperf3 -c 虚拟机IP

速度应提升至 300~900Mbps。若仍不理想,请检查网线类别(至少 Cat6)、交换机端口、对端网卡能力,以及物理网卡是否跑在完整的 PCIe 带宽上。

结语

Virtio 网卡显示“百兆”并非故障,而是半虚拟化设计的必然。真正的问题是物理网卡硬件卸载被关闭,导致虚拟化场景下性能雪崩。掌握这一排查思路,你就能在虚拟化网络优化的道路上少走弯路,彻底告别“百兆”困局。

希望这篇文章能帮你理清思路,如果你也曾在虚拟化网络中踩过坑,欢迎在评论区分享交流。

相关文章

评论

加载中...