虚拟磁盘discard在qemu中的应用

Posted rayylee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了虚拟磁盘discard在qemu中的应用相关的知识,希望对你有一定的参考价值。

1. discard是什么

在SSD出现之后,产生了一个问题:由于SSD底层的存储实现上和传统的机械硬盘截然不同,导致两者在数据写入和删除上表现出了极大的差异,传统机械硬盘删除数据时仅仅需要将元数据标记为删除,而真正的数据block实际上并没有立即被删除,当下一次写入数据时,只需要用新的数据覆盖掉旧的数据即可。

而SSD则不一样,新的数据只能往空白区域写入,不能像机械硬盘那样直接覆盖,因此一次覆盖写操作将变成一个 read-erase-modify-write 的循环,操作系统如果还是按照机械硬盘的覆盖写入方式来操作SSD的话,将带来性能上的大打折扣和硬盘使用寿命的缩短。

因此对于SSD的操作人们提出了新的需求——需要在数据删除的时候通知硬盘,将数据立即清理掉,在这种需求下,trim指令[1]诞生了,trim指令允许操作系统在SSD上将不再使用的数据通知到SSD底层并在其内部将数据擦除掉。

2. 虚拟磁盘discard

在虚拟化技术的磁盘虚拟化中,也出现了类似问题:由于虚拟磁盘与物理机械硬盘的差异,导致操作系统如果还是按照机械硬盘的方式来删除虚拟磁盘的数据的话,会出现一些额外的效果。

通常我们都希望thin providing的磁盘设备容量用多少算多少,但是现实往往不尽如人意,当我们往虚拟磁盘中写入100M数据,再将它删除,再写入100M数据,我们希望看到的结果是,虚拟磁盘占用不超过100M容量大小,但是现实是虚拟磁盘占用了超过100M容量。这是因为当我们在虚拟机内部执行了删除操作时,如果还是按照机械硬盘的删除方式,那么真正占用了磁盘空间的block部分并没有立即被释放,如果我们在虚拟机内部不断地进行write-delete 循环的话,虚拟磁盘文件将越来越大,大到甚至超过了额定预分配大小。

人们开始意识到在这种虚拟化场景下类似于SSD的trim指令所提供的功能也仍然适用,对于节省存储开销有积极意义。因此,与trim类似的指令也出现在了虚拟磁盘中,用在scsi接口虚拟磁盘上的这个指令叫unmap,通常我们把trim和unmap指令提供的功能称之为discard。

3. 哪些版本支持discard

内核对discard的支持早在2.6.33中就被包含进来,在RHEL6中我们可以发现在2.6.32版本的内核包就将这个功能backport进来,用户空间的程序开始支持discard要稍微晚一些,qemu在1.5版本开始支持(commit history), libvirt从1.0.6开始支持(commit history)。这两个项目的discard功能支持都是由Red Hat提交的,其中libvirt的discard支持是由OsierYang负责的,他是兰大开源社区的创始人之一。

我们可以看看当前最新的fedora20中的版本情况:

[root@localhost ~]$ rpm -q qemu-kvm
qemu-kvm-1.6.2-1.fc20.x86_64
 
[root@localhost ~]$ rpm -q libvirt-daemon
libvirt-daemon-1.1.3.4-4.fc20.x86_64

4. 如何使用discard

要启用虚拟机的discard功能我们只需要在确保当前系统版本支持的基础上,进行两方面的配置即可,一是在host machine上通过libvirt修改虚拟机配置添加disk driver的相关支持,注意下面的配置示例中将使用virtio-scsi作为虚拟磁盘驱动,且添加了额外的’ discard=“unmap” ’

  <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none' discard='unmap'/>
      <source file='/disk/fedora20.data1.img'/>
      <target dev='sda' bus='scsi'/>
  </disk>

  <controller type='scsi' index='0' model='virtio-scsi'>
  </controller>

另一方面我们需要在虚拟机system内修改磁盘的挂载参数以增加对discard的支持:
mount -o discard
或者使用fstrim命令来一次性触发discard操作:
fstrim /mntpoint

5. 如何验证discard是否有效

我们可以通过下面这个简单的对比实验来观察discard的效果,首先为虚拟机分配两块磁盘,sda设置为支持discard而sdb不设置

    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none' discard='unmap'/>
      <source file='/mnt/sda.img'/>
      <target dev='sda' bus='scsi'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/mnt/sdb.img'/>
      <target dev='sdb' bus='scsi'/>
    </disk>

接着启动虚拟机,将两块磁盘分区格式化文件系统后分别挂载到/sda和/sdb目录,对于两个目录均执行循环写入和删除数据的操作,

[root@localhost ~]$ mount -o discard /dev/sda1 /sda
[root@localhost ~]$ mount /dev/sdb1 /sdb 
[root@localhost ~]$ for _ in 1..3; do
    /bin/dd if=/dev/urandom of=/sda/file.$RANDOM bs=1M count=100 && sync
    /bin/dd if=/dev/urandom of=/sdb/file.$RANDOM bs=1M count=100 && sync
    /bin/rm -f /sda/file.* /sdb/file.* && sync
done

现在回到host machine中,使用du命令来观察两个虚拟磁盘的占用容量大小情况:

[root@localhost ~]$ du -h sda,b.img
34M  sda.img
138M sdb.img

此时discard的好处显而易见,启用了discard功能的sda消耗的存储容量要比没有启用的sdb小得多。

参考链接:
[1]http://en.wikipedia.org/wiki/TRIM
[2]http://libvirt.org/formatdomain.html#elementsDisks
[3]https://github.com/ceph/ceph/blob/master/doc/rbd/qemu-rbd.rst#enabling-discardtrim
[4]https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/7-Beta/html-single/7.0_Release_Notes/index.html#sect-kernel-based-virtualization

以上是关于虚拟磁盘discard在qemu中的应用的主要内容,如果未能解决你的问题,请参考以下文章

虚拟磁盘discard在qemu中的应用

如何解决磁盘空洞问题

使用qemu-img创建虚拟磁盘文件

KVM管理

glance支持的磁盘格式类型

qemu-kvn中的virtio浅析