提起存储都是血泪史,不知道丢了多少数据,脑子首先想到的就是《你说啥》洗脑神曲,我就像那个大妈一样,千万个问号?????????????.........
hdd是啥?ssd又是啥?
mbr是啥?gpt又是啥?
primary partion是啥?logical partion又是啥?
sata是啥?scsi又是啥?
sas又是啥?nvme又是啥?
它们和pcie又是什么关系?
hardware raid是啥?firmware raid是啥?software raid又是啥?
intel rst中raid/ahci模式又有啥区别?为啥raid模式双系统linux安装时找不到盘?
需求
第一高并发低时延,第二隔离。
用于特定业务运算时临时数据过多过大,在内存中放不下,要临时写到硬盘中,这些数据不需要长久保存,只要能快速大量写和读就行。
虚拟机用的nvme ssd盘的大小和数据在创建虚拟机时指定,不用支持动态添加nvme ssd和虚拟机带nvme ssd热迁移,nvme ssd数据不做多副本。
调研
先看nvme是什么东东,从它的spec入手。
居然支持sr-iov和namespace,sr-iov代表着硬件资源切分和隔离,并且是标准pcie设备,可以passthrough给虚拟机的,namespace看起来和sr-iov差不多,硬件级别的虚拟,两者什么区别暂时不明白。
高并发低时延:
性能高要求至少跳过host上的image format和file system处理,不能再把虚拟机的硬盘当作一个image文件,而是直接让qemu调用host内核的block layer或者操作硬件。
- pcie passthrough
- qemu userspace nvme driver
- spdk
- 一个raw disk给虚拟机,虚拟机里分区和创建文件系统
隔离:
有软件隔离和硬件隔离,硬件隔离是最安全的。
- lvm
- 虚拟机独占一个nvme ssd
- nvme namespace
资源利用率:
除了满足用户需求还得考虑资源的充分利用,争取把本地nvme ssd的空间充分利用起来。
- lvm
- nvme namespace
nvme mdev太超前了,不知道硬件和软件是否支持。
验证
测试机器上有9块nvme ssd,一块系统ssd挂sata接口下,另外8块挂pci下,前四块4T,后四块2T。
lspci -s b2:00.0 -vvv查看发现Capabilities中没有Single Root I/O Virtualization (SR-IOV),上网一查看来是真不支持。
试着在一块nvme ssd上创建两个namespace报错,上网找找,一对型号是支持的,得升级firmware。
找升级工具,安装 yum install ./intelmas-1.5.113-0.x86_64.rpm,升级intelmas load -intelssd 7
代码语言:javascript复制在第7块ssd是划分4个500G namespace
nvme detach-ns /dev/nvme7 -n 1 -c 0
nvme delete-ns /dev/nvme7 -n 1
nvme reset /dev/nvme7
nvme create-ns /dev/nvme7 -s 975175680 -c 975175680 -f 0 -d 0 -m 0
nvme attach-ns /dev/nvme7 -n 1 -c 0
nvme create-ns /dev/nvme7 -s 975175680 -c 975175680 -f 0 -d 0 -m 0
nvme attach-ns /dev/nvme7 -n 2 -c 0
nvme create-ns /dev/nvme7 -s 975175680 -c 975175680 -f 0 -d 0 -m 0
nvme attach-ns /dev/nvme7 -n 3 -c 0
nvme create-ns /dev/nvme7 -s 975175680 -c 975175680 -f 0 -d 0 -m 0
nvme attach-ns /dev/nvme7 -n 4 -c 0
nvme reset /dev/nvme7
在系统上看到确实成了4块nvme ssd。
但pci设备没有多,至少说明pci passthrough是不行的,估计有了sr-iov结合namespace就可能单独passthrough了,passthrough不行退而求其次试试qemu userspace nvme driver。
代码语言:javascript复制#qemu nvme userspace driver
intel_iommu=on iommu=pt
echo 0000:b2:00.0 > /sys/bus/pci/devices/0000:b2:00.0/driver/unbind
echo 8086 0a54 > /sys/bus/pci/drivers/vfio-pci/new_id
lspci -s 0000:b2:00.0 -vvv
#虚拟机1
/usr/libexec/qemu-kvm -machine pc-q35-rhel7.3.0,accel=kvm,usb=off,dump-guest-core=off
-cpu host -m 16384 -device piix3-usb-uhci,id=usb -device usb-tablet,id=input0,bus=usb.0,port=1 -vnc :0
--monitor stdio -device virtio-scsi-pci,id=vs0
-drive file=/home/huiwei/linux0.vmdk,format=vmdk,id=drive0,if=none -device scsi-hd,drive=drive0 -device virtio-scsi-pci,id=vs1
-drive file=nvme://0000:b2:00.0/1,format=raw,id=drive1,if=none -device scsi-hd,drive=drive1
#虚拟机2
/usr/libexec/qemu-kvm -machine pc-q35-rhel7.3.0,accel=kvm,usb=off,dump-guest-core=off -cpu host -m 16384 -device piix3-usb-uhci,id=usb -device usb-tablet,id=input0,bus=usb.0,port=1 -vnc :1 --monitor stdio -device virtio-scsi-pci,id=vs0 -drive file=/home/huiwei/linux1.vmdk,format=vmdk,id=drive0,if=none -device scsi-hd,drive=drive0 -device virtio-scsi-pci,id=vs1 -drive file=nvme://0000:b2:00.0/2,format=raw,id=drive1,if=none -device scsi-hd,drive=drive1
报错了,看来也行。
代码语言:javascript复制qemu-kvm: -drive file=nvme://0000:b2:00.0/2,format=raw,id=drive1,if=none: Failed to open VFIO group file: /dev/vfio/80: Device or resource busy
不了解以为是什么高大上的东西,想想也是,不可能两个qemu进程同时驱动这个pci设备。
The difference between <disk type='nvme'> and <hostdev/> is that the latter is plain host device assignment with all its limitations (e.g. no live migration), while the former makes hypervisor to run the NVMe disk through hypervisor's block layer thus enabling all features provided by the layer (e.g. snapshots, domain migration, etc.). Moreover, since the NVMe disk is unbinded from its PCI driver, the host kernel storage stack is not involved (compared to passing say /dev/nvme0n1 via <disk type='block'>) and therefore lower latencies can be achieved.
再退而求其次,创建两台虚拟机分别用不同的namespace。
代码语言:javascript复制#虚拟机1
/usr/libexec/qemu-kvm -machine pc-q35-rhel7.3.0,accel=kvm,usb=off,dump-guest-core=off
-cpu host -m 16384 -device piix3-usb-uhci,id=usb
-device usb-tablet,id=input0,bus=usb.0,port=1 -vnc :0
--monitor stdio -device virtio-scsi-pci,id=vs0
-drive file=/home/huiwei/linux0.vmdk,format=vmdk,id=drive0,if=none
-device scsi-hd,drive=drive0 -device virtio-scsi-pci,id=vs1
-drive file=/dev/nvme7n1,format=raw,id=drive1,if=none -device scsi-hd,drive=drive1
#虚拟机2
/usr/libexec/qemu-kvm -machine pc-q35-rhel7.3.0,accel=kvm,usb=off,dump-guest-core=off -cpu host -m 16384 -device piix3-usb-uhci,id=usb -device usb-tablet,id=input0,bus=usb.0,port=1 -vnc :1 --monitor stdio -device virtio-scsi-pci,id=vs0 -drive file=/home/huiwei/linux1.vmdk,format=vmdk,id=drive0,if=none -device scsi-hd,drive=drive0 -device virtio-scsi-pci,id=vs1 -drive file=/dev/nvme7n2,format=raw,id=drive1,if=none -device scsi-hd,drive=drive1
libvirt用如下格式
代码语言:javascript复制<disk type='block' device='disk'>
<driver name='qemu' type='raw'/>
<source dev='/dev/nvme7n1'/>
<target dev='sdb' bus='scsi'/>
</disk>
虚拟机里多了一块硬盘,能正常分区和创建文件系统,并且读写。
最后删除虚拟机,擦除数据。
代码语言:javascript复制nvme format -s1 /dev/nvme7n1
nvme format -s1 /dev/nvme7n2
方案
总体上来说,pci passthrough一个nvme ssd只能给一个虚拟机用,qemu userspace nvme driver也存在这个问题,还要求升级libvirt版本到6.0.0,存在过度资源浪费,排除这两种用法。
spdk要求有hugepage,要求qemu支持vhost user,得升级qemu版本,nvme ssd独占给spdk进程,对spdk不熟悉。
lvm多了一层会引入额外的性能损耗。
nvme namespace可以把nvme ssd分成flavor中指定大小的namespace,虽然还是同一个pci设备,但在host上看到的就是一个个单独的硬盘,由物理硬件做隔离和加速。
所以选择nvme namespace,/dev/nvme0n1 via <disk type='block'>,最终效果如下,一个专用qemu iothread处理这块nvme raw block。
给虚拟机的存储控制器用virtio-scsi,主要是考虑到虚拟机和物理机对硬盘命名方式一致,而且一般物理机上用scsi controller,在物理机上应用有可能针对scsi用过优化,用virtio-scsi保证用户从物理机顺利迁移到虚拟机上。
virtio-scsi后端继续用qemu virtio scsi,kernel vhost-scsi用的少,而且我们用的host centos kernel没有编译进去(CONFIG_VHOST_SCSI is not set)。
开发
部署时所有非系统用nvme ssd盘都划分成500G大小的namespace,nova-compute要能发现nvme ssd盘namespace,并且上报给nova控制面,nova控制面写到数据库,
创建虚拟机时flavor中指定本地ssd大小,支持1*500,2*500,3*500,4*500的规格,nova-scheduler调度时考虑本地ssd盘资源,用过的在数据库中做标志,删除虚拟要时擦除数据。
os-brick是否可以发现和管理nvme?
pynvme又能做什么,nova是否可能调用pynvme而非执行命令?
nvme-cli是否有对应的python库?
虚拟机内规划好ssd和目录对应关系,或者用lvm管理ssd。
参考文献
https://community.intel.com/t5/Solid-State-Drives/Intel-NVME-SR-IOV-support/td-p/624319
https://nvmexpress.org/resources/nvm-express-technology-features/nvme-namespaces/
https://www.intel.com/content/www/us/en/support/articles/000038017/memory-and-storage/data-center-ssds.html
https://opendev.org/openstack/os-brick
https://github.com/pynvme/pynvm