作者:深耕行业的 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 性能。

vhost1.jpg

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 发送的请求。

vhost2.jpg

下面我们一起来看一下超融合架构下,基于 virtio-blk 的数据路径是什么样子的。

备注:超融合架构是一种 IT 基础架构解决方案,将计算、存储和网络资源整合在一个统一系统(计算服务器)中。超融合基础架构由虚拟化、分布式存储和软件定义网络组成。利用分布式架构实现集群的可靠性和容错性,并通过将计算与存储集成在一起,灵活部署在通用标准硬件上,来降低数据中心复杂性和占用空间,并支持更多的现代工作负载。

vhost3.jpg

  1. Guest 发起 I/O 操作,Guest 内核 Virtio 驱动写 PCI 配置空间,触发 VM EXIT,返回到 Host KVM 中(通知 KVM);
  2. QEMU 的 vCPU 线程从 KVM 内核态回到 QEMU,让 QEMU Device 来处理 Virtio Vring 请求;
  3. QEMU 通过 iSCSI Drive 发起存储连接(iscsi over tcp to localhost);
  4. 通过 Socket 将请求连接到存储进程提供的 iSCSI Target;
  5. 存储引擎接收请求并进行 I/O 处理;
  6. 存储引擎发起对本地存储介质的 I/O;
  7. 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)。
  • 用户态进程间内存共享,优化数据复制效率(零拷贝)。

vhost4.jpg

  1. 当 Guest 发起 I/O 操作后,存储软件通过 Polling 机制感知新的请求动作,从 virtqueue 获取数据;
  2. 存储引擎接收请求并进行 I/O 处理;
  3. 存储引擎发起对本地存储介质的 I/O;
  4. I/O 操作完成后,由 vhost device 发送 irqfd(eventfd)通知到 KVM;
  5. KVM 注入中断通知 Guest OS 完成 I/O。

注:前端 vhost driver 与后端 vhost device 之间的控制类信息传递通过 UNIX Domain Socket 文件实现。

介绍完理论过程,让我们看一组存储性能对比 Virtio vs Vhost-user(单节点性能)。

表格.jpg

测试数据基于 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(数值越高越好)性能差异:

vhost5.jpg

通过图表对比单节点 4k iodepth=1 下的 Latency(数值越低越好)性能差异:

vhost6.jpg

总结

通过理论和真实的性能数据介绍,可以看出,相比 Virtio 方案,通过 Vhost 技术实现了更加突出的存储性能表现,但作为企业级产品交付,需要考虑到企业级功能,例如存储软件异常下的 Vhost 重连/切换、虚拟机的内存热添加等实际场景,希望这篇文章对于读者理解 Vhost 以及适配超融合架构有所帮助。