#isucon に参加してきました&isuconツールを試してみました

「なんでもありの」といううたい文句の通りに楽しめたチューニング大会#isucon に参加してきました。

最初は参加するつもり無かったんですが、知ってる方がかなり参加されそうだったのと、MySQL Casual の帰りに@kamipo さんが

「3 人チームで#isucon に申し込んだけど、『kamipo』『未定』『未定』やねん!」

と悲しそうにしていたので、kamipo さんと 2 人チームで参加させて頂くことになりました。kamipo さんホントありがとう!!ちなみにチーム名はふたりとも大好きな「チームやすべえ」

あんま大したことができなかったし、藤原組とかいうや ◯ ざなチームが圧倒的な強さを見せたりしていたので、真面目な話はそちらにお譲りします!

ちーむやすべえの軌跡

  • 僕は週後半の激務で朝起きられるか不安に思いながら AM2:00 頃寝てなんとかギリギリ起きたら、kamipo さんは明け方まで AKB 充で気力満タンだった

  • 2 人とも前日まで会場は livedoor だと思ってた

  • とりあえずレッドブル注入

  • isucon 開始

  • kamipo さんの toprc をみて、僕と kazeburo さんで「へぇ〜こんなのあるんだ、kamipo さんすごい!」

  • 僕の MacBook フリーズ

  • とりあえずサイドバーのクエリひどいので、fujiwara さん達と同じくカラム追加してアプリ変更

  • 何回かベンチして js とか結構遅そうと思う

  • マックで作戦会議

    • リバプロを nginx にしてそこで静的コンテンツを返そう
    • リバプロ、DB にも app を入れよう
  • kamipo さん、慣れない CentOS に nginx 入れるも、kazeburo の罠(keepalive)にハマったことに気づけず撃沈

  • nginx は諦めて apache に戻して RewriteRule で静的コンテンツのみリバプロで返す様に

  • app を増やすとなんか微妙に遅くなったりエラーになったり

    • あとで気づいたけど、DB で Too many connection 出てたせいかも
    • apache のプロセス数とかいじったらなんか変に遅くなったりして僕泣きそうに
  • とりあえずレッドブル注入

  • 記事の GET が遅いし数多いのでキャッシュ使えないか kamipo さんの頭がフル回転

  • 僕の MacBook フリーズ

  • app をもう 1 台追加して apache のプロセス数適当に減らしてなんとか落ち着かせる

    • この辺で 50000 req/min が限界
  • kamipo さんが memcached 使う箇所を決めたので、慣れない CentOS で kamipo パッチを当てた memcached をビルド

  • kamipo さん修正アプリを試してみるも、なんか memcached うまく使えてないかも

  • 時間切れ

こんな感じでしたかね、多分。kamipo さん間違えてたらごめんなさい><てか、僕は何もやってない。。。

基本的には終始 vmlog とアクセスログでネックを見てました。基本的に設定とか SQL とかはググりまくって書いてました。もっと覚えろって話ですねすみません。2 人ともあまりこの手のアプリに慣れてなかったので、fujiwara さん達みたいに動的ページをまるごとキャッシュするという発想は思いつかず、あとで話を聞いて「ぐぬぬ。。。」という感じでした。

感想

最初のクソ SQL については、kamipo さんの言葉を借りると「まずスライムから出てきてくれる」と言っていた様に、分り易すぎるボトルネックがはじめに出てきてくれてすごい親切だし楽しめるなぁと思いました。チューニングの為には基本的にアプリを改修するしかなくて、まさに普段業務でやってる感じでしたね(ちなみにそこのコードは僕が書きました!)。

スライムを倒すと次はもう少し強敵が現れて、僕らはそれをうまく倒せなくて 50000 req/min 辺りが限界でした。というわけで、すごくよく設計されたいい教材だなぁと感じました。そして、なんとそのコード一式を公開してくれています!すごすぎる!

というわけで、MacBook Air につっこんで動かしてみました。

isucon ツールを使ってみた

とりあえず git clone してみると、tools と webapp がありますね。

$ cd ~
$ git clone https://github.com/tagomoris/isucon.git
$ cd isucon

アプリ

webapp の方が isucon のアプリです。こっちのセットアップは簡単。

僕は perl のしか使ってないのですが、mysql に config/database を突っ込んで config/hosts.json 作ってあとは README に書いてある通り。終わったら localhost:5000 で使えると思います。投稿とかしてみてください。

$ cd webapp/perl
$ cat ../config/database | mysql -uroot
$ vi ../config/hosts.json
{"servers":
  { "reverseproxy": ["127.0.0.1"],
    "webap": ["127.0.0.1"],
    "database": ["127.0.0.1"]}
}
$ curl -k -L http://cpanmin.us/ > ./cpanm
$ chmod +x ./cpanm
$ ./cpanm -Lextlib -n --installdeps .
$ perl -Mlib=extlib/lib/perl5 extlib/bin/plackup -s Starman -E production --preload-app app.psgi

perl/etc にある conf を使って supervisord 経由で上げておくと便利ですね。後でまとめて説明します。

ベンチマークツール

ベンチマークツールの方は若干大変でした。まずベンチマークツールの概要は以下です。ちなみに node.js で動いています。

  • master.js

    • 全チームのスコアが見れるページ
    • ブラウザから自分のチームのサーバにベンチをかけることができる
  • agent.js

    • master.js から呼び出されてベンチをキックしたりする
  • bench.js

    • agent.js から呼び出されて実際にベンチ(http_load)を実行する

master.js と agent.js はデーモンとして起動しておく必要があるので、tools/etc 配下の conf を真似て supervisor で起動する準備しておきます。さっきの webapp もあわせて以下の様に include を指定しておきました。ini の方は環境にあわせて適当にパスを変更しておいて下さい。あと program も被らないように。

$ vi etc/supervisord.all.conf
# supervisord.agent.confからコピペ
(snip)

[include]
files = bench_master.ini bench_agent.ini ../../webapp/perl/etc/isucon.ini

$ vi etc/bench_agent.ini (他もこんなイメージで)
[program:isucon_agent]
command=/Users/riywo/isucon/tools/etc/agent.sh
process_name=isucon bench agent
stdout_logfile=/tmp/isucon.agent.log
stderr_logfile=/tmp/isucon.agent.log

あと、node.js は適当にインストールして下さい。オススメは nvm で入れて、npm で必要なモジュールを入れる。多分こんな感じ

$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ . ~/.nvm/nvm.sh
$ nvm install v0.4.11
$ nvm use v0.4.11
$ npm install async express jade jsdom mysql (足りないかも?)

master.js は DB にデータ入れるので、etc/master.sql を DB に入れておきます。

$ cd tools/etc
$ cat master.sql | mysql -uroot

次に、チーム情報とかを持っている config.json をテスト用にしてしまいます。

{
  "master":{
    "host":"localhost:3080",
    "pass":"obU9HNc3rk5N"
  },
  "bench": {
    "bench01": "localhost:3101"
  },
  "teamlist": [
    "team01"
  ],
  "teams": {
    "team01": {"id":"team01", "name":"てすと", "pass":"pass", "bench":"bench01", "target":"localhost:80"}
  }
}

チーム数減らすと views/index.jade が微妙にエラーになるので適当に編集。

     #scoreboard
       table#waku
-        - each row in [0,1,2]
+        - each row in [0]
           tr.dan
-            - each col in [0,1,2,3,4,5,6]
+            - each col in [0]

あと、http_load をパッチ当てて make。

$ cd http_load
$ tar xvzf http_load-12mar2006.tar.gz
$ patch -p0 < http_load.patch
$ cd http_load-12mar2006
$ make

lib/http_load.js が呼び出すパスが微妙にずれてたので修正。

-var HTTP_LOAD_PATH = __dirname + '/../http_load-12mar2006/http_load';
+var HTTP_LOAD_PATH = __dirname + '/../http_load/http_load-12mar2006/http_load';

あと、perl 環境がイマイチな人は static_check.pl が動く様に以下実行。僕は perlbrew で入れてたので多分要らなかった。

$ cd tools
$ curl -k -L http://cpanmin.us/ > ./cpanm; chmod +x ./cpanm
$ ./cpanm -Lextlib -n JSON Furl

これで supervisord を入れて起動すれば、webapp(localhost:5000)と、ベンチマークツールの web 画面(localhost:3080)が上がっているはず。

$ cd tools
$ easy_install supervisor  (pythonある前提)
$ supervisord -c etc/supervisord.all.conf

あとは、localhost に apache なり nginx なりを 80 番で起動して、全て localhost:5000 にプロキシするように設定したらベンチマークが通るはずです。(「idle」を押して pass と入力)

ちなみにとりあえず叩いてみたら MacBook Air 11 インチ RAM 4GB で 13288 req/min とか出ました。ただ、#isucon の時とはちがってデータが空なのでクソ SQL が問題にならないせいですね。適当にデータ突っ込んでやってみると楽しそうです。

みんなでセルフ isucon やってみよう!

アプリもさることながら、ベンチマークツールもとてもよくできているので、ベンチを叩くのが楽しいですね。node と supervisor 入れれば簡単に動くと思うので、残念ながら#isucon に来られなかったみなさんもぜひ試してみて下さい。tagomoris さん、kazeburo さん、使い方間違ってたらごめんなさい><

個人的には apache の StartServers とかいじった時にえらく遅くなったりしたのが気になってるのでホントは色々試してみたいところ。

このツールはちょっとカスタマイズすれば新人研修とかで使えそうだなーと思ったので、動かすところまで持って行ってみました。が、node.js がさっぱり分からないのでちょっとカスタマイズするのもしんどそうです。。。webapp の方は、perl しか見てないですが、非常に少ないコードで書かれていて見通しもいい(CloudForecast で kazeburo ware に慣れてたし!)ので、別のアプリにするのは僕でもできそう。

というわけで、本当に livedoor の皆さんお疲れ様でした。すばらしいイベントだったと思います。懇親会でいろんな方とお話ししたかったのですが諸事情により参加できず残念でした!次回があるのかどうかは分からないとのことでしたが、もちろんやってくれますよね!?