0x01 前言

最近我的服务器在测试中发现有许多IO警告,分析日志发现虚拟机的IO都很低,磁盘写入速度只有5m/s到20m/s。在审查配置后发现没有修改默认的缓存模式。

0x02 模式

在centos7中,有以下五种缓存模式:

  1. none:虚拟机的IO不会被服务器缓存,但有可能被物理磁盘或阵列控制器缓存
  2. writethrough:虚拟机的IO缓存在服务器,而且数据立即刷新到物理磁盘中
  3. writeback:虚拟机的IO缓存在服务器
  4. directsync:和writethrough类似,但虚拟机的IO会绕过服务器的页面文件
  5. unsafe:服务器会缓存所以来自虚拟机的IO,同时忽略来自虚拟机的disk sync请求
  6. default:如果不手动指定缓存模式,那么将会使用默认的缓存模式

在配置虚拟机时如果不指定缓存模式,那么writethrough将作为默认的缓存模式。不同的qemu-kvm可能会有不同的默认缓存模式,想查询kvm服务器中默认的缓存模式,可以使用以下方式:

#输入以下命令
[root@server ~]# qemu-img -h

#在返还的内容中找到以下内容
  'cache' is the cache mode used to write the output disk image, the valid
    options are: 'none', 'writeback' (default, except for convert), 'writethrough',
    'directsync' and 'unsafe' (default for convert)

我的服务器以writeback作为默认的缓存模式。如果服务器的raid缓存没有电池供电,那么默认的缓存模式很有可能为writethrough。

0x03 安全

数据安全是第一位,如果选用缓存模式不慎,极有可能会导致数据丢失。下图为缓存模式IO示意图:

none与writethrough比writeback有较高的安全性。

根据上图,writeback模式下,来自虚拟机的IO会被写入服务器的页面文件中。不建议在raid缓存没有电池的情况下使用writeback模式,服务器一旦断电,还在缓存中的数据将会丢失。

writethrough的安全性最高,因为是直接写入到物理磁盘中,但同时也会损失掉一部分性能。

0x04 性能

下面我用同一个虚拟机分别测试以上五种缓存模式,测试所使用的物理磁盘的最高速度为330m/s,由4块2TB硬盘组成raid10,阵列卡有512M缓存并带有电池。以下是虚拟磁盘的信息:

[root@server ~]# qemu-img info /disk2/kvm/images/test_images/io_test_1.img 
image: /disk2/kvm/images/test_images/io_test_1.img
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 2.0G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true

使用以下命令进行测试:

dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync

每一个模式将测试5次,以下是缓存模式为none的结果:

[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.8543 s, 157 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.83386 s, 184 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.40407 s, 199 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.25176 s, 204 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 4.94201 s, 217 MB/s

以下是缓存模式为writethrough的测试结果:

[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 7.44214 s, 144 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.90264 s, 182 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.85222 s, 183 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 4.9245 s, 218 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.6933 s, 189 MB/s

以下是缓存模式为writeback的测试结果:

[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.30278 s, 170 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.19481 s, 173 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.06488 s, 177 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.38592 s, 168 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.20265 s, 173 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.61563 s, 191 MB/s

以下是缓存模式为directsync的测试结果:

[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.10843 s, 210 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.92729 s, 181 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.67731 s, 189 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.69663 s, 188 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 5.46388 s, 197 MB/s

以下是缓存模式为unsafe的测试结果,以为数据并没有真实写入硬盘,所以速度非常惊人:

[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 1.16476 s, 922 MB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.96282 s, 1.1 GB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.915939 s, 1.2 GB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.814352 s, 1.3 GB/s
[root@io-test-1 disk2]# dd bs=1M count=1024 if=/dev/zero of=1gb.test conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.897145 s, 1.2 GB/s

以下是五个缓存模式速度测试结果图标:

按预想,应该是writeback的性能略高于除了unsafe的其他模式,但我服务器上结果却是none的性能比较好。这一结果也有其他因素影响,例如我服务器正在运行的其他虚拟机和虚拟磁盘的其他参数。

0x05 配置

在使用virt-install安装虚拟机时,可以通过以下参数为虚拟磁盘指定缓存模式:

cache=writethrough

例如:

--disk path=/disk2/kvm/images/test_images/io_test_1.img,size=20,bus=virtio,cache=writethrough

如果已经安装好虚拟机,想修改缓存模式,则需要修改配置文件:

#打开配置文件
[root@server ~]# virsh edit io_test_1

#修改以下内容
<driver name='qemu' type='qcow2' cache='writeback'/>

然后重新启动虚拟机即可。

0x06 结语

数据的完整性肯定要比性能更重要,请慎重选择缓存模式。在这里推荐使用none、directsync和writethrough。