一 简介
用户对超高并发、超大规模计算等需求推动了存储硬件技术的不断发展,存储集群的性能越来越好,延时也越来越低,对整体IO路径的性能要求也越来越高。在云硬盘场景中,IO请求从生成到后端的存储集群再到返回之间的IO路径比较复杂,虚拟化IO路径尤其可能成为性能瓶颈,因为虚机内所有的IO都需要通过它下发给后端的存储系统。我们使用了SPDK来优化虚拟化IO路径,提出了开源未解决的SDPK热升级和在线迁移方案,并且在高性能云盘场景中成功应用,取得了不错的效果,RSSD云硬盘最高可达120万IOPS。本文主要分享我们在这方面的一些经验。
二 SPDK vhost的基本原理
SPDK(Storage Performance Development Kit )提供了一组用于编写高性能、可伸缩、用户态存储应用程序的工具和库,基本组成分为用户态、轮询、异步、无锁 NVMe 驱动,提供了从用户空间应用程序直接访问SSD的零拷贝、高度并行的访问。
在虚拟化IO路径中,virtio是比较常用的一种半虚拟化解决方案,而virtio底层是通过vring来通信,下面先介绍下virtio vring的基本原理,每个virtio vring 主要包含了以下几个部分:
- desc table数组,该数组的大小等于设备的队列深度,一般为128。数组中每一个元素表示一个IO请求,元素中会包含指针指向保存IO数据的内存地址、IO的长度等基本信息。一般一个IO请求对应一个desc数组元素,当然也有IO涉及到多个内存页的,那么就需要多个desc连成链表来使用,未使用的desc元素会通过自身的next指针连接到free_head中,形成一个链表,以供后续使用。
- available数组,该数组是一个循环数组,每一项表示一个desc数组的索引,当处理IO请求时,从该数组里拿到一个索引就可以到desc数组里面找到对应的IO请求了。
- used 数组,该数组与avail类似,只不过用来表示完成的IO请求。当一个IO请求处理完成时,该请求的desc数组索引就会保存在该数组中,而前端virtio驱动得到通知后就会扫描该数据判断是否有请求完成,如果完成就会回收该请求对应的desc数组项以便下个IO请求使用。
SPDK vhost的原理比较简单,初始化时先由qemu的vhost驱动将以上virtio vring数组的信息发送给SPDK,然后SPDK通过不停的轮寻available数组来判断是否有IO请求,有请求就处理,处理完后将索引添加到used数组中&#