KVMを使う(ディスク性能編その2)
今回はKVMでアタッチしたディスクのパフォーマンスについて、read/write性能を計測してみましょう。前回のディスク性能編では新規に作ったqcow2のパフォーマンスが悪いというお話をしました。今回もrawとqcow2の違いに注目したいのですが、拡張時のオーバーヘッドの影響を排した状態でのread/writeを比較したいと思います。また、KVMのディスクに対して指定できる別のパラメータについても触れてみたいと思います。
qemuの-driveオプション
KVM(qemu)によって仮想マシンを起動するとき、ディスクのアタッチは通常以下のように行います。
host# qemu-system-x86_64 -hda disk.img ...
このオプションについてqemuのマニュアルを読むと以下のような記述があります。
Instead of ‘-hda’, ‘-hdb’, ‘-hdc’, ‘-hdd’, you can use:
つまり-hda等のイメージファイルを指定するオプションは、-driveの短縮形であるということです。この-driveオプションには興味深いパラメータがたくさんあるのですが、今回はcacheオプションを取り上げます。
‘cache=cache’
つまり、ホストOSがイメージファイルにアクセスするときに使うキャッシュモードを、「無効」「writeback」「writethrough」のうちから指定することができるのです。指定しない場合、デフォルトはwritethroughにセットされます。
ディスクキャッシュは、速度の遅いHDDへのアクセスを改善するために使われます。キャッシュは使っていないメモリ領域を動的に確保して行います。メモリに蓄えられたデータは非常に高速にアクセスできます。この有無の違いが、VM上でどの程度のパフォーマンスの差になって現れるか、確かめてみましょう。
なお実験に使用したサーバ環境は以下の通りです。
CPU | Xeon 3060 2.4GHz |
メモリ | 2GB |
HDD | 500GB (250GB×2をRAID0で構成) |
OS | Fedora 12 |
ゲストCPU | 1ユニット |
ゲストメモリ | 1.2GB(1228MB) |
ゲストHDD | 100GB、各種フォーマットおよびcacheモード |
hdparmを使ったread性能の測定
KVMではブートディスクの他に3つのディスクをアタッチできますから、3つのキャッシュモードをそれぞれ指定したイメージファイルをアタッチしてやることにします。
host# qemu-system-x86_64 -hda vm01.img \
-drive index=1,media=disk,cache=writethrough,file=raw1.img \
-drive index=2,media=disk,cache=writeback,file=raw2.img \
-drive index=3,media=disk,cache=none,file=raw3.img \
...
これでゲストOSからは、/dev/sdb = writethrough、/dev/sdc = writeback、/dev/sdd = noneのモードで利用できるようになります。
これらのブロックデバイスに対してhdparmを実行します。hdparmはディスクのパラメータの設定プログラムですが、-tオプションを使うと読み込み性能を測定してくれます。数秒のインターバルをおいて繰り返し実行するスクリプトを書き、40回分の数値の変化をグラフにプロットしてみます。なおループに入る前にホストOSでページキャッシュをクリアしています。

グラフからはキャッシュが有効になっている場合に成績がよくなっていて、ホストのHDD性能を超えた速度で読みこめていることが分ります。hdparm -tのテストはキャッシュを使わずにディスク読み込みをするのですが、ゲスト上のhdparmはキャッシュを回避しているつもりでもKVM(qemu)がホスト上のディスクイメージにアクセスするときにキャッシュしているため、速度が向上しているのです。
このキャッシュの効果はqcow2フォーマットでも同じく現れます。

グラフには奇妙な周期が出ていますが、原因がはっきりしません。Linuxのページキャッシュにはdirty_writeback_centisecs (=500)やdirty_expire_centisecs (=3000)のようなエイジングタイマがあるようなので、これが振動の原因かもしれません。まあいずれにせよ、ホストのキャッシュが効いていることが見て取れると思います。
ゲストOSでの性能低下の割合は、noneとHOSTのデータを比較すれば分ります。ここではキャッシュの効いていないデータが表れているからです。40回分の平均値で両者を比較してみます。
HOST | raw-none | qcow2-none |
103.84MB/s | 78.23MB/s | 94.78MB/s |
比率にすると、HOSTに比べてrawフォーマットでは75%、qcow2では91%の速度となっています。
ddを使ったwrite性能の測定
次にddを使って書き込み性能を測定してみましょう。実験環境はhdparmと同じで、/dev/sdb、c、dの3つのディスクをフォーマットしてマウントし、ddコマンドで書きこみ可能な状態にします。コードはごく単純で、以下のようにddコマンドで256MBのファイルを作成します。
guest# dd if=/dev/zero of=/mnt/drive-b/write-test.tmp bs=1M count=256
これを40回繰り返すスクリプトにして、3種類のキャッシュモードごとに測定してみます。

ddコマンドによるテストではキャッシュをクリアせず、同じファイルに何度も書き込みをしています。したがってゲストOSのページキャッシュは有効になっています。まず気付くのは、writebackのデータのばらつきが非常に大きいことです。100MB/sと300MB/sをいったりきたりしていて、3倍もの性能差が現れています。他のwritethroughやキャッシュなしでも多少のばらつきがあり比較が困難だったので、グラフには10区間移動平均をプロットしてみました。
全体としてみると、素のホストでの測定値に比べて性能は半分程度と非常に低いことが分ります。メモリ量の違いはあるものの、データサイズは256MBなのでキャッシュ効果に差があるとは考えにくく、この差がKVM自体のオーバーヘッドであると推測できます。
qcow2フォーマットはどうでしょうか。

qcow2ではわずかに数値が悪くなっている他、ばらつき具合が多少減っているようです。
これらの結果をみると、KVMのcacheオプションにはあまり効果がないように思えます。それどころかキャッシュ無効時に比べて性能のばらつきが大きく、運用時にキャッシュオプションをONにすることに抵抗を感じます。思ったほど性能差が出ないことについては、ゲストOSのページキャッシュの効果に隠れているのかもしれません。またオプションがきちんと有効になっていないのでは?と勘繰りたくなるのですが、readのテストではきちんと差異が出ていたので、有効になっていることは間違いないと思います。
ホストとゲストとの性能比は大きく、40%~50%程度に落ちています。
キャッシュの状態をもっと調べるために、データサイズを1GBに大きくしてみましょう。同じようにグラフをプロットしてみます。

ファイルサイズが大きくなるとキャッシュの効果が減ります。ホストのデータ(平均117MB/s)を見る限り、だいたいキャッシュ効果はゼロになっていると判断できます。この状況下ではもっとも成績がよいのがキャッシュ無効の65%、writebackでは40%、writethroughでは30%に性能が落ちてしまいます。

qcow2フォーマットでは若干の改善が見られます。傾向としてキャッシュ無効が成績が良いのは変わりませんが、全体として性能がよく見えます。ホストのHDDと比較すると、キャッシュ無効では約70%、writeback、writethroughでは55%となりました。
Bonnie++ベンチマーク
ディスクベンチマークのひとつ、Bonnie++でも試しておきましょう。Bonnie++はディレクトリを指定するとファイルの読み書きをテストして表にまとめてくれます。ファイル生成速度などのファイルシステムに関するテストも行ってくれるのですが、今回はread/writeの結果だけを利用しています。
Bonnie++による測定は、7回の測定を行い、最大値と最小値をカットした5回分のデータを平均しています。Bonnie++による測定ではhdparmやddのときのような大きなばらつきは見られなかったので、5回の試行で十分と判断しています。
hdparmやddを使ったテスト同様、2つのフォーマットと3つのキャッシュモード、さらにホストサーバにおいて測定を実施し、グラフにしてみます。

おおざっぱに比較してみると、rawの方がqcow2より若干優位であると分ります。Bonnie++によるテストでも、キャッシュモードが無効である方がデータがよい傾向は変わりません。唯一、writethrough設定時のread性能がずば抜けていますが、なぜこうなるのか原因が分りません。本格的に追及するにはKVM/qemuのコードを追いかけてみるしかないようです。
ホストHDDとの性能比まとめ
グラフによる感覚的なデータとは別に、数値を平均して性能比をまとめておきます。平均値を算出するに当たっては、キャッシュの効果をかんがみて40回の試行のうち後半の20回のみを対象にしています。
HOST | raw | qcow2 | |
through | back | none | through |
hdparm read (MB/s) | 103.8 | 275.5 | 274.9 |
対HOST比 | 1.00 | 2.65 | 2.64 |
256MB dd write (MB/s) | 557.4 | 252.7 | 244.4 |
対HOST比 | 1.00 | 0.45 | 0.44 |
1GB dd write (MB/s) | 117.4 | 34.6 | 45.6 |
対HOST比 | 1.00 | 0.29 | 0.39 |
Bonnie++ read (MB/s) | 130.9 | 134.1 | 59.2 |
対HOST比 | 1.00 | 1.02 | 0.45 |
1GB dd write (MB/s) | 79.9 | 34.4 | 43.8 |
対HOST比 | 1.00 | 0.43 | 0.55 |
考察
まずrawフォーマットとqcow2との比較について考えてみます。両者の間では、変換のオーバーヘッドを考えればrawフォーマットの方が有利であると思われ、数字にも僅かながらその差が出ていると思います。省スペースが売りのqcow2ですが、領域拡張時のパフォーマンス劣化は相当にひどく、10MB/s以下になってしまうこともあることから、あまりメリットはないと言わざるをえません。やはり非スパースファイルとして用意したrawファイルがパフォーマンスはベストであると考えます。
cacheオプションはnone、writeback、writethroughのどれがいいのでしょうか。readのテスト結果を見る限りはデフォルト のwritethroughでよさそうな気がしますが、writeの結果からはあまりよい判断ではないと思われます。なによりもcacheオプションの動作は不可解な結果が多く、KVMの対応状況は十分といえない状況にあるようです。今後どのように開発が進んでいくのか注視していく必要があるでしょう。
ディスクのパフォーマンスの調査で私が一番気にしているのは、仮想化のオーバーヘッド、すなわちホストサーバに対してゲストの性能がどれぐらい劣化するのかということです。仮想化ソフトウェアは余裕のある資源を効率よく分散することでメリットを生み出すものですが、仮想化のオーバーヘッドによってその余裕が無くなってしまっては意味がありません。そういう意味では、今回の結果には大いに不満が残ると言わざるを得ません。ただし一点注意すべきなのは、使用したサーバが比較的古く、VT-xはサポートしているもののVT-dは未対応ということです。先日導入したPRIMERGYはもちろんVT-d対応ですので、どれほどのパフォーマンスを発揮してくれるのか、ぜひとも試してみたいところです。
今回のテストでは、特にチューニングのテクニックは使わず、インストールしただけの環境で実施しています。本来は状況に合わせてメモリやキャッシュや様々なパラメータを調整し始めるところなのですが、それには利用用途や環境をある程度絞り込まなければいけません。パブリックなサービスではこれが難しく、ベストなチューニングを探る試行はまだまだ続きそうです。
参考文献
著者

1998年、エス・アール・エス有限会社入社の後、合併を経てさくらインターネット株式会社へ。技術部部長、取締役を経て、2009年7月に研究所所長就任。
会社設立時より技術担当。レンタルサーバ組み立てから始め、データセンタ構築、バックボーン構築、オンラインゲームプロジェクトの技術運用などを歴任。2018年まで、クラウドサービスのマネージャを担当。
初代所長に任命された割に研究者としての実績はなく、論文は学生時代に書いたきり。他、数冊の書籍の執筆経験がある。
最近の興味の中心は、サーバの仮想化、クラスタリングなど。