最近のPlackとStarletにはパフォーマンス改善のため次のような変更が加えられています。
Plackに対する変更 (カッコ内はバージョン)
- Plack::Request::query_parameters の最適化 (1.0018)
- Plack::Middleware::AccessLog に Apache::LogFormat::Compilerの導入 (1.0023)
Starletに対する変更
- local $SIG{..} を無くし、rt_sig* system call が呼ばれる回数を削減 (0.17_01)
- headerとbodyを結合して一度に出力する閾値を1024から8192に変更 (0.18)
ベンチマーク
これらの変更の効果を確認するために、次のベンチマークを実行してみます
まずアプリケーションはこんな感じ
use Plack::Builder; use Plack::Request; my $length = 4000; my $body = 'x'x$length; builder { enable 'AccessLog', logger => sub { }; sub { my $env = shift; my $req = Plack::Request->new($env); my @params = $req->param('foo'); [200, ['Content-Type'=>'text/plain','Content-Length'=>$length],[$body]] } };
Middleware::AccessLogを有効にして、paramを一度取得。あと4000byteのボディを出力します。
バージョン固定の依存モジュールの導入はcartonを使えば簡単。それぞれcpanfileは
旧バージョン
requires 'Plack', '== 1.0016'; requires 'Starlet', '== 0.16'; requires 'HTTP::Parser::XS';
最近版
requires 'Plack', '== 1.0023'; requires 'Starlet', '== 0.18'; requires 'HTTP::Parser::XS';
として carton install でモジュールをインストールします。Webアプリケーションの立ち上げはそれぞれのディレクトリで
$ carton exec -- plackup -s Starlet -E production --max-workers=10 --max-reqs-per-child=10000 -a app.psgi
としました。
ベンチマークは簡単に ab。
$ ab -c 8 -n 30000 'http://localhost:5000/foo?foo=bar&bar=baz&baz=hoge&hoge=foo'
localhostから実行
結果
旧バージョン
Concurrency Level: 8 Time taken for tests: 4.807 seconds Complete requests: 30000 Failed requests: 0 Write errors: 0 Total transferred: 124110000 bytes HTML transferred: 120000000 bytes Requests per second: 6240.83 [#/sec] (mean) Time per request: 1.282 [ms] (mean) Time per request: 0.160 [ms] (mean, across all concurrent requests) Transfer rate: 25213.20 [Kbytes/sec] received
最新版
Concurrency Level: 8 Time taken for tests: 2.444 seconds Complete requests: 30000 Failed requests: 0 Write errors: 0 Total transferred: 124110000 bytes HTML transferred: 120000000 bytes Requests per second: 12273.69 [#/sec] (mean) Time per request: 0.652 [ms] (mean) Time per request: 0.081 [ms] (mean, across all concurrent requests) Transfer rate: 49586.20 [Kbytes/sec] received
Requests per secondが6000req/secから12000req/secと2倍になって、1リクエストに掛かる時間も最大50%の短縮となりました。ベンチマーク以外でも軽いアプリケーションであれば目に見える変化があるんじゃないかなと思います。