Comparing Filesystem Performance in Virtual Machines

Mitchell Hashimoto

虚拟机文件系统性能对比

原文由 Mitchell Hashimoto 发布,订阅该博客

多年来,使用 Vagrant 搭建的基于虚拟机的开发环境,其主要瓶颈一直是文件系统性能。CPU 上的差异很小,几乎可以忽略不计,而内存只有在同时运行大量虚拟机时才会成为问题。

昨天我花了大半天时间对常见的文件系统机制进行基准测试和分析,现在在此与大家分享测试结果。

我会先从结果分析开始,因为这才是大多数人最关心的内容。具体的测试方法、所用软件以及原始数据,都可以在分析内容之后找到。

下面展示的每张图表都以某种方式测试了文件的读取或写入。每张图表中被写入文件的总大小是固定的。Y 轴是吞吐量,单位为 KB/s;X 轴是“记录大小”,即单次读写的块大小,单位为 KB。

测试环境分别为 native、VirtualBox native、VMware native、VirtualBox 共享文件夹(vboxsf)、VMware 共享文件夹(vmhgfs)和 NFS。“native”环境指的是在该环境中直接使用其自身的文件系统。“native”位于宿主机上,“VirtualBox native”位于 VirtualBox 虚拟机内的根设备上,以此类推。NFS 仅在 VirtualBox 上进行了测试,因为它在 VirtualBox 和 VMware 上的性能表现应该相近。

在所有图表中,吞吐量(Y 轴)越高越好。

小文件顺序读取

首先是 64 KB 文件的顺序读取测试,测试了不同读取记录大小下的表现。小文件顺序读取在实际场景中的一个典型应用,就是加载应用的源文件以进行运行、编译或测试。

首先映入眼帘的是,NFS 在小记录大小下的读取性能非常惊人。NFS 很可能为此进行了大量的预读和缓存。至于 NFS 为何能超越虚拟机原生的文件系统,我还没有一个合理的解释。

在这里,VMware 共享文件夹的表现完全碾压了 VirtualBox 共享文件夹。VirtualBox 共享文件夹的读取性能简直惨不忍睹。如果查看原始数据,你会发现其吞吐量实际上从未超过 100 MB/s,而 VMware 则从未低于 500 MB/s,峰值甚至超过了 900 MB/s。

有意思的是,虚拟机内部的原生文件系统有时反而比宿主机上的原生文件系统表现更好。本次测试使用的是不带任何用户态缓冲的原始 read 系统调用。很可能是 hypervisor 对来自虚拟机的读取做了缓冲,从而减少了向原生内核进行上下文切换的次数,获得了更好的性能。查看 fread 基准测试的原始结果数据进一步印证了这一推测。在那些测试中,原生文件系统每次都胜过了虚拟机内的文件系统。

大文件随机读取

这项测试衡量的是随机读取 64 MB 文件中不同部分的吞吐量,同样测试了不同读取记录大小下的表现。该文件比上一项测试中的文件大了 1000 倍。这种行为模式在处理会落到文件系统上的数据库读取时可能会出现。

与小文件顺序读取相比,VMware 共享文件夹和 VirtualBox 共享文件夹之间的差距被进一步拉大。VirtualBox 的表现太差,甚至在图表上都几乎看不到。同样,VirtualBox 的吞吐量峰值从未超过 100 MB/s。而 VMware 的峰值则达到了 7 GB/s。由于 VirtualBox 的吞吐量在各种测试用例中波动极小,我推测 VirtualBox 共享文件夹系统中存在某条单一的热点代码路径限制了性能。显然他们在某些地方做错了。

NFS 的优势不再那么明显,很可能是因为在此测试场景下预读带来的好处无法体现。不过,相比其他选项,NFS 的表现依然非常出色。

和之前的小文件顺序读取一样,我们仍然看到虚拟机内部的性能优于外部。同样,这可以归因于 hypervisor 做了巧妙的缓冲,而对宿主机直接发起的原始系统调用则无法享受这种优化。

小文件顺序写入

我们来看看小文件顺序写入的性能。这最能体现存储会话状态、临时文件或写入新源文件等场景。

首先注意到的是,NFS 在这类写入场景下的性能非常糟糕。NFS 在此几乎无法做任何有效的缓存,因此你必须承担全部的开销:网络开销、在宿主机端写入磁盘,以及最后等待虚拟机收到写入成功的确认。代价可不小。

各种“原生”文件系统的表现都非常好。同样,虚拟机的性能超过了宿主机。这同样可以归因于 hypervisor 中的缓冲机制。

共享文件系统的表现比较接近,但在此测试中 VirtualBox 明显优于 VMware。

大文件随机写入

我们要看的最后一张图表是对大文件(64 MB)进行随机写入的测试结果。和小文件随机读取测试一样,这项测试也能很好地反映数据库的性能表现。

这里的结果与小文件顺序写入相比其实没有太大区别。由于文件较大,不同测试环境之间的差距更大,但除此之外,结果基本一致。

NFS 在写入方面依然表现糟糕。VirtualBox 共享文件夹在写入上继续优于 VMware,而 hypervisor 的性能则超过了宿主机。

hypervisor 性能超过宿主机是我觉得最有意思的一点。这项测试的结果清楚地表明,hypervisor 为了性能一定在同步写入上“撒了谎”。这也印证了我在 Packer 中观察到的现象:如果虚拟机没有正常关机,已提交的写入就会丢失。在虚拟机中调用 fsync() 并不意味着数据已经写入到宿主机,而仅仅表示数据已在 hypervisor 层面提交。

总体分析

就共享文件系统而言,VMware 的表现更符合需求。加载网页、运行测试套件和编译软件都是以读取为主的操作。VMware 共享文件夹的读取性能完全碾压 VirtualBox,而 VirtualBox 共享文件夹的写入性能仅比 VMware 略好一点。

如果可以选择使用 NFS,就用它。同样,读取性能远比写入性能更有价值。

hypervisor 的读写性能非常出色(因为它们作了弊)。有了这些数据,我肯定会把更多精力放在 Vagrant 中仅使用原生文件系统的新同步文件夹实现上(例如 rsync,或是将宿主机作为 NFS 客户端而非服务端)。

不过,更具现实意义的建议是:如果你使用虚拟机进行开发,请尽可能将数据库文件移出共享文件夹。你很可能会看到巨大的性能提升。

最后,我认为这些结果并没有什么巨大的意外。自 2010 年以来 Vagrant 就一直支持 NFS 同步文件夹,因为我们很早就意识到共享文件夹的性能很差。但能够有一些实打实的数据来展示不同系统的行为差异,还是很有价值的,也能让我们更深入地了解每个系统背后的运作机制。

本文章由 muse-spark-1.2-contributor 进行翻译

评论