VMware ESXにおけるCPU管理(1) - ゲストOSは自分が完全にCPUを管理していると思っている

CPUの性能がクロックの向上ではない指標で測られるようになってからすでに数年が経過しています。2004年にIntelPentium4の4GHzのリリースを中止して以来、IntelのCPUはいまだに2GHz台〜3GHz台のクロック性能に留まっています。しかしその後現在に至るまでの間、CPU性能に進化がなかったのかといえばご存じの通りそんなことはありません。半導体の集積度が18-24ヶ月で倍増するというムーアの法則は未だにおおよそ維持されており、マルチコア化を筆頭に、NUMAやQPIといったメモリ関連の革新、CPUレベルでの仮想化支援機能の実装などなど、時代の流れに即してCPUは「単純にクロック性能だけを伸ばす」状況から、メモリやチップセットなどのハードウェア的な面と命令セットや制御アルゴリズムなどのソフトウェア的な面の両面で「総合的な性能を伸ばす」状況へと変化してきました。これらの結果、CPUはクロック性能は伸びていなくても各種ベンチマークなどの性能指標としては継続的に向上を続けています。

このようにCPU進化の方向性が変化したことの恩恵を最も得たソリューションのうち代表的なものの1つが仮想化技術といえます。逆説的には、CPUがクロック性能の向上から舵を切ったからこそ、現在の仮想化技術の爆発的な普及、一般化が進み、さらにはクラウドの時代へと続く流れが始まったと言えるのかもしれません。

CPU性能において、クロックの向上はいわばスケールアップ型の進化といえます。まったく同じ処理をシーケンシャルにこなすのであれば、クロックの向上こそが性能速度の向上に繋がります。CPUのクロック性能が2倍になることによって処理性能が2倍となるのであれば、1台のサーバでは同じ処理を半分の時間で、もしくは2倍の処理を同じ時間で捌くことができるようになる「性能向上」を得ることができます。

対して、CPUの新しい進化の方向性、その中でも特にマルチコア化はスケールアウト型の進化といえます。考え方としては同じ処理を動じ並列的に処理することによって性能速度を向上させるやりかたです。クロック性能がそのままだったとしても、処理を並列的に実行することができるのであれば、計算サイクルをまわす論理的な単位(コアやスレッド)が増えれば増えるほど「性能向上」を得ることができます。

…ではOSやアプリケーションにおける処理を並列化すればいいかといえば、ソフトウェアの処理はそうは単純ではありません。たとえば、Aという処理の結果を使用するBという処理は、Aの処理が終わらないと実行できないため、結局はA→Bという順序で処理を行う必要があり、AとBを同時に処理するようにすることはできないわけです。いわゆるマルチスレッドに対応したアプリケーションの開発は簡単ではなく、さらに「並列処理の性能をフルに使い切る」ようなアプリケーションは一般的なビジネスアプリケーションではそうはありません(CPUの並列処理性能があればあるほどよい処理としては、3DレンダリングHadoop的な並列処理、HPC的な計算処理などがあるでしょうか)。
たとえば8コアx2ソケットで16コア、HTを使用すれば論理CPU数としてはさらに倍の32。こんなに多くのCPUリソースを単一のOS、単一のアプリケーションだけで使い切ることは難しい。なのであれば、このリソースを「それぞれはシングルスレッドであっても」複数のOS、複数のアプリケーションで共有して使用するようにしてしまえばよいという発想に基づいたソリューション、それが仮想化ということになるわけです。単一のOS上でマルチスレッドのアプリケーションを使用する場合と比較すると、ムダな処理は多い(それぞれのゲストOS、それぞれのミドルウェア、仮想環境の管理に用いられるリソースなど)わけですが、そうしたオーバーヘッドがあったとしても、仮想化による統合は「ハードウェアリソースをより使い切る」という面で効果が得られるようになったわけです。

たとえばシングルスレッドで処理を行うアプリケーションであったとしても、10同時に実行することができれば10スレッド処理と同じことになります*1。仮想化、中でもハードウェア環境の仮想化*2が大きく普及した要因としては、CPUの処理性能向上の方向性とともに、OSやアプリケーションにおいて「一切の修正・変更なく」物理ハードウェアのリソースを効率的に使うことができるようになるという「とっつきやすさ」もあったでしょう。

CPUスケジューラの役割は実行されるコンテキストに対して最適な処理が行われるようにCPU計算時間を割り当てることです。1つの物理サーバを占有的に使用して動作しているOS環境の場合、その割り当て対象となるのはプロセスやスレッドと呼ばれる実行単位であり、ESXホストの場合はワールドと呼ばれる単位となります。ワールドはESXホストにおけるプロセスと考えておおよそ問題はありませんが、仮想マシン側から見ると1つのワールドは1つのvCPUにおおよそ該当します。

ESXにおけるCPUスケジューラはVMkernelにおいて動作しており、求められている役割はおおよそ他のWindowsLinuxなどといった汎用的なOSとそれほど違いはありません。しかしCPU計算時間の割り当て対象となるワールドの向こう側にはゲストOSが存在しており、そのゲストOS自身は「自身がCPUリソースを完全に制御している」という前提で動作する様に設計されていることを踏まえたCPU計算時間の割り当てを行う必要があります。ゲストOSはさらに自身の処理やアプリケーションに対してCPUリソースを割り当てる処理を行うわけですから、大前提となるHypervisorにおけるCPUスケジューラが適切なCPU計算時間の割り当てを行うことができていなければ、どんなにゲストOSが頑張っても期待するパフォーマンスは望めません。

仮想化環境では、物理的なCPU数を超えて、仮想マシンに対して仮想的なCPUの割り当てを行うことが一般的です(たとえば、4つの物理CPUを搭載したハードウェア環境で、1つの仮想CPUを割り当てられた仮想マシンを同時に6台稼働させる、など)。しかし仮想マシン上で実行されているゲストOSは自身が仮想マシン上で実行されているとは意識せずに動作しているため、CPU割り当てのスケジューリングはHypervisorにおける最も重要な役割の1つです。物理的なハードウェア環境に用意された多コアのCPU資源をどのように管理し、そして全体としてはさらに多くの論理CPUが構成された仮想マシンに対してどのように公平に、かつ効率的にCPUリソースの割り当てを行うのか。このシリーズを通じて仮想化におけるCPU、特にCPUリソースのスケジューリングについて見ていきたいと思います。

*1:厳密には、オーバーヘッドの差がありますから同じとは言えないのですが…

*2:仮想マシンを提供する仮想化技術。VMware vSphereやHyper-VXenKVMなど。