虚拟机存储IO的那点事

随机IO vs 顺序IO

一般90%以上的虚拟机都是随机IO模型,用户交互类应用,如桌面,Web,它们的存储IO在Hypervisor看来都是随机的,这主要是因为我们常见的文件格式如jpg, png, exe, elf一般都采用了元数据+数据的模式,应用程序经常需要来回移动文件指针读写文件中不同的部分,现代多核心多任务的操作系统会导致更多这样的并发任务,进一步加强了这种随机性。

顺序IO模型的典型应用比较少,据我目前所知,大数据应用是其中之一,比如hdfs一般都以很大的block size以数据流的方式读写大文件。

读缓存 vs 写缓存

随机io会导致更多的cache miss,在此情况下,读缓存(write through)不仅不会带来任何性能加速,反而还会导致额外的内存复制和上下文切换。

从可靠性的角度看,虚拟化一般不会采用写缓存(write back)。如果使用写缓存,在虚拟机中返回成功的写请求其实仅仅只是存在hypervisor的内存中,一旦主机重启或者掉电,这部分数据就会丢失。除非用户能保证他们的虚拟机可以承受数据丢失,否则我们尽量避免使用write back。

同步IO和异步IO

同步IO使用read/write调用,这些调用是阻塞的,为了保障主进程不被阻塞,以及能获得更大的IO吞吐,通常会使用多个IO线程。异步IO一般使用io_submit内核调用,它是非阻塞的,可以在一个线程内通过提交更多的IO,有利于IO合并算法,同时,对于IO密集应用,异步IO会节省更多的线程上下文切换开销,另外,io_submit会强制使用O_DIRECT的透写参数绕过缓存,所以能更好的适应随机IO模型,下面两幅图对比了同步IO和异步IO的系统处理流程:

同步IO读写流程

异步IO读写流程

KVM虚拟机的IO线程

几年前还是机械硬盘时代,单盘的容量虽然每年都能翻一番,但是读写性能特别是随机读写性能却是十年如一日,即使是15k转速的SAS磁盘,单盘仅仅100-200 IOPS,如今的NVME磁盘,随机读性能到100k-200k IOPS都不算个事。较早版本的QEMU(KVM的设备模拟程序)只有一个IO线程,这对于早期处理只有数百IOPS的虚拟机已经足够了,但是对于数十万IOPS的新介质,即使把一个CPU完全跑满,也处理不过来,因此,QEMU社区花了好几年的时间,历经好多版本,终于能够让IO处理能够完全脱离主线程,跑在多个不同的线程里面,充分利用现代多核处理器的能力,这个特性最早叫做dataplane,现在好像也叫iothread。

虚拟机配置

虚拟机磁盘sda配置

disk type='block':这个磁盘的后端是一个块设备,可以用lvcreate命令创建;这个参数也可以用type='file', 说明后端是一个文件,但是在生产环境中,逻辑卷的可靠性一般要高于文件系统,所以我更喜欢用block。

driver type='qcow2':KVM的磁盘格式默认为QCOW2, 我们一般从操作系统厂商下载的云镜像的格式也都是这个格式,它最大的好处是可以支持磁盘瘦分配(thin provisioning)。

driver cache=’none':使用无缓存模式(O_DIRECT)打开文件,这个参数还支持writethrough和writeback,对于随机IO 应用,建议使用none, 对于顺序IO应用,可以使用writethrough。

driver io='native':设置native,QEMU会调用异步io_submit来提交IO; 设置为threads,QEMU会最终调用pread/pwrite同步提交IO。

iothreads配置

iothreads:指定用4个独立的线程处理磁盘IO。

iothreadpin:将指定的iothread绑定到指定的cpu上运行。

https://segmentfault.com/a/1190000005981794

猜你喜欢

转载自blog.csdn.net/u014022631/article/details/82746956