Qemu的存儲棧
在KVM虛擬化環境中,當客戶機的內核存儲系統像在物理機上一樣通過頁緩存、文件系統、通用塊設備層運行到實際設備驅動時,這時驅動對設備寄存器的訪問會觸發CPU從客戶機代碼切換到物理機內的KVM內核模塊,進而這個I/O請求會被分發到對應的Qemu模擬的磁盤設備的代碼(下面將會介紹的vhost-scsi除外)。在引入virtio-scsi之前,SCSI設備的模擬並不成熟,所以Qemu支持的磁盤接口類型主要包括IDE和Virtio[1]。
Virtio是一個通用的I/O虛擬化框架[2], 它可以有效地簡化設備邏輯,從而大大減少虛擬機退出(VMEXit)次數,並且通過使用虛擬機和物理機共享的分散聚合(scatter gather)緩沖區,提高了數據傳輸效率。當然這需要運行在客戶機內核中的前端驅動和運行在物理機中后端設備代碼協作完成。在Linux上,Virtio的磁盤驅動是在通用塊設備框架下實現的,當它接收到來自上層的I/O請求后,會把該請求加上Virtio塊設備請求的描述信息,一起加入緩沖區,然后觸發VMExit來通知后端服務代碼。Qemu中的Virtio塊設備的服務代碼會解析緩沖區中的數據,得到塊設備的操作指令和對象數據,然后調用Qemu中的塊設備代碼,進一步完成這個I/O請求。也就是說,Qemu中暴露給虛擬機的設備只負責處理設備邏輯,和客戶機里對應的驅動共同把數據從客戶機傳輸到物理機。
Qemu的塊設備層會和后端存儲交互,完成最終的I/O操作。后端存儲也就是實際存儲虛擬磁盤內容的地方。Qemu中支持的后端存儲包括:
- 主機支持的文件系統上的文件,包括本地文件系統和網絡文件系統
- 塊設備,包括本地磁盤,SAN磁盤,iSCSI磁盤和LVM等
- 遠端存儲,包括nbd, iSCSI以及Glusterfs, Sheepdog, Ceph等分布式存儲。
前端設備和后端存儲的分離,可以從Qemu的命令行中看出:
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x9,drive=drive-virtio-disk1,id=virtio-disk1
-drive file=/var/lib/libvirt/images/vm1.img,if=none,id=drive-virtio-disk2,format=qcow2
可以看到, 選項 '-device' 指定了前端的設備類型,而 '-drive' 選項定義了后端存儲,並且通過設備的'drive'屬性把設備和存儲關聯起來,就好像把盤片插入控制器。這樣的設計,使得Qemu更容易利用到外部存儲服務提供的高級特性,比如鏡像和條帶化I/O等。
后端存儲的'format'選項表明該磁盤鏡像使用的格式。Qemu支持的磁盤格式包括raw, qcow2, vdi, vmdk等。實際上,對於格式不是raw的磁盤鏡像,Qemu的塊設備層會先進入對應的格式驅動,這樣才能實現它們所提供的高級特性,比如寫時分配,快照等。
Virtio SCSI
virtio-blk設備提供了很好的性能,但仍然有一定的局限性:
- 可擴展性差:每個virtio-blk設備也是一個pci設備,也就是說每個虛擬磁盤就要占用一個pci設備,這樣一個虛擬機的磁盤個數就要受限於PCI設備的個數。
- 支持的特性受限:僅管virtio實現了SCSI透傳的功能,這一點可以從上面的'-device'選項中的'scsi'屬性可以看出,但是這個支持是有限的,因為它並不是在SCSI的框架下實現的,在客戶機看來也不是一個真的SCSI設備,當然也不支持多路徑和SCSI隔離這樣的特性。
- 設備名字和現有物理設備不兼容:virtio-blk出現在客戶機上的設備文件是/dev/vda這樣的名字,會給一些工具造成麻煩。
Virtio SCSI的引入,很好的解決了上述問題。SCSI的initiator和Target之間可以使用多種傳輸協議中作為信道來傳SCSI指令和應答數據。Virtio SCSI就是把virtio作為一種傳輸通道來傳送SCSI指令。這樣既可以保持virtio-blk設備具有的高性能,也解決了virtio-blk存在的局限性:
- 更豐富的特性,它支持的特性不取決於它本身,而是它的target,因為它已經借助SCSI的框架完整實現了SCSI initiator的功能。
- 每個virtio-scsi設備對應一個PCI設備,而一個virtio-scsi設備可以連接上千個磁盤。
- 每個virtio-scsi設備就是一個SCSI Host,這樣為在客戶機里實現多路徑創造了條件。
- 在客戶機看來,virtio-scsi設備相當於一個基於virtio的HBA卡
Virtio SCSI支持兩種target,一種是在Qemu中模擬的,另外一種是在內核中模擬的。下面的Qemu命令行展示了怎樣增加一個由Qemu模擬的virtio scsi設備
-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x8-drive file=/var/lib/libvirt/image/scsi-disk1.img,if=none,id=drive-scsi0-0-0-0,format=raw-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0
對應的Libvirt XML描述如下:
<controller type='scsi' index='0' model='virtio-scsi'/><disk type='file' device='disk'><driver name='qemu' type='raw'/><source file='/var/lib/libvirt/scsi-disk1.img'/><target dev='sda' bus='scsi'/><address type='drive' controller='0' bus='0' target='0' unit='0'/></disk>
而在內核中模擬的SCSI Target則是利用了LIO[5]的框架,通過使用vhost為LIO增加了一種基於Virtio的傳輸機制。這樣Guest的SCSI指令就可以通過Virtio直接傳送到
LIO的SCSI引擎中,然后交到它的后端存儲中處理。LIO支持文件,塊設備,內存磁盤,透傳SCSI設備等后端。在內核中實現的SCSI target有以下優點:
- 更穩定可靠的
- 減少了用戶態和內核的切換,同時避免了Qemu中的全局鎖的限制
和缺點:
- 不支持熱遷移
- 無法使用Qemu支持的磁盤鏡像格式
下面的命令行展示了如何使用tagetcli[6]創建一個SCSI target,並把它作為一個SCSI設備增加到虛擬機中:
$ sudo targetclitargetcli shell version 2.1.fb30Copyright 2011-2013 by Datera, Inc and others.For help on commands, type 'help'./> lso- / ......................................................................................................................... [...]o- backstores .............................................................................................................. [...]| o- block .................................................................................................. [Storage Objects: 0]| o- fileio ................................................................................................. [Storage Objects: 0]| o- pscsi .................................................................................................. [Storage Objects: 0]| o- ramdisk ................................................................................................ [Storage Objects: 0]o- iscsi ............................................................................................................ [Targets: 0]o- loopback ......................................................................................................... [Targets: 0]o- vhost ............................................................................................................ [Targets: 0]/> cd /backstores/ramdisk/backstores/ramdisk> create scsi-ramdisk1.img 100MCreated ramdisk scsi-ramdisk1.img with size 100M./backstores/ramdisk> cd ../../vhost/vhost> createCreated target naa.50014058a9474085.Created TPG 1./vhost> cd naa.50014058a9474085/tpg1/luns/vhost/naa.50...085/tpg1/luns> lso- luns .................................................................................................................. [LUNs: 0]/vhost/naa.50...085/tpg1/luns> create /backstores/ramdisk/scsi-ramdisk1.imgCreated LUN 0.sudo ./x86_64-softmmu/qemu-system-x86_64 -m 1024 -enable-kvm --device vhost-scsi-pci,id=vhost-scsi0,wwpn=naa.naa.50014058a9474085 -cdrom ~/Downloads/software/Fedora-Live-Desktop-x86_64-19-1.iso
新增加的SCSI設備。
[1] https://github.com/rustyrussell/virtio-spec
[2] http://www.ibm.com/developerworks/cn/linux/l-virtio/
[3] http://www.linux-kvm.org/wiki/images/f/f5/2011-forum-virtio-scsi.pdf