Hateburo: kazeburo hatenablog

Operations Engineer / Site Reliability / 運用系小姑 / Perl Monger

アプリケーションに手を入れずに #isucon 2013 予選のperlアプリケーションのスコアをあげてみようの巻

ということで、やってみた。

初期

オンライン予選で使用した問題が手元で再現できるAMIを公開しました」に書かれているAMIを使って起動し、まず、初期状態でのベンチマークを取ってみる。

2013/10/28 14:21:18 done benchmark
Result:   SUCCESS 
RawScore: 865.9
Fails:    0
Score:    865.9

disble?

たぶんミスだと思うのですが、Starmanの起動オプションがdisbleになっていたので修正

- command=/home/isucon/env.sh carton exec -- plackup -s Starman --workers 10 --port 5000 -E production --disble-keepalive app.psgi
+ command=/home/isucon/env.sh carton exec -- plackup -s Starman --workers 10 --port 5000 -E production --disable-keepalive app.psgi

supervisorctl reloadしてベンチマークを動かすとかなり結果がよくなった

2013/10/28 14:24:15 done benchmark
Result:   SUCCESS 
RawScore: 1857.9
Fails:    0
Score:    1857.9

Monoceros & OpenFileCache

次にこのエントリで紹介した、Monoceros と Plack::Middleware::Static::OpenFileCacheをいれる。

diff --git a/app.psgi b/app.psgi
index 2fb2ba5..220fd06 100644
--- a/app.psgi
+++ b/app.psgi
@@ -13,7 +13,7 @@ my $root_dir = File::Basename::dirname(__FILE__);
 my $app = Isucon3::Web->psgi($root_dir);
 builder {
     enable 'ReverseProxy';
-    enable 'Static',
+    enable 'Static::OpenFileCache',
         path => qr!^/(?:(?:css|js|img)/|favicon\.ico$)!,
         root => $root_dir . '/public';
     enable 'Session',
diff --git a/cpanfile b/cpanfile
index 25ca66c..21fe478 100644
--- a/cpanfile
+++ b/cpanfile
@@ -9,3 +9,11 @@ requires "DBD::mysql";
 requires "Starman";
 requires "Plack::Session";
 requires "Cache::Memcached::Fast";
+
+requires "Monoceros", 0.26;
+requires "EV";
+requires "Guard";
+requires "Sys::Sendfile";
+requires "Linux::Socket::Accept4";
+requires "Plack::Middleware::Static::OpenFileCache";

HelloWorldなベンチマークではStarmanよりMonocerosの方が速いっていうのと、sendfileによって静的画像のレスポンスがよくなるのを狙った。

supervisord.condを書き換えて

- command=/home/isucon/env.sh carton exec -- plackup -s Starman --workers 10 --port 5000 -E production --disable-keepalive app.psgi
+ command=/home/isucon/env.sh carton exec -- plackup -s Monoceros --workers 10 --port 5000 -E production --disable-keepalive app.psgi

ベンチマーク

2013/10/28 14:35:00 done benchmark
Result:   SUCCESS 
RawScore: 1925.2
Fails:    0
Score:    1925.2

ちょっとスコアあがった。
Starletでも同程度になったので、sendfileは影響ない感じでした。

Kossy 0.23

Kossy 0.23uri_forとResponse->finalizeの最適化が入っているのでアップデート

diff --git a/cpanfile b/cpanfile
index 21fe478..78d7bf9 100644
--- a/cpanfile
+++ b/cpanfile
@@ -1,4 +1,4 @@
-requires "Kossy", 0.19;
+requires "Kossy", 0.23;
 requires "DBIx::Sunny";
 requires "JSON::XS";
 requires "Digest::SHA";

また少しスコアあがる

2013/10/28 14:38:03 done benchmark
Result:   SUCCESS 
RawScore: 2012.7
Fails:    0
Score:    2012.7

Plack::Middleware::Session::Simple

ここで紹介した、セッション周りの改善。keep_emptyを無効にして空のセッションを保存しない、Set-Cookieを行わないようにした

diff --git a/app.psgi b/app.psgi
index 220fd06..2c98b6a 100644
--- a/app.psgi
+++ b/app.psgi
@@ -16,16 +16,12 @@ builder {
     enable 'Static::OpenFileCache',
         path => qr!^/(?:(?:css|js|img)/|favicon\.ico$)!,
         root => $root_dir . '/public';
-    enable 'Session',
-        store => Plack::Session::Store::Cache->new(
-            cache => Cache::Memcached::Fast->new({
-                servers => [ "localhost:11211" ],
-            }),
-        ),
-        state => Plack::Session::State::Cookie->new(
-            httponly    => 1,
-            session_key => "isucon_session",
-        ),
+    enable 'Session::Simple',
+        store => Cache::Memcached::Fast->new({
+            servers => [ "localhost:11211" ],
+        }),
+        httponly => 1,
+        cookie_name => "isucon_session",
+        keep_empty => 0,
     ;
     $app;
 };
diff --git a/cpanfile b/cpanfile
index 78d7bf9..78d3475 100644
--- a/cpanfile
+++ b/cpanfile
@@ -15,5 +15,5 @@ requires "EV";
 requires "Guard";
 requires "Sys::Sendfile";
 requires "Plack::Middleware::Static::OpenFileCache";
+requires "Plack::Middleware::Session::Simple";

もうちょいスコア増えた。

2013/10/28 14:46:10 done benchmark
Result:   SUCCESS 
RawScore: 2131.1
Fails:    0
Score:    2131.1

まとめ

初期 865.9 から 2131.1 と約2.5倍ぐらいの改善となりました!やった!

ちなみに同じインスタンス上で、rubyのアプリケーションを動かした場合のスコアは

2013/10/28 15:05:04 done benchmark
Result:   SUCCESS 
RawScore: 2386.1
Fails:    0
Score:    2386.1

何が違うんだろう..