作者:深耕行业的 SmartX 金融团队
本文主要介绍使用 SPDK vhost-user 技术,来加速 KVM 虚拟机中 virtio-blk/virtio-scsi 存储设备的 I/O 性能,并结合架构场景展开说明,让读者对这项技术带来的特性提升有更直观的了解。
首先我们先看看当前主流的 I/O 设备虚拟化方案:
- QEMU 纯软件模拟,利用软件模拟 I/O 设备提供给虚拟机使用。
- Virtio 半虚拟方案,规范了前后端模型,在虚拟机(Guest OS)中使用 frontend 驱动(Virtio Drive),在 Hypervisor(QEMU)中使用 backend 设备(Virtio Device)提供 I/O 能力,通过减少内存复制次数和 VM 陷入次数,提升 I/O 性能,这种方案需要安装 Virtio 驱动。
本文的主角 vhost 技术是基于 Virtio 规范发展衍生出来,优化 I/O 链路,可以用来加速 QEMU 中半虚拟化的 Virtio 设备 I/O 性能。
Virtio 介绍
Virtio 基于 Vring 的 I/O 通讯机制,相比 QEMU 的纯软件模拟,有效降低了 I/O 延迟,具有性能优势。这也是 Virtio 普及的原因,各个厂商的半虚拟化 I/O 设备实现方式开始变得统一。
在 QEMU 中,Virtio 设备是为 Guest 操作系统模拟的 PCI/PCIe 设备,遵循 PCI 规范,具有配置空间、中断配置等功能。Virtio 注册了 PCI 厂商 ID(0x1AF4)和设备 ID,不同的设备 ID 代表不同的设备类型,例如面向存储的 virtio-blk(0x1001)和 virtio-scsi 设备 ID(0x1004)。
Virtio 由三部分组成,前端是驱动层,位于 Guest 系统内部,中间是虚拟队列(virtqueue),负责数据传输和命令交互,后端设备层,用于具体处理 Guest 发送的请求。
下面我们一起来看一下超融合架构下,基于 virtio-blk 的数据路径是什么样子的。
备注:超融合架构是一种 IT 基础架构解决方案,将计算、存储和网络资源整合在一个统一系统(计算服务器)中。超融合基础架构由虚拟化、分布式存储和软件定义网络组成。利用分布式架构实现集群的可靠性和容错性,并通过将计算与存储集成在一起,灵活部署在通用标准硬件上,来降低数据中心复杂性和占用空间,并支持更多的现代工作负载。
- Guest 发起 I/O 操作,Guest 内核 Virtio 驱动写 PCI 配置空间,触发 VM EXIT,返回到 Host KVM 中(通知 KVM);
- QEMU 的 vCPU 线程从 KVM 内核态回到 QEMU,让 QEMU Device 来处理 Virtio Vring 请求;
- QEMU 通过 iSCSI Drive 发起存储连接(iscsi over tcp to localhost);
- 通过 Socket 将请求连接到存储进程提供的 iSCSI Target;
- 存储引擎接收请求并进行 I/O 处理;
- 存储引擎发起对本地存储介质的 I/O;
- I/O 操作结束,通过上述逆过程返回至 Virtio 后端 Device,QEMU 会向模拟的 PCI 发送中断通知,从而 Guest 基于该中断完成整个 I/O 流程。
QEMU 通过本地 Socket 连接存储进程,数据流从用户态到内核态再到用户态(数据复制开销),同时 iSCSI 协议层也存在性能消耗,如果存储进程可以直接接收处理本地 I/O,就可以避免这些问题带来的损耗,实现 Virtio Offload to Storage Software。
Vhost 加速
如前所述,Virtio 后端 Device 用于具体处理 Guest 的请求,负责 I/O 的响应,把 I/O 处理模块放在 QEMU 进程之外去实现的方案称为 vhost。由于我们需要实现的优化目标是在两个用户态进程之间(超融合架构),所以采用 vhost-user 方案进行存储加速实现(vhost-kernel 方案主要是将 I/O 负载卸载到内核完成,所在不在本文讨论)。
Vhost-user 的数据平面处理主要分为 Master 和 Slave 两个部分,其中 Master 为 virtqueue 的供应方,一般由 QEMU 作为 Master,存储软件作为 Slave,负责消费 virtqueue 中的 I/O 请求。
Vhost-user 方案优势:
- 消除 Guest 内核更新 PCI 配置空间,QEMU 捕获 Guest 的 VMM 陷入所带来的 CPU 上下文开销(后端处理线程采用轮询所有 virtqueue)。
- 用户态进程间内存共享,优化数据复制效率(零拷贝)。
- 当 Guest 发起 I/O 操作后,存储软件通过 Polling 机制感知新的请求动作,从 virtqueue 获取数据;
- 存储引擎接收请求并进行 I/O 处理;
- 存储引擎发起对本地存储介质的 I/O;
- I/O 操作完成后,由 vhost device 发送 irqfd(eventfd)通知到 KVM;
- KVM 注入中断通知 Guest OS 完成 I/O。
注:前端 vhost driver 与后端 vhost device 之间的控制类信息传递通过 UNIX Domain Socket 文件实现。
介绍完理论过程,让我们看一组存储性能对比 Virtio vs Vhost-user(单节点性能)。
测试数据基于 3 节点集群(超融合架构,集群存储网络未开启 RDMA),节点硬件配置如下:
- Intel Xeon Gold 5122 3.6GHz
- 8*16G DDR4 2666MHz
- 2*Intel P4610 1.6T NVMe
- Mellanox CX-4 25Gbps
通过图表对比单节点 4k iodepth=128 下的 IOPS(数值越高越好)性能差异:
通过图表对比单节点 4k iodepth=1 下的 Latency(数值越低越好)性能差异:
总结
通过理论和真实的性能数据介绍,可以看出,相比 Virtio 方案,通过 Vhost 技术实现了更加突出的存储性能表现,但作为企业级产品交付,需要考虑到企业级功能,例如存储软件异常下的 Vhost 重连/切换、虚拟机的内存热添加等实际场景,希望这篇文章对于读者理解 Vhost 以及适配超融合架构有所帮助。