最近の Plack のパフォーマンス改善まとめ 2015年11月版
OSS活動の成果発表のお時間です。
Plackの 1.0038と2015年11月27日時点のmasterにはPlack::Request、Plack::Responseのパフォーマンスをあげる変更が入ってます。その紹介とベンチマークです。
Plack 1.0038 で HTTP::Headers::Fast 0.20 につけた flatten メソッドを使うようになってます。Plack::Response->finalizeのパフォーマンス向上が期待できます。
こちらはまだ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'
結果
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