Strawberry Perl PortableZIP editionをファイルサーバに置いて使用する

Strawberry Perlは、Windows用Perlの実装の1つです。リリースには複数の種類があり、「PortableZIP」というエディションも用意されています。これにはStrawberry Perlの関連ファイルがまとめられており、PC上に展開するだけで、インストールする事無く実行する事ができます。

そして、この展開したファイル群をファイルサーバに置いても実行させる事ができるので、(信頼されたネットワーク内に限るべき、ですが、)ファイルサーバにアクセスできるWindows PCであれば、事前に何の準備もする事なく、Perlスクリプトを実行できます。

例えば、拙作のWAF+PSGI serverのOneman、OnemanベースのWebアプリと合わせてファイルサーバに置く事で、ネットワーク内の全てのPC上でWebアプリを動作させる事ができます。

ファイルサーバへの配置

例として、以下のように、Strawberry Perl、Oneman、Webアプリモジュール、Webアプリ実行用Perlスクリプト、Perl実行用バッチファイルを配置します。
32bit用だけを置いておけば64bit PCでも動作しますが、ここでは環境変数を参照して、実行するプログラムを振り分けてみます。

\\Server\share\strawberry-perl-5.16.2.1-32bit-portable\
\\Server\share\strawberry-perl-5.16.2.1-64bit-portable\
\\Server\share\Oneman.pm
\\Server\share\MyWebApp.pm
\\Server\share\mywebapp.pl
\\Server\share\mywebapp.bat

MyWebApp.pm

Oneman WAFを使用したWebアプリケーションを作成します。
例としてHello, world!を表示するだけのアプリですが、次に作成するmywebapp.plから$Binを渡す等でファイルサーバのパスが取得できるので、ファイルサーバに対するファイルI/Oを行う事もできます。
もしくは$ENV{USERPROFILE}等を参照して、ローカルPCにファイルを保存してもよいかもしれません。

# MyWebApp.pm
package MyWebApp;
use base 'Oneman';
sub app {
    my ($self) = @_;
    $self->write('Hello, world!');
    return;
}
1;

mywebapp.pl

MyWebAppを動作させるためのスクリプトを作成します。
OnemanはPSGIサーバも内蔵しているため、$psgi_appからstart()メソッドを実行する事によりローカルPCでWebサーバが起動します。
start()メソッド(実体はOneman::oneman())のpreforkオプションを使い、ソケットをオープンした後、BUILDERとWORKERをforkする前に、ブラウザを起動させる処理を加えています。
また、jQuery等の静的ファイルも合わせて配置し、staticオプションにより出力させる事もできます。

# mywebapp.pl
use FindBin qw( $Bin );
use lib $Bin;
require MyWebApp;
MyWebApp->psgi_app->start(
    prefork => sub { system('START http://localhost:5000/') == 0 },
);

mywebapp.bat

mywebapp.plを実行するためのバッチファイルを作成します。
環境変数によりOSが32bitか64bitかを判別して実行ファイルを振り分けます。決定したperl.exeによりmywebapp.plを実行します。

# mywebapp.bat
@ECHO OFF

IF %PROCESSOR_ARCHITECTURE% == "x64" (
    SET PERL=\\Server\share\strawberry-perl-5.16.2.1-64bit-portableperl\bin\perl.exe
) ELSE (
    SET PERL=\\Server\share\strawberry-perl-5.16.2.1-32bit-portableperl\bin\perl.exe
)

%PERL% \\Server\share\mywebapp.pl

実行

以下のコマンドをローカルPCのコマンド プロンプトから実行します。

>\\Server\share\mywebapp.bat

もしくは、バッチファイルなのでショートカット (.lnk) を作成しておくと便利です。

Webサーバが起動した後に、自動的にブラウザが起動して、Webアプリのトップページが表示されます。

まとめ

このように、Strawberry Perl PortableZIP editionをファイルサーバに展開して使用すれば、特別にWebサーバを用意する事なく、複数のPCでPerlベースのWebアプリを動作させる事ができます。

ただし、ネットワーク上に置いたファイルをローカルPCで実行する事になるので、セキュリティポリシーによっては正常に動作しないかもしれません。また、動作する場合においても、それらファイルが悪意あるユーザから不正に書き換えられないようにするため、一般ユーザには読み込みのみが可能になるよう管理者が配置する、等の工夫が必要です。

Oneman 0.22 – Starmanに肉薄する速さ YMMV ;-)、ほんとか??

細かな修正を行い、Oneman 0.22を公開しました。

さて、Onemanの機能数や品質は低く、Starmanには到底及びませんが、さて速さはどんなものだろうと思い、試してみました。

ベンチマークに使用したのはHello.psgi。

my $app = sub {
    my $env = shift;
    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ "Hello World" ],
    ];
};

StarmanとOnemanをそれぞれ以下のように実行して、ab (Apache HTTP server benchmarking tool) により秒間リクエスト処理数を計測します。

$ starman --workers 10 Hello.psgi
$ perl -MOneman -e 'oneman "Hello.psgi", workers => 10'

StarmanもしくはOnemanと、abは、いずれもLet’snote CF-R8 (Windows 7) のVirtualBoxで動作するUbuntu上で実行します。Perlは5.16.2、abのオプションは以下のとおり。

$ ab -c 10 -t 1 -k http://127.0.0.1:5000/

StarmanとOnemanを交互に3回実行して、それぞれでabを5回ずつ実行、計30回のベンチマークを取りました。さてその結果は?

やっぱりStarmanは速いですが、Onemanも意外に健闘しています。

Starman 0.3006
    Requests per second:    544.31 [#/sec] (mean)
    Requests per second:    616.26 [#/sec] (mean)
    Requests per second:    635.29 [#/sec] (mean)
    Requests per second:    682.02 [#/sec] (mean)
    Requests per second:    639.67 [#/sec] (mean)

    Requests per second:    591.27 [#/sec] (mean)
    Requests per second:    788.01 [#/sec] (mean)
    Requests per second:    728.52 [#/sec] (mean)
    Requests per second:    746.70 [#/sec] (mean)
    Requests per second:    727.46 [#/sec] (mean)

    Requests per second:    608.93 [#/sec] (mean)
    Requests per second:    705.51 [#/sec] (mean)
    Requests per second:    746.26 [#/sec] (mean)
    Requests per second:    739.99 [#/sec] (mean)
    Requests per second:    729.13 [#/sec] (mean)

Oneman 0.22
    Requests per second:    540.42 [#/sec] (mean)
    Requests per second:    648.77 [#/sec] (mean)
    Requests per second:    609.61 [#/sec] (mean)
    Requests per second:    637.44 [#/sec] (mean)
    Requests per second:    615.70 [#/sec] (mean)

    Requests per second:    443.15 [#/sec] (mean)
    Requests per second:    640.58 [#/sec] (mean)
    Requests per second:    625.77 [#/sec] (mean)
    Requests per second:    656.86 [#/sec] (mean)
    Requests per second:    639.11 [#/sec] (mean)

    Requests per second:    517.57 [#/sec] (mean)
    Requests per second:    638.55 [#/sec] (mean)
    Requests per second:    626.50 [#/sec] (mean)
    Requests per second:    634.62 [#/sec] (mean)
    Requests per second:    645.03 [#/sec] (mean)

特定の環境でのテストではありますが、Onemanも実用に十分耐える速さと言えそうです。ちょっと嬉しい。
しかし、仮想環境でのベンチマークとは言え、StarmanのPODに載せられている結果と1桁違うのがなんとも。。

また、Starmanには、

High Performance
Uses the fast XS/C HTTP header parser

とあります。
Onemanはpure perlである事に加え、Keep-Aliveの実現と、(alarmを使えない)Windows上で実行時のタイムアウト処理のために、selectと1バイト取得の連続でヘッダの読み込みを行っているので、効率がかなり悪いです。
そのため、リクエストヘッダのサイズが大きくなると、Starmanとの差はもっと大きくなるかもしれません。

ソース

http://www.tamashiro.org/src/Oneman-0.22/
http://www.tamashiro.org/src/Oneman-0.22.tar.gz

Oneman 0.21 – PSGI版Movable Typeを動かせるようにしました

先日公開した自作のPSGIサーバOnemanは、Plack::Test::SuiteはPASSしたものの、巷のPSGIアプリケーションがきちんと動くのか?
そこで、PSGI対応したMovable Typeの動作確認をしてみました。

>perl -MOneman -e "oneman 'mt.psgi', workers => 10"
Oneman: accepting connections at http://0.0.0.0:5000/

ブラウザでアクセスしてみると、、動かない。。
トップページはきちんと表示され、おぉ、自分で作ったサーバでMTが動いている!という少しの感動があったのですが、まず静的コンテンツの取得が遅く、次のページにも遷移できない。

早速調査を行い、大きく2点の修正をして、Movable Typeが正常かつ軽快に動作するようになりました。これで多少は使えるサーバになったかな。

以下に、その修正点について書いています。

ハンドルからの入力を固定長化

PSGIアプリからのレスポンスがhandleの場合、getline()で処理をする前に、入力を64KBytesに固定長化するよう変更しました。

local $/ = 65536;

これを忘れていたためにgetline()で行毎に読み込みしていたため、jquery-ui.jsのような巨大なテキストファイルのレスポンスに時間を要していました。
固定長化した事で劇的に改善しました。64KBytesという値はPlack::Utilを参考にしています。

入力ストリームのバッファリング

ブラウザからのGETリクエストはうまく動作するのですが、POSTリクエストに反応しないため、MT::PSGIのソースを読んでみると、以下のコードがありました。

        syswrite $child_in, do {
            local $/;
            my $fh = $env->{'psgi.input'};
            <$fh>;
        };

クライアントが送信するデータをEOFまで読み込みさせています。なんと乱暴な!これではKeep-AliveなHTTP/1.1クライアントではアクセスできなくて当然ではないか、と思ったのですが、でもplackupやstarmanで試してみると正しく動作する。。

HTTP::Server::PSGIのソースを読んでみて分かったのですが、PSGIサーバ側でいったん入力をバッファリングしてあげるんですね。Oneman 0.20では、クライアントのソケットをそのままpsgi.inputに入れていたため、そこを修正して入力をバッファリングするようにしました。

これで無事Movable Typeが動作するようになりました。さて、次は何を動かしてみようかな。

ソース

http://www.tamashiro.org/src/Oneman-0.21/
http://www.tamashiro.org/src/Oneman-0.21.tar.gz