約40年にも及ぶコンピュータの仮想化の歴史。その過程は,1台のコンピュータを仮想化によって「分割」する技術の積み重ねだった。複数のコンピュータを「結合」して仮想的なコンピュータに仕立て上げる仮想化への取り組みは,ようやく実用化に向けて舵を切った段階だ。
1台のコンピュータを仮想化するうえで,オーバーヘッドをいかに減らすかが鍵になる。実マシンとそん色ない速度で動いてほしいところだが,仮想化の処理がはさまるので,どうしても性能が落ちてしまう。そこでこの仮想化を支援する機能を順次ハードウェアに組み込む研究開発に拍車がかかっている。
一方,複数のコンピュータを仮想化して結合する手法は,OS以上の階層で仮想化した「グリッド・コンピューティング」と,CPU以下の層で仮想化したコンピュータを結合する「仮想マルチプロセッサ」の大きく二つの形態で開発が進んでいる。
分割/オーバーヘッド解消に向け競う
仮想マシンのオーバーヘッドの多寡は,既存の階層構造のどこに仮想マシンを実装したかでほぼ決まってくる。仮想マシン・ソフトの実装を見てみると,方式は大きく四つに分かれる(図1[拡大表示])。(1)仮想CPUを用意する,(2)OSのアクセス制御を利用する,(3)ホストOSの上でゲストOSを動作させる,(4)ゲストOSを仮想マシンの上で直接動作させる,の4手法がある。それぞれオーバーヘッドを減らす手法が異なる。
(1)は,独自の命令セット・アーキテクチャ(中間言語)を使う仮想CPUを定義する手法である。代表的なのは,「Write once,run anywhere」をうたうJava。x86互換CPUやRISCプロセッサといったCPUの種類を問わずに同じバイナリを実行できる,アプリケーションの可搬性が特徴だ。
原則としてプログラム言語のコンパイラやインタプリタは中間言語のコードを生成する。仮想マシンは中間言語を機械語に変換して実行する。変換後の機械語をキャッシュするため,初回実行時以外のオーバーヘッドはそれほどでもない。あらかじめ機械語にコンパイルして使う場合もある。
(2)はOSのリソース管理機能を使い,複数の仮想OSを実行する形態だ。仮想化を実行する主体はホストOSのカーネル。プログラムの実行単位であるプロセスに与えるリソースを複製・共有することで,OSが複数あるように見せる。
例えばSun Microsystems社のOS「Solaris 10」では,「コンテナ」という名称で実装している。「セキュリティ機構を強化したTrusted Solarisのアクセス制御機構がベース。仮想化のオーバーヘッドはほとんどない」(サン・マイクロシステムズ プロダクトマーケティング本部の高松新吾主任)という。ちなみに,仮想(ゲスト)OSの種類はホストOSに依存する。Solaris 10では,仮想OSのバージョンはホストOSのバージョンによって制限される*1。
OSをだます作業がオーバーヘッドに
(3)と(4)は仮想マシンの実装として現在主流となっている方式。(3)はホストOSと連携してハードウェアを制御する仮想マシンを,(4)はOSからハードウェアを完全に隠してしまう仮想マシンを,それぞれ実装する。いずれもゲストOSの切り替えに伴うCPUレジスタの退避・復帰と,ゲストOSが実行する割り込みなど特権命令のエミュレーションがオーバーヘッドとなる*2。
CPUレジスタの退避・復帰は,OSがマルチタスク処理をする場合と同様に,ゲストOSが利用中のハードウェアの状態情報を切り替える作業(コンテキスト・スイッチ)がオーバーヘッドになる。仮想マシンがゲストOS AとゲストOS Bを同時に実行したとする。仮想マシンはゲストOS Aを一定時間実行した後,ゲストOS Aのコンテキストをメモリーに格納する(退避)。ゲストOS Bのコンテキストをメモリーから読み込んでCPUのレジスタを書き換える。ゲストOS Bを一定時間実行し,再度ゲストOS Aのコンテキストをレジスタに書き込む(復帰)。
特権命令をエミュレーションする必要があるのは,元々ハードウェアを直接制御するソフトウェアであるOS(この場合はゲストOS)を仮想マシンの制御下に置くためだ。
x86互換CPUを例に説明しよう。x86互換CPUには,リング0~3の四つの動作モードがある(図2[拡大表示])。一般にOSのカーネルはリング0で動作する。OSのシェルやアプリケーションをリング3で動かすことで,それらのプログラムとカーネルがアクセスできるメモリー空間を分けている*3。ゲストOSがリング3で動作する仮想マシンで,リング0でのみ動作を許されている命令(特権命令)を実行しようとすると,エラー(例外処理)が発生する。
特権命令をエミュレートする方法は大きく二つ。ゲストOSによる特権命令の実行を仮想マシンが動的に検知してエミュレートするか,特権命令を使用するゲストOSのコードを仮想マシンのエミュレート処理にジャンプするように事前に書き換えておく。
前者の方式でゲストOSを正常に動作させるには,仮想マシンがゲストOSの特権命令の実行を検知して,特権命令をエミュレーションした結果をゲストOSに返してやる。一部検知が難しい特権命令があるため,その実行を仮想マシンが随時監視する必要もある。これらのエミュレーション処理がオーバーヘッドとなる(図3[拡大表示])。
後者の方式を採る仮想マシンとしては,米XenSource社が提供するオープンソースの仮想化ソフト「Xen(ゼン)http://www.xensource.com/」がある。ゲストOSで特権命令を使うコードをXenの仮想マシンのAPIの呼び出しに書き換えてしまうため,特権命令の検知にかかるオーバーヘッドがない。半面,ソースコードを改変できないOSをゲストOSとして動かせない。
仮想マシンを“神”にする
OSに手を加えず,コンテキスト・スイッチと特権命令のエミュレーションのオーバーヘッドを解消するには,CPUが仮想マシンのエミュレーションを支援する必要がある。具体的には,ゲストOSの切り替えに伴うコンテキスト・スイッチの機能と「リング−1」に相当する動作モードを,CPUの機能として追加する。
例えば米Intel社の「Vanderpool Technology(VT)」では,仮想マシンが稼働する「ルート・オペレーション」と,ゲストOSが稼働する「ノンルート・オペレーション」という二つのモードを用意。ゲストOSの起動(VMLAUNCH)/一時停止(VMRESUME)/終了(VMCLEAR)などの仮想マシン向け命令を備えている。仮想マシンのレジスタ内容は,VMCS(Virtual Machine Control Structure)と呼ぶテーブルに格納。コンテキスト・スイッチをハードウェアで支援する。
特権命令のエミュレートについても,あらかじめ例外発生時に仮想マシンに処理が戻るようにVMCSを定義しておくことで,仮想マシンの負担を減らす。
米Advanced Micro Devices(AMD)社の「Pacifica(開発コード名)」でも,同様の機能を備えている*4。CPUの仮想化支援機能は,Intel社が2005年内,AMD社が2006年に対応CPUを出荷する予定だ。
メモリー・アドレス変換を高速化
メモリーのアドレス管理と,ディスクやネットワークといったI/Oデバイスの仮想化もオーバーヘッドになる。メモリーのアドレス管理は複数のゲストOSが同じ物理アドレスを読み書きしないようにする排他制御が,I/Oデバイスの仮想化はデータ転送時に起こるコンテキスト・スイッチがそれぞれ問題になる。
「I/Oデバイスの仮想化によるオーバーヘッドは,VMware ESX Serverのケ ースでディスク・アクセスが20~30%,ネットワーク・アクセスで30~40%」(日本IBM テクニカル・セールス・サポート フィールド・テクニカル・サポート xSeries&IntelliStationアドバンスト・テクニカル・サポートの佐々木言主任ITスペシャリスト)と高い。
メモリーについては,仮想メモリーから物理メモリーへの変換作業が2回発生するのが原因。ゲストOSの仮想メモリー管理機構は,仮想メモリーを物理アドレスに変換しながら動作する(図4[拡大表示])。しかしゲストOSは互いに独立して稼働するため,そのままでは,物理アドレスの競合が起こりかねない。そこで,仮想マシンはゲストOSが利用するアドレスを競合しない物理アドレスに再変換する。この仮想マシンによるメモリー管理のソフトウェア・エミュレーションがオーバーヘッドになる。
この再変換のオーバーヘッドを減らすために,「拡張アドレス変換機構」をCPUに実装する。仕組みは単純だ。仮想マシンがソフトウェアで処理する仮想メモリーの管理機構を,CPUの機能として実装してしまうのだ。