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