C10K対応Prefork型高速PSGI/Plackサーバの Monoceros をHTTP/1.1に対応させました。
https://metacpan.org/release/Monoceros
https://github.com/kazeburo/Monoceros
MonocerosではHTTPのKeepAliveに対応して、大量の接続を捌く事ができますが、リリース時点ではHTTP/1.0 KeepAliveにしか対応していませんでした。しかし、nginxのupsream などでは、keepaliveを有効にしてHTTPセッションを使い回したい場合にHTTP/1.1が求められます。
以前このあたりの事をしらべてblog書いています
nginx-1.1.x で httpなupstreamにもkeepaliveができるようになったので検証してみた
https://blog.nomadscafe.jp/2012/02/nginx-11x-httpupstreamkeepalive.html
これではMonocerosが活かせないということで既に1.1に対応しているStarmanを参考にしつつ、HTTP/1.1対応しました。対応したのは次の機能
- KeepAlive
- Transfer-Encoding: chunked (Request & Response)
- HTTP Pipelining
- Expect
これらに対応しつつ、今までのHTTP/1.0のKeepAliveも使えるようになっています。
ほとんど使われない機能ですが、HTTP Pipeliningにも対応していて
my $body = 'OK 'x10;
sub {
[200, ['Content-Type'=>'text/plain'],[$body]]
}
こんなpsgiを書いてMonocerosを起動してncを使って2つのリクエストを続けて投げてみると、
$ cat reqs.txt
GET /1 HTTP/1.1
Host: foo
GET /2 HTTP/1.1
Host: foo
Connection: close
$ cat reqs.txt | nc 10.xx.xx.xx 5000
HTTP/1.1 200 OK
Date: Fri, 17 May 2013 06:08:35 GMT
Server: Plack::Handler::Monoceros
Content-Type: text/plain
Transfer-Encoding: chunked
1e
OK OK OK OK OK OK OK OK OK OK
0
HTTP/1.1 200 OK
Date: Fri, 17 May 2013 06:08:35 GMT
Server: Plack::Handler::Monoceros
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: close
1e
OK OK OK OK OK OK OK OK OK OK
0
と、レスポンスも2つ得られました。Transfer-Encodingがchunkedにもなってますね。
Monocerosをnginx のバックエンドに設置してのベンチマーク
HTTP/1.1対応できたので、早速nginxのバックエンドにしてベンチマークしてみました。
Upstream KeepAliveを有効にすると、大体倍の性能になるようですね。ベンチマークに使ったのはab、参考としてabもkeepalive on/off切り替えてデータを取得しました。なお、直接 Monocerosにアクセスすると、2万強のreq/secがでます。この差がReverse Proxyする分のオーバーヘッドですね
ベンチマークに使った環境は前回と同じ、Xeon L5630 2.13GHz 4コア/8スレッド を2つ積んだサーバです。nginxとMonocerosを同じサーバに導入し、abは別のサーバから実行しました。
ベンチマークに使ったアプリケーション
my $body = 'OK 'x10;
sub {
[200, ['Content-Type'=>'text/plain','Content-Length'=>length($body)],[$body]]
}
残念ながら ab が Transfer-Encoding: chunked による KeepAliveに対応していないので、Content-Lengthを付けています。
Monocerosの起動は、
$ carton exec -- plackup -E production --port 5000 --max-workers=10 -s Monoceros --max-reqs-per-child=50000 -a app.psgi
nginx.confは主なところを抜き出すと以下。
worker_processes 1;
events {
use epoll;
worker_connections 10000;
}
http {
keepalive_timeout 5 3;
keepalive_requests 50000;
upstream backend {
server 127.0.0.1:5000;
keepalive 100;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend;
}
}
}
ab は -c 100 で実行しました。
$ ab -k -c 100 -n 50000 'http://10.xx.xx.xx:8080/
リクエストの数や接続数次第ではnginxのworker_processes/keepaliveなどの設定を変更する必要がありそうです。