Hateburo: kazeburo hatenablog

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

最近の Plack のパフォーマンス改善まとめ 2015年11月版

OSS活動の成果発表のお時間です。

Plackの 1.0038と2015年11月27日時点のmasterにはPlack::Request、Plack::Responseのパフォーマンスをあげる変更が入ってます。その紹介とベンチマークです。

github.com

Plack 1.0038 で HTTP::Headers::Fast 0.20 につけた flatten メソッドを使うようになってます。Plack::Response->finalizeのパフォーマンス向上が期待できます。

github.com

こちらはまだmasterにmergeされた状態。リリースはされてない。POSTリクエストのパースにHTTP::Bodyではなく、HTTP::Entitiy::Parserを使い、パラメータのパースに WWW::Form::UrlEncodedを使うようになっています。

HTTP::Entity::Parserは tokuhirom の pullreq をベースに作ったモジュールで chansen の HTTP::MultiPartParserをuploadデータの解析に利用しています。GETのクエリーパラメータなどの文字列をパースする WWW::Form::UrlEncoded は XS版も用意され、インストールするだけで長いクエリパラメータの処理が超高速になります。

ベンチマーク

以下のような psgi を用意して Plackの 1.0037、10038、そしてmasterでベンチマークを行いました。

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');
        my $res = $req->new_response(200);
        $res->content_type('text/plain');
        $res->content_length($length);
        $res->body($body);
        $res->finilize;
    }
};

ベンチマークを行ったサーバはgcpの12コアのサーバです。下記のsysctlのチューニングを行いました

sudo sysctl -w net.core.netdev_max_backlog=8192
sudo sysctl -w net.core.somaxconn=32768
sudo sysctl -w net.ipv4.tcp_tw_recycle=1
sudo sysctl -w net.ipv4.tcp_tw_reuse=1

perlは5.20.3、Starletは 0.28、Gazelleは0.40です。

起動オプションは Starlet、Gazelleともに同じです。

plackup -s (Starlet|Gazelle) -E production --max-workers=10 --max-reqs-per-child=5000000 -a app.psgi 

ベンチマークは wrk にて取りました

./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'

結果

f:id:kazeburo:20151127160552p:plain

1.0037から1.0038は微増。1.0038からmasterは PP版で5%ほどのパフォーマンス向上、XSになると15-20%のパフォーマンス向上となりました。WWW::Form::UrlEncoded::XSを使うと実際のアプリケーションでも差異がでるかもしれません。

以下wrkコマンドの結果

Gazelle + Plack 1.0037

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   375.59us  187.59us   9.30ms   98.41%
    Req/Sec     8.58k     0.93k   12.50k    91.67%
  512632 requests in 30.00s, 1.98GB read
Requests/sec:  17085.90
Transfer/sec:     67.46MB

Gazelle + Plack 1.0038

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   369.07us  188.53us   8.06ms   98.86%
    Req/Sec     8.73k   686.61    12.24k    89.50%
  520994 requests in 30.00s, 2.01GB read
Requests/sec:  17365.83
Transfer/sec:     68.56MB

Gazelle + Plack master + WWW::Form::UrlEncoded::PP

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   347.94us  210.95us  10.08ms   98.87%
    Req/Sec     9.15k     0.90k   13.45k    91.33%
  546160 requests in 30.00s, 2.11GB read
Requests/sec:  18204.06
Transfer/sec:     71.87MB

Gazelle + Plack master + WWW::Form::UrlEncoded::XS

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   297.28us  220.10us  10.23ms   99.33%
    Req/Sec    10.30k     0.95k   14.73k    92.00%
  614871 requests in 30.00s, 2.37GB read
Requests/sec:  20494.01
Transfer/sec:     80.91MB

Starlet + Plack 1.0037

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   450.54us  175.99us   7.97ms   96.39%
    Req/Sec     7.38k     0.90k   11.11k    92.33%
  440509 requests in 30.00s, 1.71GB read
Requests/sec:  14683.24
Transfer/sec:     58.20MB

Starlet + Plack 1.0038

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   443.11us  175.54us   7.51ms   96.42%
    Req/Sec     7.47k     0.91k   11.22k    92.17%
  446088 requests in 30.01s, 1.73GB read
Requests/sec:  14866.09
Transfer/sec:     58.92MB

Starlet + Plack master + WWW::Form::UrlEncoded::PP

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   420.69us  177.07us   6.51ms   98.15%
    Req/Sec     7.82k   786.01    11.52k    91.33%
  467110 requests in 30.00s, 1.81GB read
Requests/sec:  15569.02
Transfer/sec:     61.71MB

Starlet + Plack master + WWW::Form::UrlEncoded::XS

$ ./wrk -t 2 -c 8 -d 30 'http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome'
Running 30s test @ http://localhost:5000/foo?foo=bar&bar=baz&q=HTTP%3A%3ARequest%3A%3ACommon&ie=UTF-8&sourceid=chrome
  2 threads and 8 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   373.80us  193.16us   6.98ms   98.96%
    Req/Sec     8.65k   785.91    12.77k    95.00%
  516923 requests in 30.02s, 2.00GB read
Requests/sec:  17222.14
Transfer/sec:     68.26MB