exit(l); } else if (len break; len) ! = len) / * ネットワークから入力 * / } else { if if (write(fd, buf , / * ネットワークに出力 * / exit(l); perror ( "read") ; (errno ! = EAGAIN) { if ((len = read(fd, buf , BUFSIZ)) write(), buf, / * 端末への出力 * / } else { break ; } else if (len len) ; se 厄 ct システムコール く 0 ) { 上記のように修正したプログラムの入出力を処理するル ープに注目すると、 for の無限ルーフ。のなかで、非プロッ キング入出力の 2 つのファイルの入力を試み続けるビジー ウェイトと呼はれるループとなっています。標準入力と ネットワークのいすれからも入力するデータがない場合、 読込みを試みて EAGAIN を得たあと、さらに言もムみを 試みて EAGAIN を得るという処理を繰り返すことにな ります。これでは CPU 資源の無驪貴いといわれても仕方 がありません。 入出力のデータがあるときだけ処理したい場合は、 se- lect システムコールを利用するのかイ甦リです。たとえは、 サンフ。ル・プログラムの pr 。 cess 関数を図 1 のように変更 すれは、端末からの入力とネットワークからの入力をどの 順番でもおこなえるようになります。しかも、ビジーウェ イトも起こりません。 急にプログラムか難しくなったように感しるかもしれま せんが、 select システムコールの動作を理解す川まさほど 難しくはありません。それでは、 select システムコールに ついて詳しくみていきましよう。 fd-set 本体 select システムコールは、ファイル・ディスクリプタの 集合に対して言も囚みや書込みが可能かどうかを調べること 78 かできます。さらに、帯域外データと呼ばれる朱なデー タが到着したかどうかも調べられます。ファイル・ディ スクリプタの集合を表現するために、 fd_set という専用の データ構造が用意されています。このデータ構造に対する 演算としては、以下のものカ甘是供されています (fd-set 型 の変数 fds か旦言されているとします ) 。 FD ZERO(&fds) : ファイル・ディスクリプタの集合 を空集合にネノ期化する。 UNIX MAGAZINE 2002.1 合に要素を追加するときにその最大値 &f 尉寺しておくガ去 大値を得るガ去があります。それは、 FD-SET により集 しかし、もっと簡単に集合の要素となる可能性のある最 には、 sysctl 関数を利用して値を取得することになるで 変数として取得できます。プログラム中で正しい値を使う す。これは sysctl コマンドでも kern. maxfilesperproc 許されているファイル・ディスクリプタの最大値になりま limit コマンドで得られる descriptors のイ直かフ。ロセスに 過度に大きく見積もられた値となっています。実際には、 のファイル・ディスクリプタを扱えます。ただしこれは、 用している値です。 fd-set 型は、この値で示される数まで もっとも簡単です。これは fd-set 型を定義するときに利 ファイルで定義されている FD-SETSIZE を用いるのが 値です。この値には、 /usr/include/sys/types. h ヘッダ 素となる可能生のある値とはファイル・ディスクリプタの FD-ISSET を使って検査することになります。集合の要 いません。要素となる可能性のあるすべての値について、 どの操作がほしいところですが、残念ながら用意されて このほかに、集合に属するすべての要素を処理するな す。 構造体として宣言されているため、直接代入できるからで には、このマクロはあまり利用されません。 fd-set 型が んが FD-COPY(&src, &dst) カイ吏えます。しかし実際 合全体をコピーするには、マニュアルには書いてありませ を使って集合に含まれる要素を順に追加していきます。集 通常は、ます FD-ZERO て集合を祺月化し、 FD-SET かを検査する。 FD-ISSET(fd, &fds) : 集合に fd が含まれるかどう FD-CLR(fd, &fds) : 集合から fd を削除する。 FD-SET(fd, &fds) : 集合に fd を追加する。
s ele ct の利用 した 3 つの集合に、みつかったファイル・ディスクリプ には、ファイル・ディスクリプタの甫を渡すために利用 該当するファイル・ディスクリプタがみつかったとき おいてエラーが発生したことを示します。 select システムコールが負の値を返した場合は、呼出しに か満たされる前にタイムアウトとなったことを表します。 れは、ファイル・ディスクリプタに対して指定した条件 トを設定すると、この値が 0 になることがあります。 常は、これは正の直になっているはすです。タイムアウ を満たしたファイル・ディスクリプタの数を表します。通 select システムコールカ鮗了したときの戻り値は、条件 ル・ディスクリプタがあるかどうかを即座に調べられます。 せん。時間として 0 を指定すれば、条件を満たすファイ ステムコールは最大でも指定された時間しかプロックしま 方、 timeval 構造体を使って時間を指定すると、 select シ する条件が岡たされるまで、そこで処理は止まります。 ます。つまり、いすれかのファイル・ディスクリプタに関 NULL を指定すると select システムコールはプロックし すファイル・ディスクリプタがない場合、最後の引数に テムコールはプロックせすにすぐに戻ります。牛を満た ここ旨定した値に関係なく select シス プタがあれは、 指定するわけです。条件を満たすファイル・ディスクリ を満たすファイル・ディスクリプタがない場合の動作を イル・ディスクリプタを検査しますが、指定された条件 テムコールでは言ムみ、書込み、帯域外データを扱うファ するか、タイムアウトするかを指定します。 select シス 最後の引数の timeout には、 select の処理をプロック なります。 るかを指定します。さきほどの例でいえば、 fdmax 十 1 と 値十 1 、つまりいくつのファイル・ディスクリプタを調べ nfds には、検査するファイル・ディスクリプタの最大 select(nfds, &rfds, &wfds, &efds, &timeout) 定します。 efds とすると、 select システムコールは以下の形式てオ日 したかどうかを調べるファイル・ディスクリプタの集合を ル・ディスクリプタの集合を wfds 、帯域外データか到着 タの集合を rfds 、書込みが可能かどうかを調べるファイ 言ムみか可能かどうかをヾるファイル・ディスクリプ 80 タかオ褓内されています。そのため、集合に含まれるすべて のファイル・ディスクリプタに対する処理としてさきほど 紹介したループを使って、集合に残っているディスクリプ タを調 , 、く、それを処理します。 図 1 のプログラムでは、標準入力からの入力とネット ワークからの入力を select システムコールで監視してい ます。このプログラムでは入力がなければはかに処理する ことはないので、 select システムコールは入力が到着する までプロックするようになっています。 select システムコ ーノレから戻ってきた場合には、 FD-ISSET を使って標準 入力やネットワークからの読込みが可能かどうかを調べ、 入力があればそこからデータを読み込みます。そして、標 準入力ならネットワークへネットワークからの入力な ら標準出力へ書き出します。ほかにも、入力カ鮗了したと きにプログラムを終了できるように残っているファイル・ ディスクリプタの数を数えたり、 alarm を使ってタイム アウトを設定し、プログラムを終了できるようにしたりし ています。 図 1 のプログラムでは、標準入力とネットワークから の入力の 2 つを監視していました。一方、ネットワークや 標準出力への出力についてはとくに見をおこなわす、い きなり出力しています。ネットワークの先に書き込めない 場合、このプログラムでは書込みの段階でプロックしてし まいます。本来なら、入力を読み込んでもそれをすぐに書 き込むのではなく、書込みが可能かどうかを調べてから書 き込むべきです。この場合には、読み込んだデータを一引芋 的にどこかにイ尉寺しておかなければなりません。入力が可 能になったので読み込んだが、まだ出力できない状態だっ たということもあるためです。しつは、 telnet コマンドで この情報を保持するために利用されるのが、前回紹介した リングバッフアです。 それでは、 telnet コマンドでこの処理をおこなっている 部分をみていきましよう。具イ勺には、 sys-bsd ファイル にある process-rings 関数です。この関数は TN3270 マ クロが定義されているかどうかによる条件コンパイルが多 く、見通しか懇くなっているので、関係のない部分を削除 した状態でみることにしましよう。 出力先の監視 UNIX MAGAZINE 2002.1
連載 /UNIX Communication Notes—O との受信侍ち状態に戻り、もう 1 つのプロセスは処理をお こなうかたちになっていた。これを擬似コードて表現する と、次のようになる。 main() 初期処理 ; socket() ; S bind(s, listen(s) ; while ( 1 ) { / * socket の生成 * / / * s 。 cket に対する設定 * / accept(s, C S exit(O) ; close(cs) ; 実際の処理 ; close(s) ; / * 子プロセス * / if ((pid = fork() / * 受信待ちでプロック このコードからも分かるように、子プロセスがクライア / * 親プロセスは実際に接続されたソケットをクローズ * / / * 受信待ちに戻る * / close(cs) ; システムコールを用いて起動するかたちにした。 inetd に 理するプログラムを inetd が fork() し、さらに exec( 特定のポートへのアクセスがあった場合、そのポートを処 をしなければならない複数のポートを監視する。そして、 inetd は、 select() システムコールを使って、受信待ち UNIX で標準的に使われるようになった。 inetd (lnternet super daemon) が開発され、 4.3BSD せておかなけれはならないという間題を解決するために 上記の間題のうち、あまり使われないデーモンも不力さ inetd の登場 かった。 ・プロセスを複製する fork() システムコールの実行が遅 った。 モリしかなかった衫琪月の UNIX システムには重荷とな として、プロセステープルか増えてしまい、わずかなメ め、デーモンとして稼動させるプロセスか増える。結果 ・ふだん利用しないサーバーもデーモンとして起動けるた この方式には、以 - ドのような間題があった。 のソケット接続要求だけを処理する構造になっている。 ントからの要求を処理し、親プロセスはクライアントから 64 よって起動される処理プログラムは、標準入力からデータ を読み込むと socket に届いたデータを読むことができ、 標準出力に書き出すと相手にデータか送られるような形式 UNIX MAGAZINE 2002.1 グラムのなかでうまく処理できるようにすれはよい。この きなオーバーヘッドをともなう実装ではなく、 1 つのプロ だけに fork() でプロセスを複製している。このように大 さきはど窈疑似コードでは、処理をおこなう部分のため ラムが考案された。 fork() によるプロセスの複製はしないサーバー・プログ 間で通常のデーモン・プログラムとして実行されるが、 その後カーネルに組み込むのではなく、ユーサー空 ユーサー空間で作る ネルに組み込まれることはあまりなかった。 くい。そのため、 NFS 以外のサーバー・プログラムがカー への糾込みは、作業か難しいだけでなく、デバッグもしに しかし、一殳的な処理をおこなうプログラムのカーネル ていた。 ファイルシステムを扱う NFS はカーネルへの実装に適し ロセスの複製というオーバーヘッドを軽減した。しかも、 常駐スレッド (thread) をカーネルに組み込むことで、プ しようと考えたわけである。 NFS では、処理をおこなう るプロセスの複製はしないように実装し、処理性能を改善 変わりはなかった。そこで、常駐はしても、 fork() によ って複製される状況は、 inetd かイ吏われるようになっても サーバーへのアクセスがあるとプロセスが fork() によ これは、 NFS サーバーの実装の際に採られた方法である。 次に考えられたのが kernel resident thread である。 kernel resident thread えなかった。 にデーモンとして起動さ常駐するという形態をとらざるを などの常駐すべきサーバーは、依然としてシステムのプート時 けではない。たとえば、 UDP を用いたサービスや、 sendmail しかし、すべてのデーモンが inetd の管理下に置かれたわ ノート 5 わすかながら改善された。 状態にしておくという間題カ黝夬さシステムの性能が きる。これにより、起動された大量のデーモンを受信待ち peername() などのライプラリ関数を用いて知ることがで の API が定められた。相手のアドレスなどの情報は、 get-
プログラミング・テクニック しかし、接続するのが echo サーバーではない、つま り複数の入力行を読み込んでから数行ぶんの応答をまとめ て返すサーバーの場合、このプログラムでは対応すること ができません。どの程度の入力をサーバーに送れは応答が 返ってくるかカ吩からないため、標準入力からの入力を読 み込みつつ、それをサ→ヾーに送る必要があります。さら に、サーバーからの返答を監視しなければなりません。そ のためにおこなうのか非期の入出力てす。 ・ファイル言当子の複製 ・ close-on-exec フラグの取彳等と疋 ・ステータスフラグの取得と設定 ・入出力関連シグナルの受信プロセスの取得と設定 ・レコードロックの取得と解除 があります。非プロッキング入出力は、ステータスフラグ て蒲衂されています。実際の処理は次のようになります。 fcntl(fd, F—GETFL, 0 ) ) perror("fcntl") ; exit(l); if (fcntl (fd, F—SETFL , f ー O—NONBLOCK) perror("fcntl") ; exit(l); if ( (f = 非プロッキング入出力 ます、実際に入出力をおこなっている process 関数が 呼び出される状況と、この関数の重川乍について石忍してお きましよう。 ます、 fcntl に対して F-GETFL コマンドを実行し、 この関数か呼び出されるときには、 TCP を利用してい ファイル・ディスクリプタの現在のステータスフラグを取 る場合はすでに接続か確立した TCP のソケットが引数 得します。続いて、 F-SETFL コマンドによりステータ として渡されます。 UDP の場合には、接続という念は スフラグを設定します。このとき引数として、最初に取得 ありませんが、バケットの送出先があらかじノ旨定された したフラグの値と非プロッキング入出力を示す O-NON- 状態て呼び出されます。つまり、いすれも read や write BLOCK とのビットごとの論理和をとった値を指定しま などのシステムコールを使ってデータを読み書きできるよ す。この処理により、もとのステータスフラグから非プロ うになっています。ただし、相手側とのやりとりのなか ッキング入出力のフラグのみを変更したものを設定するこ で、ネットワークからの入力と標準入力の両方を順番に読 とかできます。値を取得迂すに O-NONBLOCK だけを み書きしていては正しく重川乍しなくなってしまいます。そ 引数として F-SETFL を実行すると、ほかのフラグか設 こで、ネットワークからの入力でも標準入力でも、言も囚み 定されていた場合にこれらがクリアされてしまいます。上 か可能になった段階で読み込んで対応する出力先に出力し 己の処理は、このような問題を避けるための工夫です。 ようとします。 上に示したコードでは fd を非プロッキング入出力に設 言ムみが可能かどうかを調べるのは、ネットワークや標 定しました。次に、標準入力についても非プロッキング入 準入力から読み込むべきデータがない場合にプロセスカワ・ 出力の設定をしたあと、サンプル・プログラムのような入 ロック ( 入力待ちで停止 ) してしまうからです。逆にいえ 出力に関するループを実行すればよいのですが、ループの ば、プロックさえしなければいつ読み込んでもかまわない 内部をすこし変更する必要があります。非プロッキング入 はすです。そのためには、 fcntl システムコールを使って、 出力をおこなうファイル・ディスクリプタは、読み出す ファイル・ディスクリプタか非プロッキング入出力をお データがないか書き込む準備ができていない場合にエラー こなうように設定します。 を返し、 errno を EAGAIN に設定するためです。これ fcntl システムコールは次のような形式でイ吏います。 は実際にエラーが発生したわけではなく、一日勺に実行で fcntl ()d , command, arg) きないことを表すのですから、エラーを無視しなけれはな りません。そのためのコードは次のようになります。 fd には処理の対象となるファイル・ディスクリプタを、 command にはおこないたい処理を表すマクロを指定しま for ( ; / * 端末から入力 * / す。さらに処理に対する引数を arg に指定します。 if ((len = read(), buf , BUFSIZ)) く 0 ) { if (errno ! = EAGAIN) { fcntl で可能な処理としては、 perror("read") ; 1 三ロ 77 UNIX MAGAZINE 2002.1
連載 UNIX Communication N0tes—O ために利用できるのが、 select() システムコールである。 select() は、複数のファイル識別子で指定される入力ソ ケットを監視し、カーネル内でプロックする。読み出せる ようになった ( 到着した ) ソケットがあるとプロックか外 れ、処理ルーチンを同一プログラム内でおこなうようにす るコードか書ける。これにより、複数のソケットを監視し ながら処理を夫行するルーチンか書けるようになった。 しかし、この実装には大きな問題がある。プログラムを 実行しているコンテキストは 1 つしかないので、リクエス ト処理ルーチンを実行しているあいだは、ほかのソケット に到着したデータや新たな接続要求はすべてカーネル内に イ尉寺される。けっきよく、 fork() は使わなくても、すべ ての処理がシリアライズされるため、高い性能か得にくく なった。もちろん、リクエスト処理ルーチンの処理量が大 きいと、処理待ちになるリクエストも増えることになって しまう。 そこで、登場するのがスレッドである。その考え方は 実装により多少異なるが、おおまかには次のようなもので ・スレッドを利用するプログラムでは、その実行時に複数 のスレッドを起動することができる。 ・ 1 つのスレッドは、実行を管理するためのコンテキスト をもつ。ここには、プログラム・カウンタとスタックだ けが用意されている。つまり、現在、どの部分を実行し ているかという情報と局所変数だけが各スレッドに割り 当てられている。 大域変数は、すべてのスレッドて共有される。したがっ て、或変数を使えばスレッド間での通信カそきる。 ・スレッドの生成や消去などは、プログラムで明カ勺に記 述できる。 スレッドを利用すると、ユーサー空間て稼動するプロ グラムで並列処理を簡単に記主できる。描丘の生能サー バーの世界では、スレッドの利用を目指す開発か続けられ ている。現在のスレッドの実装には、 BSD 系の pthread や Linux の linux pthread などがある。これらはそれ ぞれに実装形態か違い、長所もあれば短所もある。また、 BSD の pthread の実装のように、システムコールとの 親和がやや悪いという欠点は解消されつつあるが、完全 、解決されたわけではない。スレッドを利用するサーバー UNIX MAGAZIN E 2002 ユ はまだ少ないが、高性能サ→ヾーの世界ではスレッドを用 いた開発が一殳的になり始めている。 WWW サーバーの Apache 2.0 系列がその一例である。今後、高生能サー ーを構築する際には、使用されるプログラム自体がスレ ノ、 ッドを使う実装になると思われる。 ☆ 今回は、十分な処理性能が得られるサーバーの構築方 法について述べた。むろん、厳選された性能のよいパーツ を用いて高生能サーバーを構築するガ去もあるが、レイヤ 4 / 7 スイッチを使ったクラスタ化によって実現すること も増えてきている。とくに、商用 WWW サービスを提供 するサイトなどでは、常識といってもよいはどクラスタ化 サーバーの利用が進んでいる。 高生能サーバーを導入する場合は、レイヤ 4 / 7 スイツ チを用いたサーバー構成のノウハウを応用するとよい。最 近は、サーバー・プログラムそのものの高性能化もスレッ ドを用いた並列処理によって見されようとしている。ス レッドを用いた処理は SMP 型システムとの整合生もよ く、今後、高性能サーバー・プログラムの実装手法とし て普及する可能性がある。サーバーの実装を目指すソフト ウェア技術者は、スレッドを用いたプログラム開発の腕を 磨くべきであろう。 ( やまぐち・すぐる奈良先立斗 ! 物支彳大芋ギ完大学 ) [ 文献 ] [ 1 ] Lawrence S. Brakmo and Larry L. Peterson, "TCP Vegas: End t0 End Congestion Avoidance on a Global lnternet ” IEEE ノ 0 社ロ田 1 0 れ Selected Areas をれ Comm 社れを ca 0 れ , V01.13 , NO. 8 , Oct0ber 1995 (ftp: //ftp.cs.arizona.edu/xkernel/Papers/jsac.ps. Z) 65
表 3 さまざまな構成の PC -733 でデータを週言したときの合計アイドル時間俿畴合 nettest 実行中のアイドル時間 PC ー 733 ・商化 VM/PC-733 IRQ 通知をおこなわない最適化 VM/PC-733 送信の結合と IRQ 通知をおこなわない最商化 VM/PC-733 VMware Workstation 2.0 の VM/PC-733 ク・リンクを一杯にするかなり前に CPU によって性能が 制限される。しかし、最商化を施すと VM/PC-733 はネ イテイプに匹敵するスルーブットを達成する。 VM/PC- 350 は最適化を施しても CPU の性能による制限を受け るが、 2 倍のスルーブットを維持し、最適化されていな い V / PC ー 733 と同等の性能を達成している。 VM/PC -350 の 2 つの曲線はそれぞれ PC ー 733 の曲線の形状と一 致する。 図 6 は、 VM/PC-733 が CPU の性能による制限を受 けすに 100Mbit のリンクを一杯にできることを示してい る。しかし、 VM/PC-350 は最直化を施しても CPU に よって性能を左右される。ネイテイプの PC ー 733 と pc- 350 は 100Mbit のリンクを簡単に一にする。最後の実 験では、さまざまな構成で CPU がどのように消費される かについての情報を集めた。 システムを詩ヾ、アイドル日判の正確な長さを得た。通 常は、ゲストカ止命令 (HLT) を発行すると、 VMware Workstation は領域を VMApp に切り替える。そして、 VMApp はすべてのテンヾイスで select() をプロックする。 こでは、ホスト OS に制御を戻す代わりに、ゲストの HLT 命令がスピンして VMM の CPU を停止させるオ プションを有効にした。 TSC レジスタを使用して、ゲス トが HLT 命令を発行してから次のハードウェア割込み が発生するまでのアイドル時間を測定した。このアイドル 時間は、ゲスト OS がほかの計算をするのに利用できる CPU サイクルである。ホスト OS のはうは、このアイド ル時間をすべてほかの引算に利用できるわけではない。ゲ ストの HLT 命令によって VMApp への切替えが発生 した場合、いくっかの領域切替えやシステムコールによる オーバーヘッド (select() システムコールなど ) が発生す るからである。 ネイテイブマシンのアイドル時間については、 Linux 3.5 CPU 利用率 170 86 % 21.7 % 17.9 % 2.0 % 0 % カーネルに組み込まれている標準のプロファイラを拡張し て、ユーサーコードの実行やカーネルのアイドルルーフに 使われる時間を測定できるようにした。これによって、ア イドルループに費やされた合言判間の割合カ昇られる。 表 3 に示すように、送信サイズが 4KB の VM/PC- 733 では、 64Mbps で CPU に性能を制限されていたゲ ストが、 I/O を一杯にして 21.7 % のアイドル時間がある 状態にまて改善された。これに対し、 PC -733 のアイドル 時は 86 % である。 こまでくると、残りのほはすべての オーバーヘッドは、 CPU のイ反想化か、ホスト協調型アー キテクチャの生質によるものである。次節では、ホスト協 調型アーキテクチャの枠の内側と外側で、さらなる描商化 の可能性を検証する。 前節て解説した最適化では、イ反想化による CPU のオー バーヘッドを、一ト分な I/O 性能か得られるところまて減 らすことができた。本節では、 I/O 性能をさらに改善し、 CPU の利用率を減らすための手法について説明する。お もな最適化の対象としては、 1. CPU と割込みコントローラの仮想化のオーバーヘッド の轤成 2. ゲスト OS やそのドライバの修正 3. ホスト OS の修正 4. VMM からネイテイプ・ハードウェアへの直接アクセス 力げられる。後半の 2 つの手法は、純粋なホスト協調 型イ廨課マシン・アーキテクチャからは逸脱している。ホス ト協調型アーキテクチャの言 t では、既存のホスト os が 通常どおりに実行さイ廨課ソフトウェアがホスト OS の API を使ってハードウェア・テンヾイスにアクセスすると いうことを思い出してほしい。 UNIX MAGAZINE 2002.1
ますは関数の引数です。次のようにたいへん多くの引数 をとります ( 誌面の都合長で折り返しています。以下 int process int netin —rings (netin, netout , netex, ttyin, = 〉 ttyout, P011 ) / * If 0 , then block P011 ; until something tO d0 * / 、 ttyin などの引数には、リングバッフアに空き プログラミング・テクニック ここでは最初に netin や netout などの値を初期化し ていませんが、この関数の実行か開始される点では、 れらはつねに空の状態になっています。これらは外部変数 であり、一度ネ加月化されると以降は初期化せずに使い続け ます。この段階では集合に要素が j 助日された状態になって いますが、後ろの部分の処理カ鮗ったときには FD-CLR を使ってかならす要素がない状態に戻しています。 次が select システムコールです。引数のところでも説 明したように、 p 。Ⅱ引数が真の場合にはさきほど定義した TimeValue をタイムアウトとして指定し、ポーリンク鋤 作となるようにしています。 があれは真の値カイに入されています。つまり、バッフアに オ褓内できるスペースがあるので、 netin ならネットワーク から、 tty ⅲなら標準入力から言囚みをおこなってもよい という意味です。一方、 netout や ttyout はリングバッ フアにデータがあるかどうかを表します。つまり、 netout ならネットワークへの、 ttyout なら標準出力への書込み をおこなってもよいという意味になります。 po Ⅱ引数は、 コメントにもあるように、値カイ為なら select をプロック します。 select 関数のための引数としては、以下のものを定義し ています。とくに注目してはしいのが TimeValue 変数 です。 register int C ; int returnVa1ue = 0 ; static struct timeval TimeVa1ue = この変数は、あとで select のタイムアウト引数として 利用します。タイムアウト値として 0 秒を指定しているた め、実際の重川はポーリングになります。 次に、 FD-SET を使って select に指定する集合を設定 します。このとき、引数の値にもとづいてファイル・ディ スクリプタを追加していきます。 if ((c if seIect(16, &ibits , ( P011 (struct timeval * ) 0 (c &obits, &xbits, &TimeVa1ue) ) く 0 ) { (netout) { FD_SET (net , if (ttyout) { FD_SET (tout , if (ttyin) { FD_SET(tin , if (netin) { FD_SET (net , (netex) { FD_SET (net , if if &obits) ; &obits); &ibits) ; &ibits) ; &xbits) ; UNIX MAGAZIN E 2002.1 if (errno return 0 ; printf ("s1eep(5) from telnet , - after select : %s\r\n" , strerror(errno) ) ; s1eep(5) ; = EINTR) { return 0 ; クリプタです。これはネットワークからの言もムみ用のファ になります。ますは、例外条負 : を表すファイル・ディス 以降は、各ファイル・ディスクリプタに関連した処理 間を作ったあとに return で関数を終了しています。 対処方法があるわけではないので、 sleep ですこし待ち時 を石忍しています。とはいえ、それ以外の場合にもとくに 返ると同時に errno に EINTR カ材褓内されるので、それ ます。割込みにより select の実行カ鮗了した場合、一 1 が こではその処理もしてい が失敗したようにみえるので、 られない状況もありえます。そのときも見かけ上は select ている場合には、割込みなどにより select の実行を続け ラーが発生したときです。しかし、 select がプロックし select システムコールが一 1 を返すのは、基本的には工 うがよいように思えます。 ことも考えられます。もうすこし汎用的な手段をとったほ のでしようが、別の部分を修正した場合は 16 以 E になる ディスクリプタは 16 を超えることはないと石言している こで扱うファイル・ おそらく telnet コマンドの作者は、 select の第 1 引数として整数の 16 を指定しています。 81
BØC マンドを利用する。言田は、それぞれに伺属のマニュアル を参照してもらいたい。 この種のソフトウェアをとりあげるときは、できるかぎり 詳細に説明するよう心トけてきた。しかし、今回のテーマは 高性能 " サーバーの構築である。その観点から IPVS とハー ドウェア実装のレイヤ 4 スイッチを上交すると、残念ながら IPVS のバケット中幻当生能は著しく低い。現在のネットワーク で、 UNIX システムを用いて糸各制御をおこなうことがはとん どないことからも分かるように、ソフトウェアでの実装では十 分な註能か得にくいのである。そこで、今回はあえて細かな説 明をしないことにした。 IPVS の成疋については、 Linux Vir- tual Server Project のサイトから多くのサンプルファイルが ダウンロードできる。これらを読めば、すぐに使えるはすだ。 IPVS のもう 1 つの問題は、ロードバランサーか普通のコ ンピュータ上に実装されるため、ロードバランサー自身が Sin- gle Point ofFailure となってしまうことだ。つまり、ロー ドバランサーか沽郊章すると、サーバーはまったくサービスを提 供できなくなる。ハードウェア実装されたレイヤ 4 スイッチも 古郞章することはあるが、普通のコンピュータとくらべるとその 確率はかなり低い。フラッシュメモリからプートできる PC を 使い、機械的に下力する部分のない IPVS ロードバランサーを 構築することもできる。しかし、これは別の意味で管理と実装 が大変である。その労力も考えれば、ハードウェア実装された レイヤ 4 スイッチを導入するほうが合理的であろう。 連載 /UNIX Communication Notes—O ソフトウェアの根本的な高速化 もう 1 つの方法は、サーバー・ソフトウェアの高速化 である。 ネットワーク・サービスを提供する現在のサーバーでは、 1 つのサーバープロセスが各クライアントに対する処理を おこなフ。このサーバー・プログラムの実装がますけ川ま、 もちろん高い性能は得られない。これまでに、サーバー プログラムの実装で高い処理性能を得るための試みが数多 くおこなわれてきた。以下では、その一端を紹介する。 原始時代 UNIX MAGAZINE 2002.1 ープロセスを fork() で複製し、 1 つのプロセスはも 装されていた。クライアントからのアクセスがあると、サ (listen() システムコールでの待ち ) 状態となる形式で実 てシステムのプート時に起動され、 socket の受信待ち 4.2BSD の時代には、サーバーはすべてデーモンとし JCIass [ 英語版 ] Enterprise Suite 5.0 ー」 ava アプリケーショッ開発のための最強コンポーネントコレクション一 JavaBeans コンポーネントと ユーティリティ、 9 製品のセット さまざまな IDE 製品から ピジュアルフログラミング JDBC を経由した あらゆるデータベースとの接続 ※グラフ / 3D クラフ / グリッド / 階層型グリッド / 入力フォーム / テータ連結 / メーター / 帳票印刷 / 」 a 「生成ユーティリティ www.bOC.co.jp/jclassenterprise/ 動作環境 」 DK 1 . 1 .8 + Swing 1 . 1 . 1 / 」 DK 1 .2.2 / 」 DK 1 .3 標準価格 399 , 000 円 Bytecode Source COde 799 , 000 円 開発元 : カナダ Sit 「 aka 社 BOC は文化オリエント株式会社の登録商標です / その他記載さ れている会社名およひ製品名は各社の商標または登録商標です / 表示の価格に消費税は含まれておりません 製品のお求めは BOC オンラインショップにて BOC BuyDirect! www.bOC.CO.jP/shOP/ 文化オリエント株式会社 BØC 本社仙台市泉区七北田字白水沢 14- IAKAMA ヒル〒 981-3131 Td022-373-0360 F 022-373-1625 63
VMwareWorkstation ホスト協調型 VMM における IIO テパイスの仮想化 ~ Jeremy Sugerman 、 Ganesh Ve 社 ac わ a m 、 Be 9- 村 0 9 Lim 要約 仮想マシンは、メインフレーム・コンピュータへの対 話型の同時アクセスを実現するために、 1960 年代に IBM によって開発された。個々のイ反想マシンはべースとなる物 理マシンの複製であり、物理マシンを巣作しているよ うな錯覚をユーサーに抱かせる。また、仮想マシンを使う と資源の分離や共有などの利点カ碍られ、不頁や構成の異 なるオペレーティング・システムを実行することができる ようになる。 VMware Workstation は、このようなメ インフレーム・クラスの仮想マシン技術を、 PC べースの デスクトッフ・コンヒュータやワークステーションにも たらすものである。 本論文は、 VMware Workstation による I/O テンヾイ スのイ反想化に焦点を当てる。 PC はさまざまなハードウェ イ反想マシンの概念は、きわめて高価なメインフレーム・ アをもち、オペレーティング・システムカワ。レインストー ハードウェアを時分割する方法として、 IBM が考案した ルされている場合が多い。 VMware Workstation は、フ ものである [ 4 , 5 ] 。 IBM の定義によると、、、仮想マシン " レインストールされたオペレーティング・システムを置き とはべースとなる物理マシンのハードウェアの完全に保 換えるのではなく、これを利用してユーザーレベルのアフ 護、分離されたコピーである。そのため、各イ反想マシンの リケーション (VMApp) コンポーネントを重川させ、特 ューサーは自分専用の物理マシンを使っているような感覚 権モードの仮想マシンモニター (VMM) コンポーネント を得られる。また、ソフトウェア開発者は、物理マシンの をスケジューリングする。 VMM は高性能な CPU の仮 クラッシュやほかのユーサーへの景グを心配せすにプログ 想化を直接実現し、 VMApp はホスト・オペレーティン ラムの開発とテストをおこなうことができる。 グシステムを使って I/O デバイスを佖想化して、さまざ まなデバイスから VMM を隠蔽する。このようなホスト 従来の仮想マシンシステムの構成を図 1 に示す。 VMM 協調型アーキテクチャ (hosted architecture) によるテンヾ (Virtual Machine Monitor : イ反想マシンモニター ) と呼 イスのイ反想化では、スルーブットカ吠きく遅延の小さなデ はれるソフトウェア層がマシンのハードウェアを完全に制 バイスに要求される性能を実現できるかどうかがきわめて 御し、イマシンを作成する。イ反想マシンはそれぞ独 重要な間題となる。 自のオペレーティング・システム ( 以ード、 (S) を実行で こうした目的を達成するため、我々は VMware Work- きる完全な物理マシンのように振る舞う。 1 つの OS がマ station における Ethernet アタフタのイ反想、化とその性能 について調査した。その結果、最適化をおこなえは、 VM- ware Workstation のホスト協調型イ反想化アーキテクチャ は、オ剽勺な PC のネイテイプ I/O のスルーブットに匹 敵することが明らかになった。 733MHz Pentium III の システムで 100Mbps Ethernet を使用した場合、イ反想化 にともなうオーバーヘッドのため、単純なホスト協調型の 実装では CPU の性能による制約を受けるが、 CPU 利用 率の肖鹹を目的とした一連の山も商化を施すと、ネイテイプ のネットワーク・スルーブットに卩攵するシステムを実現 できる。その他の最適化については、ホスト協調型アーキ テクチャの内側と外側の両面から角見する。 158 UNIX MAGAZINE 2002 ユ
放棄せすに、領域切替えの回数を大幅に減らすための最商 化を実装した。 VMM での I/O ポートの里 ホスト領域への領域切替えを要求するイ反想 I/O アクセ スは、物理 I/O デバイスへのアクセスを要求するもの だけであることを思い出してはしい。 I/O 命令の大半は Lance のデータポートへのアクセスであり、バケット送 信の引き金になるのはこのうちの 3 分の 1 にすぎない。 残りのアクセスはイ瓦想 Lance のデータポートの状態を変 更するだけであり、領域を切り替えなくても VMM で簡 単に直接処理できる。したがって、実際に I/O を要求し ない OUT ・命令のエミュレーションは、 VMware Work- station 2.0 の 10 分の 1 以下の時間て夫現することがで きるようになった。 また、 Lance のアドレスレジスタがもつ動 ( 信生を利 用すると、 Lance のアドレスポートへの I/O アクセスの 処理コストはさらに咸できる。 Lance の言翹 ( りと書込み には副作用がなく、最後に書かれた値をイ寺するだけであ る。そのため、 VMM にアクセスする命令か特権モード の命令であっても、 VMM は特別な場所に保存するだけ の単純な MOV 命令としてそれらを処理できる。これに より、 VMM はいくつかのイ瓦想化層を不要にし、これら のアクセスを処理するための命令を減らすことかできる。 言の結合 第 2 の最適化は、大量の I/O をおこなうワークロー ドでは割込み率が高く、ホストの IRQ を受信するたび に VMM 領域からホスト領域に切り替える必要がある という事実を利用して、さらに領域切替えの回数を減ら す。 VMware Workstation 2.0 では、 Lance アタフ。タ にバケットが送信されるたびにホスト領域に切り替えて、 プリッジて鮟続されたネットワークにバケットを送信す る。 Lance のデータポートのエミュレーションの一部を VM て夫行するようにしたため、 VMM は割込みによっ て次にホスト領域への切替えが発生するまで、実際の送信 を遅らせることかできる。 具体的には、次のようにして送信の結合をおこなう。 VMM は、システムの領域切替え率が高いかどうかを調 べる。切替え率 ( べき成袞カウンタで定期的に再言 t 算す ーーー ~ ーる ) ~ ー ~ が一ト分に高い場合、 VMM はゲスト OS がバケット UNIX MAGAZINE 2002.1 I/O デバイスの仮 を送信する際に、それをリングバッフアのキューに入 イ反想マシンに制御を戻す。次に実際に割込みが発生し、制 御が VMApp に戻されたら、リングバッフアにある未処 理のバケットを送信する。これにより、バケット送信によ る領域切替えと、割込みによって発生した領域切替えをま とめることカきる。 バケットをキューに入れる作業にはコピーは必喫ない。 バケットをイ瓦想 Lance コントローラの送信リングバッフ アに残せばよいのである。遅延させるバケットの数が多い 場合訓点のデフォルトは 3 ) 、 VMM はネイテイプ NIC を有効に利用するために、強制的に領域を切り替え てバケットを送信する。また、ホストのシステムタイマー を利用して次の IRQ には領域切替えが保証されるため、 バケットが 2 回以一日屋延することはない ( 遅延が 1 回発 生すると、 VMApp は必要であれば送信の結合を中止す る ) 。こうした最適化は、大量の I / O を扱うワークロード でとくに大きな保カ碍られる。割込み率カ皜いと、連続 して I/O カリ用されるかぎり領域切替えが抑制されるか らである。 送信の結合は、ゲストとホストの IRQ にも効果がある。 ゲストはバケットがキューに入れられると即座に実行を続 けるため、次に強制的な領域切替えが実行されるまでに、 ゲストがバケットを連続して送信できる可能生か咼い。そ のため、 VMApp は複数の送信バケットを 1 回の領域切 替えで処理することかできる。また、一 -- 漣の処理に対して イ反想 IRQ を 1 つだけ伝えればよい。前述のように、イ課 IRQ の伝達とそれに関連する襯在モードのイ廨課化命令は、 コストの高い操作である。また、複数のバケットを同時に 送信すると、ホスト領域での実行中にネイテイプの送信完 ードウェア割込みがホスト領域 了割込みか得られたり、 で実行さ VMM 領域で実行した場合よりも高速に処理 される可能性か増える。 IRQ 通知 第 3 の最適化は、バケットの送受信通知を受け取るため の、ホストのシステムコールを減らすことに照準を定めて いる。 VMApp はネノ測」化の際に VMNet ドライバとの共 有メモリを設定し、バケットがくると VMNet ドライバ はビットべクトルを設定する。次に、 NIC の IRQ ごとに select() をすべてのデバイスに対してイ月するというコス 167