ホーム

へぼい日記

XslateはSyntaxを変えても基本的には実運用上の速度は変わらない

  • 投稿者: chiba
  • 2010/8/13 金曜日 19:54:00
  • perl

TTの158倍速いというxslateですが、このベンチマークはSyntax::Kolonを使っています。
TT互換なSyntaxであるところの、Syntax::TTerseを使うとどうなるのかなということでhttp://github.com/nihen/p5-Text-Xslate/tree/add_tterse_benchのbenchmark/x-rich-enc.plとbenchmark/x-poor-env.plにTTerseも追加してみました。

以下結果

%perl benchmark/x-rich-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
Template/2.22
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.9502
1..5
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - TCS: Text::ClearSilver
ok 5 - HTP: HTML::Template::Pro
Benchmarks with 'include' (datasize=100)
          Rate     TT     MT    TCS    HTP Xslate TTerse
TT      78.6/s     --   -69%   -94%   -95%   -99%   -99%
MT       257/s   227%     --   -82%   -84%   -98%   -98%
TCS     1412/s  1697%   450%     --   -11%   -89%   -89%
HTP     1586/s  1918%   517%    12%     --   -88%   -88%
Xslate 13241/s 16752%  5054%   838%   735%     --    -1%
TTerse 13397/s 16951%  5115%   849%   745%     1%     --
%perl benchmark/x-poor-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Template/2.22
HTML::Template/2.9
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
1..4
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - HT: HTML::Template
Benchmarks with 'include' (datasize=100)
         Rate     TT TTerse Xslate     HT     MT
TT     49.5/s     --   -27%   -28%   -61%   -80%
TTerse 67.9/s    37%     --    -1%   -47%   -73%
Xslate 68.5/s    38%     1%     --   -46%   -73%
HT      127/s   157%    88%    86%     --   -50%
MT      253/s   411%   273%   269%    99%     --

このように誤差の範囲ぐらいの差しか無く同様に速い。
これはなぜかというと、Xslateは様々なSyntaxで書かれたテンプレートを共通の中間コードにコンパイルし、それをキャッシュしているためその中間コードはほぼ同一のものになるからです。
一応そのコンパイル部分には差が現れるが、ファイルキャッシュもできない環境というのはほぼありえないので実運用上、速度の差は無いと言ってよいとおもわれる。というわけでTT使ってる人は安心してTTerseに移行してみるといいと思うです。(互換性がどの程度あるのかは使ってないから知らないけど!)

ちなみにコンパイル部分のみのベンチマーク

% perl author/bench_compile.pl
Parser: Kolon v.s. TTerse
         Rate tterse  kolon
tterse 80.1/s     --   -42%
kolon   139/s    74%     --
はてなブックマーク - XslateはSyntaxを変えても基本的には実運用上の速度は変わらない

Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた

  • 投稿者: chiba
  • 2010/7/10 土曜日 23:53:26
  • perl

Path::AttrRouterというtypesterさんが開発されているdispatcherがあって、Catalyst-likeなControllerのattributeを拾ってきてルーティングテーブルを作成してくれるのが便利で使っています。

で、HTTPメソッドを考慮したルーティングを行ってくれる機能が欲しかったので追加してみました。
method_supportブランチとしてforkしてgithubにあげてあります。

使い方はこんな感じです。

use Path::AttrRouter;

{
    package MyController;
    use base 'Path::AttrRouter::Controller';

    sub index :Path { print "index\n" }
    sub post :Path Method('POST') { print "post\n" }
}


my $router = Path::AttrRouter->new( search_path => 'MyController' );

my $m;

$m = $router->match('/', 'GET');
$m->dispatch; # index

$m = $router->match('/', 'POST');
$m->dispatch; # post

Methodが指定されなかったsubroutineはGET, HEADがデフォルトになるようになってます。
一応後方互換性は考慮してあり、$router->matchの第二引数が空の場合は
どのメソッドでもマッチするようになっています。

本家にとりこまれればうれしいけれど取り込まれなければ別distとして継承使って作り直すかもです。

ところで、諸事情により前職を退職していまして、ブログURLを移転しています。
RSSリーダーに登録されていた方等は再度登録お願い致しますです。
一応302飛ばすようにしてはあるんですが、RSSリーダーって自動的にそこらへん追跡してくれないんすかね。

追記(2010-07-11 17:17)
http://twitter.com/#!/typester/status/18255875606
とのことです。確かにPath::名前スペースなのでHTTPメソッドに依存するのは筋悪でした。
HTTP::AttrRouterとかで作ってみようかなーと考え中。

はてなブックマーク - Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた

PlackにおけるCSRFとDNS-Rebinding対策

  • 投稿者: chiba
  • 2009/12/20 日曜日 11:32:53
  • perl

最近のwebセキュリティ界隈ではCSRFやDNS-Rebindingが話題ですが、Plackでアプリケーションサーバを立ち上げる際にこれらの対策をどのように行うかについてまとめてみました。

まず、CSRF対策ですが、拙作のPlack::Middleware::RefererCheckを使うことにより、RefererのチェックによるCSRF対策が行えます。CSRF対策としては、onetime token方式も存在しますが、個人的にはRefererチェックが導入が楽で好きではあります。Refererを送信しないクライアントを対象にしたサービスを運営される方は別途onetime token方式の対策をおこなってください。

Plack::Middleware::RefererCheckの使い方はこのようになります。(SYNOPSYSからの抜粋)

use Plack::Builder;

builder {
  enable 'RefererCheck', host => 'www.example.com', same_scheme => 1, error_app => sub { [403, [], ['Forbidden']] };
  $app;
};

# or more simply(host from $env->{HTTP_HOST} and same_scheme => 0)
# this is vulnerabilly for DNS Rebinding
builder {
  enable 'RefererCheck';
  $app;
};

さて、コード中にも書いてあるように後者のチェック用hostをHTTP_HOSTから取得する方法はDNS-Rebindingに脆弱です。しかし前者のように固定hostを設定することにより、DNS-Rebindingへの対策も同時にできることになります。尚、onetime token方式ではXHRのsame originポリシーの崩壊によりDNS-Rebindingへの対策を単体で行うことはできません。

このようにRefererCheckを固定hostで行うことによりCSRF対策においてはDNS-Rebindingに対応できますが、CSRFから保護されるページ以外についても当然DNS-Rebindingでのアクセスははじきたいところです。apache等においてはname base virtual hostを活用することにより、期待するホスト名以外のアクセスをはじくことができますが、PlackでもPlack::App::URLMap(mount)を使うことにより同様のことが可能です。

use Plack::Builder;
builder {
  mount 'http://example.com/' => builder {
    mount '/app' => $app;
    mount '/admin' => $admin_app;
 }
}

このようにすることにより、example.com以外のHOSTでのアクセスは404となります。mountは上記の例のように、hostの指定とpath_infoの指定を同時に行えるもので、apacheでいうとVirtualhostとLocationを一緒にしたような機能になります。なので、上記のコードは下記のコードと等価です。

use Plack::Builder;
builder {
  mount 'http://example.com/app/' => $app;
  mount 'http://example.com/admin/' => $admin_app;
}

もちろんホスト名を違うものをmountできますのでPlack単体でVirtualhostな運用もできます。URLMap便利ですね。

はてなブックマーク - PlackにおけるCSRFとDNS-Rebinding対策

Plack::Middleware::Header

  • 投稿者: chiba
  • 2009/12/3 木曜日 23:19:23
  • perl

Plack::Middleware::Headerをgithubに上げました。

これは、Plack::Middlewareレイヤーでレスポンスヘッダを設定するもので、Apacheでいうところのmod_headersに相当します。

使い方はこんな感じです。

use Plack::Builder;
builder {
    enable 'Header',
        set => ['X-Plack-One' => '1'],
        append => ['X-Plack-Two' => '2'],
        unset => ['X-Plack-Three'];
    $app;
};

自分はPlack::Middleware::Staticと併用してExpiresをつけたりするのに使うために作りました。IEがExpires: -1とかやっておかないとしばらくキャッシュしてIf-Modifled-Sinceなリクエストも投げてくれなくなっちゃうという弊害があったので。

あと、IE関連では、If-Modified-Sinceの値に”;length=***”という余計なものが付いてきてしまい(ここここを参照)、Middleware::ConditionalGETを有効にしても304を吐けなかったりしていたので、それを取り除くためのMiddlewareも書いてみました。こちらは名前とかがきもいのでgistレベル。

追記(2009-12-13 21:27): cpanにアップしました。あと、If-Modified-SinceのIEバグの件はmiyagawaさんがConditionalGET側で対応してくれました

はてなブックマーク - Plack::Middleware::Header

patternがemptyな場合には前回成功時のpatternが使われるというハマりポイント

  • 投稿者: chiba
  • 2009/11/26 木曜日 2:42:23
  • perl
print "match1\n" if "baz" =~ m{};
"foo" =~ m{foo};
print "match2\n" if "baz" =~ m{};

の結果は

match1

である。なぜならperldoc perlrerefに書いてある通り、

If 'pattern' is an empty string, the last successfully matched regex is used. 

であるから。

patternを動的に生成してたりする時に空になっちゃうケースなんかがあると思うので、その場合はマッチ処理自体を回避するようにしたほうがよいかと思われます。

最初バグかと思いました。

はてなブックマーク - patternがemptyな場合には前回成功時のpatternが使われるというハマりポイント

Casual Talks#1でLTしてきました

  • 投稿者: chiba
  • 2009/11/21 土曜日 22:35:56
  • perl

昨日(11/20)にperl-casualのCasual Talks#1にて拙作のFormValidator::NestedについてLTしてきました。

slideをslideshareにあげておきました。

得られた教訓
1. 実際に話し始めると早口気味になるのでスライド大目ぐらいが自分にはちょうどいいかも
2. プロジェクターにつなぐときはねじをちゃんとしめておく
3. やっぱり笑いを一つぐらいとっといたほうが場は暖かくなる
(PAUSE ID requestの際にcatalyst-pluginを作りたいと書いていたと言ったときに若干嘲笑気味の笑いはありましたがw)

自分以外も発表が初めてだという方も多かったのに、発表が皆さんうまくて非常に面白かったです。またの機会があったら今回の教訓を踏まえまた発表できたら幸いです。

主催されたyusukebeさん、会場の用意や二次会の(実質)幹事をされたnobjasさんお疲れ様でした。

はてなブックマーク - Casual Talks#1でLTしてきました

JSocketを使ってPOSTもストリーミングするPlackアプリ

  • 投稿者: chiba
  • 2009/10/20 火曜日 3:58:37
  • perl

さて、前エントリJSocketというのを作ったと書いたのですが、これは実はjavascriptで動くtwitter streamクライアントを作るならばmultipart/mixedを使うべきというのを読んで、レスポンスがpollではなくてストリーミングできるというのを知って、リクエストもやりたいよというふうに思ったのがきっかけでした。

まず、XHRでできないかを試してみたのですが、xhr.send(data)を一回読んでしまうと少なくともjavascript側ではリクエストは完了したと思ってしまって、再度xhr.send(data)しても反応はありませんでした。

そこでJSocketの登場です。JSocketを使うとhttpリクエストを断続的に送信することができます。やったですね。

で、Plack::Server::Coroを使って試しに
リアルタイムチャット
を作ってみました。どうぞお試し下さい。レスポンスもJSocketを使っていますのでmultipartに比べてboundary分お得だったりもします。テキストエリアに入力された文字がストリーミングで送信され、また他人のデータもストリーミングで受信できていると思います。ちなみに自分の発言もサーバから持ってきてるので一人でも確認できます。

ちなみにこれを1つのコネクションでやってしまおうというのがWebsocketなんだろうという認識ですね。ただwebsocketはhttpの上に一応のってますがハンドシェイク以外の部分はhttp/1.0やhttp/1.1的には正しくないでしょうし、JSocketでの二重接続であれば正しいhttpとしてふるまえるはずで、現行のapacheやproxy等でも扱える可能性があったりします。

あ、チャットのサンプルコードもgithubにあげてあります。

plackup -s Coro --app chat.psgi 

という感じでPlack::Server::Coroをお使いください。

はてなブックマーク - JSocketを使ってPOSTもストリーミングするPlackアプリ

javascriptからsocketが扱えるJSocketを作りました

javascriptからsocketを扱いたいなぁという事象が発生したんですが(それについては別エントリで)、SocketJSというのがあるんですがDownloadするところがなぜかSSLになっていてCAがCAcertでfirefoxだとデフォルトでは見れないので、かっとなって自分で作ってみました。今も反省していません。

コードはgithubからどうぞ。
使い方はjs/jsocket.jsに軽く書いてあります。

/*
 * Jsocket - Socket on Javascript
 * Author: Masahiro Chiba <nihen@megabbs.com>
 * Depends:
 *  - jQuery: http://jquery.com/
 *  - jQuery TOOLS - Flashembed: http://flowplayer.org/tools/flashembed.html
 * SYNOPSIS:
 *  JSocket.init('/static/JSocket.swf', function () {
 *     socket = new JSocket({
 *         connectHandler: connectHandler,
 *         dataHandler:    dataHandler,
 *         closeHandler:   closeHandler,
 *         errorHandler:   errorHandler
 *     });
 *     socket.connect(location.hostname, location.port || 80);
 *  });
 *  function connectHandler() {
 *      socket.write("GET / HTTP/1.0\x0D\x0A\x0D\x0A");
 *      socket.flush();
 *  }
 *  function dataHandler(data) {
 *      alert(data);
 *      socket.close();
 *  }
 *  function closeHandler() {
 *      alert('lost connection')
 *  }
 *  function errorHandler(errorstr) {
 *      alert(errorstr);
 *  }
 *
 * */

こんな感じですね。flashの力を借りているので、Flashのソケットポリシーファイルとかを参考にポリシーファイルを配布するサーバを立ち上げておいてから使ってください。まる。

はてなブックマーク - javascriptからsocketが扱えるJSocketを作りました

mod_psgi試してみた

  • 投稿者: chiba
  • 2009/10/16 金曜日 18:17:20
  • perl

mod_psgi をインストールしてみたをみて速くなるなら試してみようということでmod_psgiを試してみますた。

まずはこんな感じの簡単なPSGIアプリで。

my $app = sub {
    return ['200', [Content-Length => '5'], ['hello']];
};
ab -n 10000 -c 100
mod_psgi
 Requests per second:    1403.51 [#/sec] (mean)
mod_perl
 Requests per second:    668.33 [#/sec] (mean)
Standalone
 Requests per second:    702.46 [#/sec] (mean)
Standalone::Prefork
 Requests per second:    725.78 [#/sec] (mean)

おおおお。超絶早いですね!
(plackupの際に-E product(development以外ならなんでもおk)をつけないとだいぶ遅くてそれをそのまま載せてたのを修正しました)

で、お次は、Catalyst::Engine::PSGIを使ってCatalystのhello worldなアプリを。

catalyst.pl Hello

で作って、debugモードを切って、Root.pmのindexで

    $c->response->content_type('text/plain');
    $c->response->body( 'hello' );

こんな感じにしたもの。

ab -n 1000 -c 10
mod_psgi
 Requests per second:    207.87 [#/sec] (mean)
mod_perl
 Requests per second:    144.94 [#/sec] (mean)
cat-standalone
 Requests per second:    184.95 [#/sec] (mean)

おおおおお。早いですね!!これはこれだけでも乗り換える意味がありそうだ。と思ってたんですが現在実運用中のCatalystアプリでやってみたところ”child pid 32320 exit signal Segmentation fault (11)”とかいって死にました。うーむ。これは再現する最小構成を探ってid:spiritlooseさんにフィードバックしたいところですね。

casual-perlerな人たちは今持ってるCatalystアプリをmod_psgi+Catalyst::Engine::PSGIで動かしてどんどんフィードバックするといいんじゃないかな!

はてなブックマーク - mod_psgi試してみた

Archer and Git

  • 投稿者: chiba
  • 3:17:31
  • git

最近会社のレポジトリ管理も順次gitに移行しようとしてるのですが、今までArcher&svnでデプロイしていたものをgit用にarcher.ymlを書き換えしてみた。

汎用的にはこんな感じ。中央サーバのレポジトリにreleaseというブランチを作っておいて、作業者もそれの追跡ローカルブランチなreleaseを作っておくというのが前提。releaseに直接コミットは厳禁。

git stash saveがあるから作業ディレクトリを別に用意する必要ないかなぁとか思ってこんな形にしてみた。今のところ満足してるけど運用しているうちになんか不具合がでるかもしれない。

はてなブックマーク - Archer and Git

1 2 3 4 5 6 7 8 9

ホーム

検索
フィード
メタ情報

ページの上部に戻る