Chienomi

ConoHa WINGのLiteSpeed (LSAPI)について

製品・サービス::cloud

この記事はConoHa WINGに大してLiteSpeedの利用について問い合わせたものに対する回答が全く納得がいなかったので、検証したものである。

私の質問は次の通りだ。

WINGのサービス説明にLiteSpeedを採用している、との説明があり、実際にRack/LiteSpeedを使用して記事化しようと考えたのですが、ドキュメントにLiteSpeedの設定方法についての記載がなく、実際に利用することができません。

ドキュメントの所在 or 設定方法 ( or WordPress/EC-CUBEでしか利用できない?)についてお教え頂きたく存じます。

それに対する回答が次のとおり

記載させていただいております「LiteSpeed LSAPI」に つきましては、webサーバーとは異なる、PHPの動作の 種類となります。

※phpinfoコマンド内の「Server API」でも確認いただけます。

※WINGのwebサーバーにつきましては「Apache + nginx」  を採用しております。

また、動作環境は自動的に設定されるため、恐縮では ございますが、ドキュメントや設定方法のご用意は無い 状況でございます。

概要

LiteSpeedとはなにか

LiteSpeed Web Serverは公式にて次のように説明されている。

LiteSpeed Web Server conserves resources without sacrificing performance, security, or compatibility. Replace Apache with LiteSpeed, and double your maximum capacity, eliminate the need for a 3rd party caching layer, and get support for cutting-edge technologies like HTTP/3 - all in 15 minutes with zero downtime!

また、OpenLiteSpeedは次の通り。

Our Open Source web server is held to the same high standard as our Enterprise solution: OpenLiteSpeed is a high-performance, lightweight, open source HTTP server. Users are free to download, use, distribute, and modify OpenLiteSpeed and its source code in accordance with the precepts of the GPLv3 license.

つまるところ、LiteSpeedとはいわゆるアプリケーションサーバーである。

アプリケーションサーバーについて

ここでは、少々初歩的にすぎるが、アプリケーションサーバーが何か、ということを説明しておこう。

最も基本的な動作として、ウェブアプリケーションは伝統的なプロセスモデルによって実行される。 つまり、ウェブアプリケーションをプロセスとして起動し、その出力を応答とするのである。

このモデルで動作するものとして有名なのはCGIだ。 CGIの場合、アプリケーションの起動時、値を環境変数によって受け渡し、標準出力をウェブサーバーが受け取り、そのままレスポンスとして利用する。

十分に機能し、なおかつ普及したCGIで満足しなかった大きな問題はおおまかに2点だ。

ひとつは、ウェブサーバーがアプリケーションプロセスを起動し、その間スレッドがブロックされる、という問題だ。 これによってウェブサーバーが、そもそも応答できない状態が生じる可能性がある。 もっとも、この問題は現代においても多くの場合同様ではあるのだが。

もうひとつは、パフォーマンスである。 プロセスを生成する、forkとexecという動作は重く、ラグがある。 実際にはそこまでではないのだが、大量のリクエストをさばくときには足を引っ張る。 加えて、PerlやRubyのような重いインタープリタは、起動そのものに時間がかかる上に、そのあとスクリプトをコンパイルする作業が入る。このことから、今のLinux基準で言えば、fork/execのコストなんて目じゃないほど時間がかかる。

このことから考えられたのが、プロセスをデーモナイズする、という方法である。 処理系を起動し、スクリプトのコンパイルを終えたプロセスを、処理ごとに終了させずそのまま残して再利用することでこのコストをなくしてしまおう、というわけだ。

この代表格がFastCGIである。 この場合、毎回プロセスを起動するわけではないので、環境変数を使って受け渡すということはできない。 そこで、FastCGIでは標準入力からバイナリプロトコルで受け渡すことになっている。 FastCGIアプリケーションとウェブサーバーとの間ではTCP、もしくはUnixドメインソケットが利用される。

この方式は単純なプロセスモデルよりもパフォーマンス面で優れているが、問題もある。 それは、アプリケーションが単一の入出力であり、並列化できないということだ。 CGIの場合はサーバーのスレッド数で動作するので、スレッド数が多ければ並列性の差によって却って遅くなってしまう可能性すらある。

そこで、こうしたキューイング、マルチスレッドなどを実現するために考えられたのがサーブレットだ。

サーブレットはサーバーそのものにアプリケーションをロードした状態で組み込んでしまえば良い、という発想である。 これなら、並列化もサーバー側でコントロールできる。

初期のサーブレットとしてはmod_perlやmod_phpといったもの、そしてApache TomcatといったApacheがアプリケーションをロードしてデーモナイズするという方法が取られた。 だが、より高速で、より良いコントロールを実現するため、様々なアプリケーションサーバーが作られることになった。

この場合アプリケーションから見ると少し複雑である。 というのは、CGIスクリプトの場合、アプリケーションは単独で起動されるプログラムである。 そして、FastCGIではデーモンプロセスである。ここまではまぁいいだろう。1

サーブレットの場合、アプリケーションサーバーと一体になっている。単純に言えば、アプリケーションはサーバーフレームワークを用いてサーバーそのものをコントロールするコードを書くことになる。例えば次はWebrickを用いたRubyサーブレットである。

require 'webrick'

srv = WEBrick::HTTPServer.new({
  BindAddress: "127.0.0.1"
})

srv.mount_proc("/") do |req, res|
  res["Status"] = 200
  res["Content-Type"] = "text/plain; charset=UTF-8"
  res.body = Time.now.to_s
end

srv.start

だが、こうしたコードにはいくらかの問題がある。 最大の問題はサーバーが変わるごとにコードに対する大きな変更が必要となることである。 また、サーバーのコードを書く必要があり、サーバーフレームワークによって楽にかけるようになっているにせよ、煩わしさは否めない。

RackやSinatraはこうした問題を解消するものである。 例えばSinatraでは次のようにできる。

#!ruby
require 'sinatra'

get '/' do
  content_type "text/plain"
  Time.now.to_s
end

コントロール、分配に関しては必ずしもアプリケーションサーバーが担っているわけではない。 例えば、Thinサーバーはシングルスレッドで動作し、分配はリバースプロキシ(一般的にはNginxやApache)によって行うことになっている。リバースプロキシを使うのであれば、FastCGIでもできる(実はアプリケーションサーバーを使うメリットとFastCGIを使うメリットに著しい乖離があるわけではない)。

Unicornはアプリケーションサーバーがマスターがスレーブに分配する構造になっている。

いずれにせよ、アプリケーションサーバーを利用するということは、アプリケーションプロセスを永続させる、というところが肝であり、そうしないのであればCGIと何ら変わらないし、CGIで良い。

LSPHP, LSAPI

LiteSpeedは、LiteSpeed Web ServerとLiteSpeedアプリケーションとの間のやりとりの方法をLSAPIと呼んでいる。

これは、CGIやFastCGIのように、「値の受け渡し方」の話であり、LiteSpeedがどのように値を受け渡すのかということを理解していないと、アプリケーションを書くことができない。

LiteSpeed Web Serverのサーブレットとして動作するPHPアプリケーションをLSPHPと呼んでいる。

LSAPIがどのようなものであるのかを気にする必要があるのは、基本的にはLiteSpeedバインディングの開発者、ミドルウェアの開発者などである。

RubyのLSAPIバインディングも存在し、別にPHP専用というわけでもない。

もちろん、LiteSpeed互換のアプリケーションサーバーを作るのであれば、LiteSpeed Web ServerなしにLSAPIを使うということはできないではない。だが、その意味は恐らくないだろうし、LSAPIはあくまでLiteSpeedを使う上でアプリケーション側で知る必要がある情報に過ぎないと考えることができ、そして一般的なプログラマはその詳細を気にする必要はない。

LiteSpeed

LiteSpeedはアプリケーションサーバーであるが、アプリケーション(特にPHP)を高速に動作させるための工夫が入っている。PHP専用というわけではないのだが、RubyにとってのUnicornのように、PHPにとっては主たる選択肢として挙がるものだ。

Perl, Ruby, PythonでCGIを書いている人間としてはもはや使うことのなくなったFastCGIだが、PHPの場合はFPMというFastCGI実装があり、インターフェイスこそFastCGIだが、FastCGI実装としてはかなり現代的なアプリケーションサーバーに近い機能をもったものとなっている。

そして、PHPはFPMがあるからこそ、あまりアプリケーションサーバーを求める声がない。 だが、FastCGIよりも速い、つまりはPHP-FPMよりも速い実装のアプリケーションサーバーとしてLiteSpeedが有力視されているという格好だ。

もちろん、他にもNginx UnitなどのPHP対応のアプリケーションサーバーも存在する。

LiteSpeed Web Serverの大きな特徴として、ウェブコンソールがあり、このコントロールパネルからインスタンス化したいアプリケーションの指定ができる、というのがある。 LiteSpeedのデプロイはUnicornと似た連続性のあるモデルを採用していて、ダウンタイムがない。この技術を応用して、新規にアプリケーションがインストールされた場合はインスタンスを起動するし、アプリケーションが除外された場合は現在のリクエストが終了した段階でインスタンスを停止する。

検証する

前述の通り、LiteSpeedアプリケーションとして機能しているのであれば、プロセスは永続化されており、PIDは変化していないはずである。 逆に言えば、PIDが変化するのであればPHPスクリプトは毎回プロセスとして起動されているのであり、特に高速化はされていない(CGIと同等である)。

<?php
header("Content-type: text/plain; charset=UTF-8");

echo(getmypid());
echo("\n");
?>
% for i in {1..100}; do sleep 1.5;curl "http://example.com/test.php"; done
278263
278407
278802
278831
278983
279512
279630
279760
280330
280443
280917
281028
281177
281645
281751
281856
282332
282463
282931
283135
283681
283815
284385
284856
285003
285543
285673
285806
286408
286527
286636
287205
287319
287802
287997
288120
288258
288737
288847
288947
289313
289331
289938
290108
290245
290889
290998
291136
291742
291913
292060
292694
292879
293360
293568
293994
294108
294226
294761
294891
295415
295525
296040
296168
296765
297191
297319
297437
297999
298124
298626
298774
298889
299369
299478
299599
300024
300520
300570
300610
301207

自動的に設定されるとは一体?

複数回繰り返したのは、複数のワーカーにバランスさせている可能性があるためだ。 だが、ここまでたくさんのワーカーがあることはないので、都度プロセスを起動しているのは明らかだ。

確かにServer APIはLSAPIの表示があるのだが、LSAPIアプリケーションとしては動作していない。 そもそも、LSAPIアプリケーションとして動作させるには、LiteSpeed Web Serverにインスタンス化すべきスクリプトを指定した上で、何からのタイミングでリロードを行う必要がある。 LiteSpeed Web Serverに対して設定する方法がない以上、LiteSpeedアプリケーションをインスタンス化する方法がない。そもそもLiteSpeedが起動すべき対象を知る方法がないからだ。

phpinfo

考察

Server APIとしてLiteSpeed V7.6が表示されていて、かつ新規プロセスとして動いていることを考えると、.phpに対するハンドラをphpではなくlsphpにしているのではないだろうか。 phpコマンドでスクリプトを実行するとServer APIはCommand Line Interfaceになるが、lsphpだとLiteSpeedになる。

確かにこの場合、LSAPIを使っていること自体は事実だが、それだとConoHaの説明には問題がある。

LSAPIを使うのは前提として、PHPスクリプトがインスタンス化される(永続する)ことで意味を為すのであり、少なくとも高速化という意味ではphpコマンドをlsphpコマンドに置き換えることでは意味は発生しない。

だが、ConoHaの説明は、FastCGIよりも20%高速であるという内容がある。

ConoHa WINGによる説明

だがそれは、あくまでもLSAPIアプリケーションとして動作させた場合に高速であるという話であり、LSAPI経由で呼び出せば速いということではない。 特に、ConoHa WINGの場合、PHP動作環境として、FastCGIと比較して、とのことであるから、明らかにPHP-FPMとの比較であり、PHP-FPMはアプリケーションサーバーであることから、アプリケーションサーバーの動作速度比較でなければそもそも動作モデルが違うので比較としての意味をなさなくなる。

この混同は問題がある。知識が不足しているのか、わざとなのかは分からないが。

また、ConoHa WINGの場合はコントロールパネルからWordPressをインストールすることができ、この場合はLiteSpeedアプリケーションとして動作する、という可能性もある。このインストール作業はConoHa WINGのシステム的な機能であり、ユーザーレベルで行われるわけではないからだ。

だが、あくまでPHPの動作環境として考えたときに、 LiteSpeedを使うというアドバンテージを持っているわけではない。また、LiteSpeedアプリケーションとして動作する方法は与えられていないので、Rack/LiteSpeedやRuby LSAPIを使って動作させる方法もない。仮にあったとしてもメリットもない。

ConoHaのサポートは、もうちょっと丁寧に(というより慎重に)対応したほうが良いのではないだろうか。