Hateburo: kazeburo hatenablog

SRE / 運用系小姑 / Goを書くPerl Monger

最近のPlack/Starletのパフォーマンス改善まとめ。最大2倍の性能向上

最近の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%の短縮となりました。ベンチマーク以外でも軽いアプリケーションであれば目に見える変化があるんじゃないかなと思います。