为什么 DPDK VirtIO 只能跑到 40Gbps?—— 一次 KVM 虚拟交换机性能瓶颈定位全过程(上)
一、一个令人困惑的现网问题
某云计算厂商上线了一套基于DPDK + KVM的高性能虚拟交换平台。
整体网络架构如下:
┌──────────────┐ │ Physical NIC │ │ Intel E810 │ └──────┬───────┘ │ DPDK vSwitch │ vhost-user │ QEMU/KVM │ VirtIO-Net │ Guest DPDK设计目标非常明确:
- 物理网络:100GbE
- Guest:DPDK PMD
- 宿主机:DPDK vSwitch
- Zero Copy
- 单 VM 满速接近 100Gbps
实验室测试中,小包、大包都表现正常。
然而真正上线以后,监控平台却发现了一个奇怪的现象:
| 包长 | 理论吞吐 | 实际吞吐 |
|---|---|---|
| 64 Bytes | 100Gbps | 36~40Gbps |
| 512 Bytes | 100Gbps | 42Gbps 左右 |
| 1500 Bytes | 接近 100Gbps | 92~95Gbps |
也就是说:只有小包性能异常。
更奇怪的是:
宿主机 CPU:
平均利用率: 48%Guest CPU:
42%PMD:没有忙轮询瓶颈。
Descriptor:没有耗尽。
没有任何:
RX Miss TX Error No Mbuf Ring Full整个系统看起来一切正常。
但是吞吐率就是上不去。
二、所有人都认为是 PMD 性能不足
第一次排查时。
整个团队几乎一致认为:
一定是 PMD 跑满了。
于是开始查看:
dpdk-proc-info --stats所有 Port:
统计如下:
RX packets : 正常 TX packets : 正常 RX errors : 0 TX errors : 0 RX no mbuf : 0 RX missed : 0继续查看PMD Loop:
CPU 42% Idle 58%这意味着:
PMD并没有跑满。
于是有人开始怀疑:
RSS是不是分布不均?
检查:
RSS所有 Queue:
Queue0 Queue1 Queue2 Queue3 ...... Packets 基本一致RSS正常。
继续NUMA。
结果:
Guest Memory Local Host HugePage Local NIC LocalNUMA也没有问题。
到这里整个团队几乎陷入了僵局。
三、问题真的发生在 VirtIO 吗?
为了进一步定位。
我们绕开 Guest。
直接HostDPDK转发:
E810:
结果:
98Gbps完全正常。
说明:DPDK没有问题。
继续绕开VirtIO。
改成SR-IOV VF直通Guest:
再次测试:
96Gbps依然正常。
问题:
第一次真正开始收敛。
如果:Host正常、Guest、DPDK正常、SR-IOV正常。
那么:
唯一发生变化的。
只有:
VirtIO + vhost-user整个团队开始把目光放到VirtIO。
四、Perf 火焰图暴露了真正的热点
为了定位到底CPU时间花在哪里。
我们在Host运行:
perf record -g随后生成火焰图。
得到如下热点:
vhost_worker() │ vring_avail_event() │ vring_need_event() │ eventfd_write() │ syscall占比超过:
31%继续:
Guest采样结果:
热点几乎全部集中:
virtio_recv_pkts() ↓ virtqueue_get_buf() ↓ used_idx这里第一次出现一个陌生名字:
Virtqueue。
也是VirtIO性能真正开始分化的地方。
五、VirtIO 真正的数据通路
很多人认为:
VirtIO就是共享内存。
实际上:
真正的数据流远比想象复杂。
整体过程如下:
Guest mbuf │ ▼ VirtIO Driver │ ▼ Descriptor Table │ ▼ Available Ring │ ▼ Kick Host │ ▼ vhost-user │ ▼ Host DPDK │ ▼ NIC DMA如果反方向:则Host完成DMA以后。
继续:
Used Ring ↓ Notify Guest ↓ Guest PMD ↓ mbuf看到这里。
很多开发者都会觉得没有什么特别。
其实真正的问题。
并不是Descriptor。
而是后面的两个动作。
Kick Notify六、真正拖慢性能的不是拷贝,而是通知(Notification)
很多开发者第一次接触 VirtIO 时,都会重点关注:
- Descriptor 是否连续?
- 是否 Zero Copy?
- 是否发生数据拷贝?
这些当然重要。
但在高 PPS(Packets Per Second)场景下,真正限制性能的往往不是数据路径,而是控制路径。
对于每一批发送完成的数据,Guest 都需要通知 Host:
“新的 Descriptor 已经准备好了。”
这个动作称为:
Kick同样:
Host处理完成以后。
又需要通知Guest:
Notify如果每一个Burst都Kick。
Host就需要不停响应通知。
CPU不断发生:
Guest ↓ VM Exit ↓ KVM ↓ vhost-user ↓ 继续处理而:
VM Exit正是整个虚拟化里面最昂贵的操作之一。
为什么小包只能40Gbps?
真正答案开始慢慢浮现。
未完待续
