サーバサイドの技 〜安全で高速で負荷の少ないシステムを追求〜

 

 クラウドコンピューティングが一世を風靡しそうな時代になりましたが、それと平行して素晴らしいLinuxディストリビューションが続々と登場し、手軽にMyServerを構築できる時代となりました。実際のところ、Google App Engineを性能で超えるプラットフォームを作ることは非常に難しく、Google App Engineが制限はあるものの無料で提供されているので、MyServerを構築するなんて馬鹿らしくも思えます。けれど、ハードウェアの方もMyServerを作る追い風が吹き、ATOMを初めとする低消費電力CPUのおかげで毎月500円の電気代で24時間MyServerを稼動させられるような時代にもなっています。後はGoogle App Engineに迫る性能を出すことができれば、MyServerを構築する価値を見い出せます。ここでは、各種CGIアクセラレータやModuleとして WebServerに組み込むことなども踏まえ、その可能性を追求してみたいと思います。

Part 1、システムの理解

まずは色々と検討するためのシステムを8種類用意しましたので、よく把握しましょう。

 

 1、テキスト(Webページ等)閲覧の流れ

 

通常のWebシステム

 

 2、ノーマルCGI+スクリプトの動作の流れ

 

実行された【インタプリタ】プロセスは終了後破棄される。
同時アクセスが起きた場合は【インタプリタ】プロセスが複数メモリ上に展開される。
Non-Parsed Header CGI型の場合は⑤と⑥の処理が1つとなり、CGIから直接ブラウザにテキストを渡すことができる。

 

 3、ノーマルCGI+エグゼキュートの動作の流れ

 

実行された【エグゼキュート】プロセスは終了後破棄される。
スクリプトの読み込みやコンパイルにかかる時間もないため、当然ノーマルCGI+スクリプトよりは高速な動作をする
同時アクセスが起きた場合は【エグゼキュート】プロセスが複数メモリ上に展開される。
Non-Parsed Header CGI型の場合は④と⑤の処理が1つとなり、CGIから直接ブラウザにテキストを渡すことができる。

 

 4、SpeedyCGI+スクリプト(バイトコード)の動作の流れ

 

実行時に生成されたバイトコードプロセスは終了後も破棄されず再利用される。
1回目のアクセスはノーマルCGIと変わらないが、2回目以降のアクセスは常駐したバイトコードが使われるため、非常に高速になる。
同時アクセスが起きた場合は【バイトコード】プロセスが複数メモリ上に展開される。
外部ファイルをスクリプト内に組み入れるようにすれば、ストレージを介さないため、更なる高速化が見込める。

 

 5、FastCGI+スクリプトの動作の流れ(動的起動の場合)

 

1回目のアクセスはノーマルCGIと変わらないが、2回目以降のアクセスは常駐したインタプリタとキャッシュされたスクリプトが使われ るため、非常に高速 になる。
外部ファイルをスクリプト内に組み入れるようにすれば、ストレージを介さないため、更なる高速化が見込める。
同時アクセスが起きた場合は【インタプリタ】プロセスが複数メモリ上に展開される。
静的起動の場合はあらかじめ決めた数だけメモリ上に【インタプリタ】プロセスの常駐ととスクリプトキャッシュをさせることができるため、1回目のアクセス から高速になる。

 

 6、FastCGI+エグゼキュートの動作の流れ(動的起動の場合)

 

1回目のアクセスはノーマルCGIと変わらないが、2回目以降のアクセスは常駐したエグゼキュートが使われるため、劇的に高速になる。
外部ファイルをエグゼキュート内に組み入れるようにすれば、ストレージを介さないため、爆発的な高速化が見込める。
同時アクセスが起きた場合は【エグゼキュート】プロセスが複数メモリ上に展開される。
静的起動の場合はあらかじめ決めた数だけメモリ上に【エグゼキュート】プロセスを常駐させることができるため、1回目のアクセスから高速になる。

 

 7、module型インタプリタの動作の流れ

 

スクリプトから【Web Server】のコアシステムと直接やり取りをする目的で作られたシステム。
1回目のアクセスから【Web Server】プロセスに組み込まれた【インタプリタ】モジュールが動作するため、【スクリプト】はストレージから読み出すものの高速である。
同時アクセスが起きた場合は【インタプリタ】モジュールが複数【Web Server】プロセス内に展開される。
複数できた【インタプリタ】モジュールを再利用する目的なのか、なかなか廃棄されないため、【Web Server】プロセスが極端に肥大する傾向がある。
【Web Server】プロセスにモジュールとして統合されているが故にユーザのスクリプトの問題点が直接【Web Server】プロセスに影響を及ぼす危険性がある。
FastCGIのプロセス間ソケット通信よりもmodule型スレッド間通信の方が当然処理速度が速く、理論上はFastCGIよりも高速となる。
FastCGIのプロセス間ソケット通信の場合はアプリケーションサーバを複数分散させて処理させることができるが、module型はできない。

module型インタプリタには
mod_perl
mod_python
mod_php
mod_ruby
などがあり、Web Serverプロセスにモジュールとして組み込む

 

 8、module型エグゼキュートの動作の流れ

 

1回目のアクセスから【Web Server】プロセスに組み込まれた【エグゼキュート】モジュールが動作するため、劇的に高速である。
同時アクセスが起きた場合は待機させるか、複数【エグゼキュート】モジュールを【Web Server】プロセス内で生成するかなど自分でプログラミングする必要がある。
【Web Server】プロセスにモジュールとして統合されているが故にユーザのエグゼキュートの問題点が直接【Web Server】プロセスに影響を及ぼす危険性がある。
FastCGIのプロセス間ソケット通信よりもmodule型スレッド間通信の方が当然処理速度が速く、理論上はFastCGIよりも高速となる。
FastCGIのプロセス間ソケット通信の場合はアプリケーションサーバを複数分散させて処理させることができるが、module型はできない。

 

Part 2、次に単純比較をしてみましょう。いちいちスクロールも面倒なので、メモ代わりに上記8つの名称をもう一度記載しておきます。

  1、テキスト
2、ノーマルCGI+スクリプト
3、ノーマルCGI+エグゼキュート
4、SpeedyCGI+スクリプト(バイトコード)
5、FastCGI+スクリプト
6、FastCGI+エグゼキュート
7、module型インタプリタ
8、module型エグゼキュート

 1、メモリとストレージの速度は?(システム構造自体の比較のため、ディスクキャッシュやOSのキャッシュを無視します)
    メモリ >>>>> ストレージ
    現在は数千〜数万倍メモリの方が速いと言われています。SSDには期待です!
    ということは、 4 >>>>> 2 、 5 >>>>> 2 、 7 >>>>> 2 、 6 >>>>> 3 、 8 >>>>> 3 となります。
    FastCGIと比較して、module型インタプリタはスクリプトに関してはストレージから読み出しますので、この件に関しては 5 > 7 が言えます。
    つまり、インタプリタもスクリプトもエグゼキュートもストレージから読み取るノーマルCGIは劇的に遅いことが言えます。

 2、インタプリタとバイトコードとエグゼキュートの速度は?
    エグゼキュート > バイトコード >>>> インタプリタ
    1行ずつコンパイルする手間のかかるインタプリタと、コンパイル済みのコードでは当然かなりの差がありますね。
    ということは、 3 >>>>> 2 、 6 >>>>> 5 、8 >>>>> 7 、 4 >>>> 2 、 4 > 5 、 4 > 7 も言えそうです。

 3、プロセス間通信とスレッド間通信の速度は?
    スレッド間通信 > プロセス間通信
    グローバル変数だけでデータの共有ができるスレッド間通信はやっぱり高速です。でも、ワンクッション置くだけですので、プロセス間通信もそれほど 遅くないです。
    ということは、 8 > 6 は言えますね。
    また、FastCGIとmodule型インタプリタに関しては、この件に関しては 7 > 5 ということが言えます。

 上記3つの比較を総合すると、 ( 8 > 6 > 4 ) > ( ( 7 ? 5 ) > 2 ) という感じでしょうか?
 でも、これでは7と5の決着と、1と3が抜けています。
 理論的に考えるとメモリとストレージの差の方が、プロセス間通信とスレッド間通信の差よりも大きいので、( 5 > 7 )と言えます。
 ですが、実際スクリプトがキャッシュされてしまうと逆転現象が起きる可能性があります。
 ここでは、他の要因で消えてしまうかもしれないキャッシュは信頼せず、理論的なシステムとして検討して( 5 > 7 )と結論付けます。
 ということで、現時点で( 8 > 6 > 4 ) > ( 5 > 7 > 2 ) という結果になります。
 1については後述するとして、少なくとも 6 >>>>> 3 と 3 >>>>> 2 は言えますので、もう一つ比較する必要がありそうです。
 「ストレージからエグゼキュートを起動し、プロセスを生成する時間+エグゼキュートの動作時間」 と 「メモリに起動済みのインタプリタの動作時間」で す。
 でも、これは土俵が違うので比較できません。
 ところが、これに関しては諸先輩方が色々とテストをしてくれていますので結果は出ています。
 結果としては、「メモリに起動済みのインタプリタの動作時間」 > 「ストレージからエグゼキュートを起動し、プロセスを生成する時間+エグゼキュートの動作時間」となるようです。
 ここでのA > Bについては、時間を比較していますが、「Aの方が時間がかかる」のではなく「Aの方がBより性能が良い」と捕らえてください。
 つまり、 8 > 6 > 4 > 7 > 5 > 3 > 2 となります。
 最後に1についてです。
 1についてはサーバによって何とも言えないというところでしょうか。
 テキストのキャッシュを残したままでいられるような暇なサーバならキャッシュから読み出すので、2度目以降のアクセスは速いでしょうが、そうでなければ 遅くなります。
 今回は動作原理から比較していますので、1の場合は先ほど同様、基本的にはキャッシュを信頼しない考えで比較します。
 その場合、少なくとも 1 > ( 3 > 2 ) ということが言えます。
 2や3は「プログラムが動作するまでの時間+プログラムが動作する時間」というオーバーヘッドが伴うからです。
 それ以外の4〜8についてはメモリ上にプログラムは常駐していますので、「プログラムが動作する時間」というオーバーヘッドが伴います。
 ですが、テキストをプログラムの中に組み入れてしまったらどうでしょうか?
 そうすると、「プログラムが動作する時間」と「ストレージからテキストを読み込む時間」の差になります。
 この場合はプログラム側の処理の重さによって結果が変わることになります。
 ただ、言えることは、「2、3は論外的に1よりも遅く、4〜8は1よりも高速になる可能性がある」ということです。
 ということで、もともと1はGoogle App Engineの比較対象でもないので、今後は1は除外し今後は検討します。
 それでは、現在までの結果を速い順に一覧にしてみます。
 なお、空白行は非常に大きな速度差が存在することを示しています。

  ① : 8、module型エグゼキュート
② : 6、FastCGI+エグゼキュート

③ : 4、SpeedyCGI+スクリプト(バイトコード)

④ : 5、FastCGI+スクリプト
⑤ : 7、module型インタプリタ

⑥ : 3、ノーマルCGI+エグゼキュート

⑦ : 2、ノーマルCGI+スクリプト

 

Part 3、技に潜む危険性

 Part 2の結果としてmodule型エグゼキュートが最も高速であることがわかりました。
 けれど、このmodule型には、エグゼキュート・スクリプトを問わず、大きな危険性が潜んでいるのです。
 そうです、module型は、Web Serverと同じメモリ空間に存在し、ユーザの作ったプログラムがWeb Serverの機能を呼び出すことができるのです。
 これに関しては、自分でMyServerに悪さをすることはないので問題ないとしても、ユーザの作ったプログラムの問題点がWeb Serverに影響することは避けられません。
 バッファオーバーフローの脆弱性を突いた攻撃や各種インジェクション攻撃などがあったときにもWeb Serverに影響を及ぼすことが可能性としてあります。
 また、Web Serverは基本的にroot権限で動作しているので、乗っ取られでもしたら大変なことになります。
 そういった観点から、現在では「module型は危険であり避けるべきである」という認識が広まってきています。
 私の提唱する安全なMyServerの理念からもmodule型は極力避けるべきです。
 それを踏まえてmodule型は除外し、比較すると、6 > 4 > 5 > 3 > 2 となります。
 それでは、サイドの速い順一覧です。

  ① : 6、FastCGI+エグゼキュート

② : 4、SpeedyCGI+スクリプト(バイトコード)

③ : 5、FastCGI+スクリプト

④ : 3、ノーマルCGI+エグゼキュート

⑤ : 2、ノーマルCGI+スクリプト

 

Part 4、負荷の軽減

 今度はサーバ負荷の軽減を考えて見ましょう。
 まず、ストレージを考えてみると、ほとんど全てをメモリ上だけでできるシステムがある訳ですし、ストレージを使えばそれだけ遅くなるわけです。
 ならば、ストレージをできるだけ使わないシステムの方が理想的です。
 この観点から、2と3と7は除外できます。
 次にCPU負荷を考えてみると、プロセスの起動や破棄を繰り返せば当然CPU負荷が上がります。
 この観点からも、2と3は除外されます。
 私の提唱する負荷の少ないMyServerの理念からもノーマルCGIは絶対に避けるべきです。
 それを踏まえると、当然結果として、6 > 4 > 5 となります。

  ① : 6、FastCGI+エグゼキュート

② : 4、SpeedyCGI+スクリプト(バイトコード)

③ : 5、FastCGI+スクリプト

 

Part 5、スクリプト言語

 スクリプト言語にはPerl、Python、PHP、Ruby、VBScript、JavaScriptなどがあります。
 基本的にはインタプリタ方式で、都度コンパイルしながら実行していくことになります。
 私の使えるスクリプト言語はPerl、Python、PHP、Ruby、VBScript、JavaScriptになります。
 けれど、この中で、VBScriptはサーバサイドのスクリプト言語としては論外ですので除外します。
 JavaScriptもサーバサイドはありますが、やはり枯れていないことと、情報が少ないことで除外します。
 残る4言語の中で、現時点での性能を考えると、Perlが最も高速で、次にPython、PHP、少し離れてRubyとなるようです。
 基本的には進化した言語ほど遅いようです。
 普通に考えて見るとRuby、Python、PHP、Perlという順で組み易さを感じますので、そういう意味では、Pythonは良くがんばっていま す。
 余程、力のある技術者たちが手を入れたのでしょう。
 ただ、言語の性能だけではサーバサイドは語れません。
 インタプリタ自体の起動時間なども考慮する必要があるのです。
 まあ、一度メモリ上に乗っけてしまえばあまり関係ないかもしれませんが、PHPはコンパクトなので、レスポンスがとても良いと言われています。
 それにしてもスクリプト言語の中ではPerlが一際輝いているようです。
 また、SpeedyCGIはスクリプト言語だとPerlしか対応していないので、現時点でスクリプト言語でスピードを求めるのなら、Perlしかないと いうことになります。
 ただ、いずれにしても、スクリプト言語は元々構造上遅いので、それほど言語における差はないと考えています。
 SpeedyCGIのようにバイトコードで動作するというように、構造上高速であれば話は別です。
 負荷の軽減の観点からも、毎回インタプリタでスクリプトをコンパイルする方式の方がCPU負荷は上がりますのでやはり避けるべきでしょう。
 ということで、スクリプト言語の場合の候補が決まりました。

  ① : 6、FastCGI+エグゼキュート

② : 4、SpeedyCGI + Perl(バイトコード)

 

Part 6、コンパイラ言語

 コンパイラ言語にはC言語、Java、Visual Studioの各種言語などがあります。
 基本的には事前にコンパイルすることで、ネイティブなエグゼキュートを作り出せます。
 ただ、Javaはコンパイルするとバイトコードが生まれ、JavaVM上で動作します。
 そのおかげでマルチプラットフォームです。
 Visual StudioはCLRの場合、気が遠くなるほど(使い物にならないレベルで)遅いので、話になりません。
 ただ、VC++だけはネイティブなコードを出せるので、WindowsではOKです。
 けれど、私の考えるMyServerにはソフトウェアでお金は使いませんので、WindowsもVisual Studioも却下です。
 なぜ、GoogleのPaaSが無料で利用できるのに、またATOMマシンは3万円もあれば最高のものができるのに、OSやIDEで数十万円も出さない といけないのでしょう。
 論外です。
 出すわけがありません。
 WindowsやVisual Studioの使い勝手は確かに素晴らしいですが、経済面も性能面も安定性もセキュリティ面でもあらゆる面でLinux系の方が上です。
 ということで、もう一度言いますが、WindowsもVisual Studioは却下です。
 話を戻します。
 私の使えるコンパイラ言語には、アセンプラ(これはアセンブリ言語かな)、C、C++、VC++、C#、VC#(?)、Java(?)、VB(?)、 Fortran、COBOLなどがあります。
 ?が付いているのは、コンパイラ言語と呼んで良いのか?という意味です。
 これらの中で、最も高速なエグゼキュートができるのはアセンブラになります。
 ただ、アセンブラでは、目的のFastCGI用のライブラリが出ていませんし、自分でFastCGIと接続する手法も良くわかりませんので、現実的では ありません。
 そうすると、アセンブラとほぼ互角のスピードを出せるのが唯一C言語となりますので候補はC言語となります。
 C++などのオブジェクト指向プログラム言語と比べると随分組み難いと言われるところもありますが、C++と比較しても速度は圧巻です。
 私の計測したところ、C言語が10という単位時間でできることがC++だと13、VB6.0とJavaが50、Visual Studioは175です。
 ということで、コンパイラ言語でスピードを求めるのならC言語しか考えられないという結論になります。
 エグゼキュートを作る言語はC言語で決定です。

  ① : 6、FastCGI + C(エグゼキュート)

② : 4、SpeedyCGI + Perl(バイトコード)

 

Part 7、Google App Engine

 では、Google App Engineはどのようなシステムなのでしょうか?
 100万台規模のネットワーク型コンピューティングを無料で貸し出してくれているのです。
 やっぱり素晴らしいの一言に尽きます。
 使用言語は今のところPythonだけです。
 Djangoのフレームワークも利用可能です。
 データベースはGQLというネットワーク型データベースです。
 いずれにしても、これに勝つためには、同じPythonやそれより劣るPHPやRubyでは選択肢になりません。
 では、Pythonで考えると、どのような手法でGoogle App Engineが構築されているか候補を考えてみます。

 1、module型インタプリタ
 2、FastCGI + Python

 候補としては、基本的にこの2つだけです。
 この中でDjangoが使えると言うことは、module型インタプリタになります。
 SpeedyCGI + Perlは確かにmodule型Pythonよりも高速です。
 それでも、「Google App Engineより高速か?」と問われるとその自信はありません。
 Google App Engineはネットワーク型コンピューティングだからです。
 データベースにはGQLというネットワークデータベースが使える点もしかりです。
 互角程度には戦うことはできても、明らかに勝つということは難しそうです。
 ところが、各種データベースエンジンに最も高速な接続ができるものがあります。
 それは、C言語です。
 ここでもC言語は引けを取っていません。
 それ以上にC言語は、コンパクトなコードでメモリを自由に操作できます。
 ということは、巨大なデータベースでは無理ですが、遅いOlacleやMySQLなどを使わず、メモリ上だけでのデータベースを構築してしまえば、間違 いなくGoogle App Engineを超えます。
 そうです。
 答えはでました。
 FastCGI + Cです。
 これならば勝てる可能性が大なのです。
 これ以外の選択肢なら、わざわざWebアプリケーションだけのためにMyServerを構築する必要性はないでしょう。
 Pythonも簡単で素晴らしい言語ですので、Google App Engineで組むことこそがベストな選択肢と言えるでしょう。

  ① : 6、FastCGI + C(エグゼキュート)

Part 8、結論

 FastCGI + C
 これが「安全で高速で負荷の少ないシステム」としての最強の選択肢になりました。
 他スクリプト言語などでは考えられない非生産性ですが、一つ一つ再利用可能な関数を作っていけば、半年もあれば結構使えるようになるでしょう。
 早速いくつか作って試してみましたが、「ローカルなエグゼキュートを動作させるよりも速いかも?」と思えるほどの爆速です。
 すでにメモリ上にエグゼキュートがプロセスを生成して乗っかっているので当然です。
 巨大なものは作っていないので、まだ最終結論には至りませんが、手ごたえとしてもGoogle App Engineよりもかなり高速な気がしています。
 製作するポイントとしては、

 1、基本的にHTMLなどは全てプログラムコード内に入れる。
   → これによって全くストレージアクセスしないのでC言語の高速性をそのまま引き出せる。
 2、やれることはできるだけクライアントのJavaScriptで行う。
   → これによって、ネットワークコンピューティングでない1台だけのサーバでも負荷に耐えられるようになる。
 3、外部データベースエンジンを利用せずに全てメモリ内で処理する。
   → OracleやMySQLは遅いのです!SQLなど使わず、メモリ上だけのデータベースを自分でしっかりと設計し、うまく運用すれば、それが最 も安全で高速で最強なのです。

 と、とりあえずはこんなところでしょうか。
 こう考えると、現在のIT業界から反発が来そうな非生産的な結論に至りました。
 また、多人数で開発するには難しいということも言えます。
 生産性を考えれば、HTMLは外に出すべきでしょうし、クラスが使えて、コード量が少なくてすむスクリプト言語を選択すべきでしょう。
 力のある技術者が作って、しっかりとデバッグされたWebAPIを利用し組んでいくのが安全性を考えても良い選択肢でしょう。
 技術力はあがりませんし、性能は低いものになるでしょうが、多人数開発ができて、短期間で完成できて、それなりの品質で、効率的で、楽で、安全というこ とは言えます。
 そう考えると、Google App Engineは素晴らしい選択肢です。
 Microsoftが「10年後にはほとんどのサーバアプリケーションがクラウドに移行するだろう」とか言っていましたが、まんざらでもなさそうです。
 私の検証した結果、FastCGI + Cか、SpeedyCGI + Perl以外においてはクラウドに移行した方がメリットが大きいのです。
 最近MyServerでわざわざRubyを実践している人など見かけますが、私には到底メリットを見い出すことができません。
 遅い環境の上で、遅い言語を使って、遅いシステムを構築しても意味がありません。
 MyServerの購入代金や毎月500円の電気代がもったいない限りです。
 デザイン系の人でPHPをやっている人なんかは仕方ないですが、プログラマなら今すぐに移行を検討した方が良いでしょう。
 そのうち仕事がクラウドに全面移行したり、サーバ構築して組むのならFastCGI + Cか、SpeedyCGI + Perlあたりに限定されても仕方ないでしょうから。
 さらにいうなら、Native Clientを考えれば、JavaScriptの数十倍の速度でクライアント側で処理できるわけですので、WebプログラマはC言語が必須となる可能性す らあります。
 色々えらそうなこと言ってしまいましたが、Webシステムはそんなに単純なものではないので、今後とも継続的に変化を見定め、新しい技術を吸収しつつ見 ていかなければなりません。

 今回の検証は理論的なもので、実際に動作させてみると、大差はなくとも、module系がFastCGI系に勝るような場面も諸先輩方のサイトで 確認できます。
 ですので、そういう考え方もあるという程度でおさめていただければと思います。

 

ここでの文章、画像、検証結果などは全てDreamHopeに著作権があります。リ ンクに関してはTopLink、DeepLinkともに構いませんが、全部・一部の「学術論文等許諾の不必要な引用」以外の引用に関しては禁止します。

Copyright (C) 2009 DreamHope All Rights Reserved .  Access: