VMware ESXにおけるCPU管理(3) - CPU同期スケジューリング

(1) - ゲストOSは自分が完全にCPUを管理していると思っている
(2) - CPUスケジューリングは色々
…の続き。

ちょっとおさらいっぽいことを書いてから、今回のテーマに。

前回のエントリーで書いたように、ESXはCPUスケジューリングアルゴリズムとして"Proportional Share-Based Algorithm (共有比例比率に基づくアルゴリズム)"という方式を採用しています。この方式とLinux/UNIXにおけるCPUスケジューリングアルゴリズムの最も異なる点は「スケジューリングにおける優先度の決定方法」です。

Linux/UNIXのCPUスケジューリングアルゴリズムにおいては、プロセスの優先度はユーザによって構成されます(nice値)。重要なプロセスに対して優先度を高く設定することにより、他のプロセスよりも優先的にCPUリソースが割り当てられるようになります。対して、ESXのCPUスケジューリングアルゴリズムでは、優先度はリソースの消費量および割当量に基づいて動的に再調整されます。ユーザはリソースパラメータによってリソース割り当て優先度を調整することができますが、実際のCPUリソース割当における優先度は、仮想マシンごとのワークロード状態などの様々な要素に依存して調整されます*1。シェア値による優先度の度合いは、CPUリソースの割当時間の比率として設定されます。

このESXのCPUスケジューリングにおける共有比例比率に基づくアルゴリズムの採用は、Linux/UNIXなどにおける一般的な優先度スケジューリングアルゴリズムと比較して、いくつかのメリットが得られます。

第1のメリットは、仮想マシンごとに異なるシェア値を割り当てることによって、より柔軟にCPUリソースの割り当て時間の配分を制御することが可能となる点です。仮想マシンAと仮想マシンBを比較して、仮想マシンAが2倍のシェア値を割り当てられている状況においてCPUリソースに調停が必要な状況(割り当てるCPUリソースに余裕がない状況)となった場合、仮想マシンAは仮想マシンBと比較して2倍のCPU時間の割当を受けることができます。Linux/UNIXにおける優先度スケジューリングアルゴリズムでは、優先度の設定がCPU割当時間とは直接結びついていないため、このような制御を行うことは難しいといえます。

第2のメリットは、CPUリソースを階層化されたグループに対して調停することが可能となる点です。個別の仮想マシン単位だけではなく、仮想マシンをグループ化した「リソースプール」に対するリソースの割当を制御することができます。リソースプールは階層化が可能*2であり、さらに親階層からのリソースの融通の可否も構成できるなど、仮想マシン自体に設定されたシェア値と合わせてかなり柔軟な比例比率の制御が可能となっています*3

リソース管理において階層化が可能である点は重要です。グループ単位でリソースを配分し、各グループに割り当てられたリソースについては自由に使用可能とさせたい場合などでは、個別の仮想マシン単位だけでのシェア値の構成では管理することはできません。仮想マシン台数の増減や、仮想マシンのリソース使用状況、さらにはESXホストとしてのリソースの使用状況などを踏まえて動的にリソースの割当を管理することができるアルゴリズムは、仮想化HypervisorにおけるCPUスケジューリングアルゴリズムとしては非常に重要な機能といえます。

さて、今回のエントリーでは話を1つ進めて、マルチプロセッサ構成の仮想マシンにおけるCPUの同期スケジューリング制御について見ていきたいと思います。

■同期スケジューリングとは

まずは、なぜマルチプロセッサ構成の場合、CPUの同期スケジューリングが必要となるのでしょうか。それは同期スケジューリングはスレッドもしくはプロセスのセットに対して、時間当たり実行を最大化させることができるからです。マルチスレッドに対応したプログラムにおいて実行される一連のスレッドもしくはプロセスは、相互に頻繁に同期をとる必要があり、同期処理を行わないと実行性能に遅延が発生してしまうためです。たとえば、他のスレッドからのシグナルの待ち状態となってしまっているスレッドの発生は、それらのスレッドを同時に実行することにより待ち時間を減少させることができます。そのため、マルチプロセッサ構成をサポートするOSでは一般的に、CPUリソースを同期スケジューリングする仕組みを持っています。

このように、OSはすべてのCPU処理において同期された処理を必要とします。もし同期された動作ができなかった場合には、OSにおけるWatchdog Timerがエラーを検出し、割り込み要求により処理を停止させます。そのため、ESXホストはゲストOSにおけるCPUの同期処理を維持するために、CPUリソースの割当制御において同期スケジューリングを管理しなければなりません。ESXにおけるCPUスケジューラは、マルチCPU(vSMP)構成の仮想マシンに対するCPUスケジューリングのために "Relaxed Co-Scheduling" (緩やかな同期スケジューリング) 機能を実装することにより、各個別の仮想マシン単位についてはCPUリソースの同期処理が可能となるように制御します。この仕組みにより、仮想マシン上でゲストOSは正常に、かつ高いパフォーマンスで実行できるようになります。

ESXホストにおける "Relaxed Co-Scheduling" (緩やかな同期スケジューリング)の仕組みについては、こちらのVMwareウェブサイトのページ"Co-scheduling SMP VMs in VMware ESX Server"に詳細な情報が掲載されています(ただしこの資料は2008年のものです)。

■ESXホストにおける同期スケジューリングの制御

通常、OSは自身が管理しているすべてのCPUが常に同一の速度で処理を行うと仮定しています。これは、OSが直接物理CPU(pCPU)を管理している環境においては正しい仮定です。しかし、仮想化環境においてはpCPUリソースはHypervisorによって管理されており、仮想マシンに導入されたゲストOSが認識するCPUはHypervisorによって抽象化された仮想CPU(vCPU)となります。vCPUはpCPUからタイムスライスで切り出された存在であり、ゲストOSは占有していると考えているvCPUに紐付いているpCPUは複数のVMによって共有されて使用されている可能性があります。

ある1時点においては、vCPUはスケジュールされているかもしれませんし、スケジュールされていないかもしれません。また、CPUリソースの確保に成功するかもしれませんし、他の処理によってリソース待ちの状態となってしまうかもしれません。そのため、vCPUに対する同期スケジューリングの仕組みがなかった場合、マルチプロセッサ構成の仮想マシンに構成されたvCPUは制御された動作を行うことはできなくなってしまいます。

以下では「ズレ(スキュー)」を、複数CPUが構成されたマルチプロセッサVMにおける実行ステータスのズレという意味で使用します。

vCPUにおけるズレは、ゲストOSにおいて実行されているソフトウェアの前提(=OSによって占有的に管理され、CPU同期スケジューリング制御されている環境において実行されていること)に背くこととなります。大きなズレの発生はパフォーマンスに問題を引き起こし、仮想CPUを使用する処理の失敗につながる可能性があります。

まずはズレのパフォーマンスに対する影響について考えてみましょう。ゲストOSは通常、CPU間の同期にスピンロックを使用します。もし現在vCPUがロックされているためにスケジュールできない場合、ロックが解除されるまでの間割り当てられている他のvCPUを待たせることとなりCPUリソースを浪費してしまうこととなります。また、同様の問題はマルチスレッド化されたアプリケーションのレベルでも発生するため、何らかの手段で同期を取る必要があります。そしてもちろん、不正確なCPUリソースの進行はゲストOS側のCPUスケジューラを混乱させる原因となります。

この問題は、単なる性能的な問題にとどまらず、より根本的な問題につながる可能性があります。たとえばゲストOSにおいて物理ハードウェアであれば数マイクロ秒で完了すると想定される処理が実行された場合、その処理がより長い間(たとえば数ミリ秒)待っても完了しなかったとするとゲストOSにおける処理にタイムアウトを引き起こす可能性があります。同期スケジューリングを使用しなかった場合、こうした問題によってOSのハングアップが引き起こされてしまう可能性があります。

■ESX2.xにおける同期スケジューリング "Strict Co-Scheduling (厳しい同期スケジューリング)"

VMwareは2003年のESX Server 2のリリースにおいて、仮想マシンにおけるマルチプロセッサ(vSMP)構成をサポートしました。ESX Server 2.xでは、ズレの検出と対処に基づくアプローチによって同期スケジューリングが実装されました。

ESX Server 2.xにおけるCPUスケジューラは、マルチプロセッサ構成の仮想マシンにおけるvCPUの処理ステータスを追い続け、vCPU間の処理が許容されるしきい値(数ミリ秒の範囲)を超える場合、vCPUが同期できないステータスとなっていると扱います。vCPUの同期ステータスに問題が検出された場合、CPUスケジューラはズレの拡大を防止するために強制的に同期スケジュールを停止します。その後、同期スケジュールを再開するためには、すべてのvCPUについて処理が進められる(スケジュールされた=pCPUが割り当て可能となっている)状態となる必要があります。このように、一度vCPUの同期ステータスに問題を検出してから再開するためにはすべてのvCPUがスケジュールされる必要があるため、このアプローチは「"Strict Co-Scheduling" (厳しい同期スケジュール)」と呼ばれます。

"厳しい同期スケジューリング"方式では、ESXホストが十分ではないCPUコア数しか持たない場合や、ユニプロセッサvCPU構成の仮想マシンマルチプロセッサvCPU構成の仮想マシンが混在して実行されている場合などにおいて、同期スケジューリングはCPUリソースの断片化によるオーバーヘッドを生じさせてしまいます。たとえば、2つの物理コアを持つESXホストにおいて、2つのvCPUを構成した仮想マシンと、1つのvCPUを構成した仮想マシンを実行させたとします。この時、ESXホストが持つ2つのCPUコアリソースの内1つを1 vCPU構成の仮想マシンに対して割り当てた時点では、2 vCPU構成の仮想マシンに対してはCPUスケジューラはもう1方のコアがアイドルしていたとしても、CPUリソースの割り当てを行うことはできません。ただしこの問題は、十分な数のコアがある場合においては、vCPUに対して柔軟なCPUリソースの割り当てが可能となるため、それほど問題とはなりません。

■ESX3.xにおける同期スケジューリング "Relaxed Co-Scheduling (緩やかな同期スケジューリング)"

VMwareは2006年のESX Server 3のリリースにおいて、CPUスケジューラとして使用する同期スケジューリングアルゴリズムを大幅に改良しました。基本的な同期スケジューリングの仕組みはこれまでと同様にズレの検出と対処に基づいています。しかし、すべてのvCPUに同期を求めるのではなく、処理を実行しているvCPUのみについてのみ同期を行う仕組みに変更されています。この仕組みにより、どのvCPUに対してCPUリソースをスケジューリングする際にも、他のvCPUとの同期のズレを抑制しながら割当を管理することが可能となります。このアプローチは仮想マシンに割り当てられたvCPUの内、ズレを検出した"同期を必要としている" vCPUについてのみ同期スケジューリングを制御するため、「"Relaxed Co-Scheduling" (緩やかな同期スケジューリング)」と呼ばれます。

ところで、ESXホストはゲストOSにおける同期処理を必要としない状態=アイドルループプロセスをどのように扱っているのでしょうか?アイドル状態のvCPUは計算サイクルを実行していないために、まったくCPUサイクルにズレを生じさせません。このような場合、ESXホストはそのvCPUはアイドルステータスにあると判断し、pCPUの割り当てを行いません。これにより、pCPUは他のCPUリソースを必要としている他の仮想マシンのために使われるため、CPU使用効率を高めることができます。この仕組みにより、2つの物理コアを搭載したESXホスト上で1つのvCPUを割り当てた仮想マシンを2台、同期スケジューリングによるオーバーヘッドを生じさせることなく実行できるのと同じように、1つのvCPUがアイドル状態となっている2 vCPU構成の仮想マシンと1 vCPU構成の仮想マシンの2台を実行していた場合でも、同期スケジューリングによるCPUリソースの断片化は発生しません。

たとえば、あるvSMP構成の仮想マシンにvCPU A, B, Cが構成されていたとします。この仮想マシンにおいて、vCPU Aではズレが検出されているが、BおよびCではズレが検出されていないとすると、vCPU BはvCPU Aを同時に実行することができるタイミングでのみCPUリソースの割り当てを受けることができるということになります。これにより、vCPU Aと他のvCPU間でのズレが大きくなってしまうことを抑止することができます。しかしこの状況において、vCPU CはvCPU Bと同時に実行する必要性がありません。もちろん可能であればESXホストは最適化のためにvCPU間で同期をとったCPUリソースの割り当てを行おうとしますが、これは必要条件となるわけではありません。

厳しい同期スケジューリングから緩やかな同期スケジューリングに変更することによって、ESXではCPUの利用効率を向上させ、同期スケジューリングによる断片化の発生を可能な限り最小限とすることが可能となりました。

■同期スケジューリングのまとめ

厳しい同期スケジューリングの場合、使用可能なアイドル状態のpCPUが1個しか存在しなかった場合には2 vCPU構成の仮想マシンに対してはCPUスケジューリングが行われません。そのため、このような状況となった場合には対象仮想マシンに対するCPUスケジューリングの遅延(2つのpCPUが使えるようになるまでスケジュールされないため)と、ESXホストとしてのCPU使用率の低下を招いてしまうこととなります。ESX3.xから導入された緩やかな同期スケジューリングは、CPU同期のズレを是正する基本的な仕組みは変わっていませんが、ズレを抑制する仕組みが緩やかとなったため、厳しい同期スケジューリングにおけるCPU断片化問題をかなり緩和させました。

厳しい同期スケジューリングの場合では、同期すべきすべてのvCPUに対してCPUスケジュールを同時に割り当てることができなかった場合に仮想マシンの計算サイクルをウェイト状態としていました。しかしこれはすべてのvCPUの処理が遅れてしまうわけではないと考えると、制限し過ぎていたといえます。現在では、CPUスケジューリングのアルゴリズムが穏やかな同期スケジューリング方式となったことにより、必要な同期処理を求めるvCPUのみが同時に実行できればよい仕組みとなっています。これいにより、仮想マシンが必要とするpCOU数を減らすことと、ESXホスト全体でのCPU使用率の向上を図ることができます。仮想マシンが必要とする計算サイクルを実行するのに十分なpCPUがある場合、CPUスケジューラは最もパフォーマンスの出るCPUリソースの割当を行います。

*1:予約リソースとして固定的にリソースを割り当てる場合はとりあえずここでは置いておいて、という話

*2:リソースプールの下にリソースプールを構成すること

*3:単体のESXホストを超えて、クラスタ単位でリソースプールを使用したい場合は、ESXホスト間で仮想マシン配置を調整するDRS機能が有効となっている必要があります。