仮想マシンにおけるファイルシステム性能の比較
長年、Vagrantを使った仮想マシンベースの開発環境における最大のボトルネックは、ファイルシステムの性能でした。CPUによる差はわずかでほとんど気になりませんし、メモリが問題になるのは多数の仮想マシンを同時に動かしているときだけです。
昨日はほぼ一日をかけて、代表的なファイルシステムの仕組みをベンチマークして分析し、その結果をここで皆さんと共有します。
まずは結果の分析から始めます。多くの方にとって最も関心があるのはそこだと思うからです。テストの具体的な手法や使用したソフトウェア、生データは、この分析の後に掲載しています。
以下に示すすべてのグラフでは、何らかの方法でファイルの読み書きをテストしています。各グラフ内で読み書きされるファイルの合計サイズは固定です。Y軸はスループット(KB/s)、X軸は「レコードサイズ」、すなわち一度に読み書きするデータのチャンクサイズ(KB)を示しています。
テスト環境は、native、VirtualBox native、VMware native、VirtualBox shared folders(vboxsf)、VMware shared folders(vmhgfs)、そしてNFSです。「native」とある環境は、その環境でファイルシステムを単独で利用することを意味します。「native」はホストマシン上、「VirtualBox native」はVirtualBox仮想マシン内のルートデバイス上、といった具合です。NFSはVirtualBoxでのみテストしましたが、VirtualBoxとVMwareのどちらでも性能特性はほぼ同様になるはずだからです。
どのグラフでも、スループット(Y軸)が高いほど良い結果であることを意味します。
小さいファイルのシーケンシャルリード
最初は、64KBのファイルをさまざまなリード時のレコードサイズでシーケンシャルに読み取るテストです。小さなシーケンシャルリードが現実に使われる場面としては、アプリケーションのソースファイルを読み込んで実行したり、コンパイルしたり、テストしたりする場合などが挙げられます。

まず目を引くのは、小さなレコードサイズにおけるNFSのリード性能が驚異的だということです。これほどの性能を出すために、NFSは大規模な先読みやキャッシュを積極的に行っているのでしょう。なぜNFSが仮想マシン内のネイティブなファイルシステムを上回るのか、うまい説明が私には思いつきません。
ここではVMwareの共有フォルダがVirtualBoxの共有フォルダを圧倒しています。VirtualBoxの共有フォルダのリード性能はひどいの一言です。生データを見ると、VirtualBoxのスループットは一度も100MB/sを超えませんが、VMwareは常に500MB/sを下回ることがなく、ピークでは900MB/sを超えています。
興味深いことに、仮想マシン内のネイティブなファイルシステムが、ホストマシンのネイティブなファイルシステムを上回ることがあります。このテストではユーザースペースでのバッファリングを一切行わない生のreadシステムコールを使っています。ハイパーバイザーが仮想マシンからのリードに対してバッファリングを行っている可能性が非常に高く、ネイティブカーネルへのコンテキストスイッチが減ることで性能が向上しているのでしょう。この仮説は、freadのベンチマークの生データを見るとさらに裏付けられます。そちらのテストでは、ネイティブなファイルシステムが仮想ファイルシステムを常に上回っています。
大きなファイルのランダムリード
ここでは64MBのファイルのさまざまな箇所をランダムに読み取る際のスループットを、やはりさまざまなリード時のレコードサイズでテストしました。ファイルサイズは前回のテストの1000倍です。このような挙動は、ファイルシステムにアクセスするデータベースの読み取りなどで見られるかもしれません。

VMwareの共有フォルダとVirtualBoxの共有フォルダの差は、小さなシーケンシャルリードのときよりもさらに大きく開いています。VirtualBoxの性能はあまりに低く、グラフ上でもかろうじて見える程度です。今回もVirtualBoxのスループットは100MB/sを超えることがありません。一方VMwareは7GB/sでピークを記録しています。さまざまなテストケースを通じてVirtualBoxのスループットのばらつきが非常に小さいことから、VirtualBoxの共有フォルダシステム内のどこか一箇所のコードパスがボトルネックになっているのだと推測しています。明らかに何かが間違っています。
NFSはこのテストケースでは先読みの恩恵が得られないためか、それほど圧倒的ではなくなっています。それでも、他の選択肢と比べれば十分に優れた性能を示しています。
そして小さなシーケンシャルリードと同様に、ここでも仮想マシン内の方がホストの外よりも良い性能が出ています。これもハイパーバイザーが巧妙なバッファリングを行っているためと考えられますが、ホストマシンへの生のシステムコールではそうしたことができません。
小さいファイルのシーケンシャルライト
次に、小さいファイルへのシーケンシャルライトの性能を見てみましょう。これはセッション状態の保存や一時ファイルの作成、新しいソースファイルの書き込みといった状況を最もよく表しています。

まず目につくのは、こうしたライトにおいてNFSの性能がひどく悪いということです。ここではNFSが効果的なキャッシュを行う余地がほとんどないため、ネットワークのオーバーヘッド、ホスト側でのディスクへの書き込み、そして書き込み成功のackをVM側で待つまでのコストをすべて負担しなければなりません。なかなか厳しい結果です。
各種「native」なファイルシステムは非常に良い性能を示しています。ここでも仮想マシンがホストを上回っており、これはやはりハイパーバイザー側のバッファリングによるものと考えられます。
共有ファイルシステム同士では接戦ですが、このテストケースではVirtualBoxがVMwareを明らかに上回っています。
大きなファイルのランダムライト
最後に見るグラフは、大きなファイル(64MB)へのランダムライトをテストした結果です。大きなファイルのランダムリードのテストと同様に、これはデータベースがどの程度の性能を発揮するかを知る良い指標になります。

小さなシーケンシャルライトと比べて、ここで大きな違いはありません。ファイルが大きいためテスト環境間の差はより広がっていますが、それ以外は結果はほぼ同じです。
NFSはライトでは相変わらずひどい性能です。共有フォルダのライトではVirtualBoxが引き続きVMwareを上回り、ハイパーバイザーはホストマシンを上回っています。
ハイパーバイザーがホストマシンを上回るという点が、私にとって最も興味深いところです。このテスト結果は、ハイパーバイザーが性能のために同期書き込みについてごまかしていることをはっきりと示しています。これはPackerでも見てきたことと一致します。仮想マシンが正常にシャットダウンされなかった場合、コミットされたはずの書き込みが失われるのです。仮想マシン内でのfsync()は、データがホスト側に書き込まれたことを意味するのではなく、ハイパーバイザー内でコミットされたことを意味するに過ぎません。
総合分析
共有ファイルシステムに関して言えば、VMwareの方が求められる挙動を示しています。ウェブページの読み込みも、テストスイートの実行も、ソフトウェアのコンパイルも、いずれもリード負荷が非常に高い処理です。VMwareの共有フォルダはリード性能でVirtualBoxを圧倒しており、一方でVirtualBoxの共有フォルダのライト性能がVMwareを上回るといっても、その差はわずかです。
もしNFSを使える選択肢があるなら、使ってください。繰り返しになりますが、リード性能はライト性能よりもはるかに重要だからです。
ハイパーバイザーの読み書き性能は素晴らしいものです(ずるをしているからですが)。このデータを得られたことで、今後はネイティブなファイルシステムだけを使う新しいsynced folderの実装(rsyncを使う方法や、ホストマシンをNFSサーバーではなくクライアントとして使う方法など)により一層力を入れていこうと考えています。
よりすぐに役立つアドバイスとしては、仮想マシンを開発に使っているなら、可能であればデータベースのファイルを共有ファイルシステムの外に移してください。大きな性能向上が期待できるはずです。
最後に、これらの結果に大きな驚きはないと思っています。Vagrantは2010年からNFSのsynced folderをサポートしてきました。共有フォルダの性能が悪いことは早い段階で気づいていたからです。とはいえ、異なる挙動を示す確かなデータが得られたことは有意義ですし、各システムが内部で何をしているのかについて興味深い示唆も得られました。
記事をランダムに読む