みなさんISUCON予選おつかれさまでした。@fujiwaraとともに今回の予選の運営をしている@acidlemonです。予選問題はまず最初に@fujiwaraがPerlの初期実装を作って私が解き、おもったよりもサクサクだったので凶悪なクエリを追加して大体完成したところで、@fujiwaraがRuby, Python, Goの移植、私がNode.js、PHPの移植を行いました。

Node.js実装についてはsupervisordではなくstandaloneで動かすとtmpfile()が $HOME/tmp にテンポラリファイル作ろうとするため、コンソールから直接npm start等で起動した場合はそのようなフォルダがなくエラーとなる問題が1日目のAMIにありました。この点でハマってしまった方、申し訳ありません。

さて、講評につきましては明日以降みなさまより提出いただいたAMIを私と@fujiwaraでチェックし、順位が確定したタイミングで@fujiwaraから出る予定となっております。それに先立ち、まず私からはどのような問題だったのかの解説をしたいと思います。

予選問題の解説


今回のWebアプリは一言でいうとgithubのgistのようなWebアプリでした。大体以下の要件のWebアプリとなっています。

  • ログイン機能がある。CSRF対策がなされている
  • メモ(Markdown形式)を投稿する機能がある。投稿するときにメモを非公開にするかどうか選ぶことができる
  • トップページに最新の公開投稿100件を表示する
  • 公開投稿をページングして辿っていく機能があり、各ページ100ページずつ表示する
  • マイページに自分が投稿したメモを公開/非公開に関係なくすべてリスト表示する
  • メモの表示はMarkdownをHTMLに変換して行う。メモページからは次/前の公開メモを辿ることができる

  • また、競技を行うマシンはAWSのEC2に以下のようなAMIを準備しました。

  • OSは最新のAmazon Linux(x86-64)
  • TCP/80ポートをApache 2.4で待ち受け、すべてのアクセスをTCP/5000ポートへリバースプロキシする
  • TCP/5000は初期設定ではperl実装が起動している。起動する実装はphp以外supervisordで切り替え可能
  • PHPを使用する場合はサンプル提供しているApache用のconfファイルを有効にしてTCP/5000でPHPを動かす
  • ストレージは最新のMySQLとAmazon Linux標準のmemcachedをインストール
  • アプリの設定はPerl, Ruby, PythonのPrefork型アプリケーションサーバは10worker、Goはコントローラ部分が10並列、Nodeはclusterを使い2プロセス、PHPはApacheのデフォルト設定
  • アプリはセッションストアとしてmemcachedのようなものを使用

    各言語の初期スコアですが、大体 Go 2500 > Ruby 2000 > Python = Perl > Node.js = PHP といった感じになっています。初期のボトルネックはほぼDBとなっていましたのでアプリで処理を行う部分のスコアはほとんど同じ感じでしたが、Goが飛び抜けているのは静的ファイルを返す速度ですこし飛び抜けた感じになっています。最終スコアからすると誤差の範囲ですね。

    具体的に高速化していく解答方法については明日以降に別途エントリの場所を #isucon タグでお知らせしますが、まずは「あれは罠なの?」などと質問が飛びそうな点などについて以下で解説していきます。

    出題内容について


    Q. セッションストアにmemcachedのようなものを使っているのは罠ですか?
    A. まずどのぐらいの方が気付いたかわかりませんが、memcachedのデフォルトポートである11211ポートで起動していたのは純正のmemcachedではなくMySQL 5.6.14のInnoDB Memcached Pluginです。純正のmemcachedは11212ポートで起動していますので、セッションストアの接続先を11212ポートに変更するとMySQLの負荷が少しだけ下がったのではないかと思います。ただし、アプリが出すクエリのほうがよっぽど重かったと思います。

    また、memcachedではなくファイルに保存するという変更も可能かとおもいます。今回は1台のEC2の上にすべて乗っていますので、memcachedとファイルで差異はあまりでなかったのではないかと思います。

    Q. HTMLにCSSで / を指定したものがありましたが罠ですか?
    A. あれは多分罠ですね。@fujiwaraが「あるあるネタ」として仕込んでいました

    Q. 静的ファイルを返す部分にディレイを入れたらスコアが下がりましたが罠ですか?
    A. チェッカーも静的ファイルを取りにいきますのでディレイを入れたらチェッカーが遅くなるのでスコアが下がるでしょうね。

    Q. gzipをONにするとスコアが下がりましたが罠ですか?
    A. ベンチマークツールとアプリが同じマシンにありますので、ベンチマークツールでgzipを展開してmd5を確認しますのでそのぶんベンチマークツールのスループットは下がるのではないかと思います。

    Q. サインインしたときにDBのlast_accessカラムを更新していましたが、使っているところが見当たりません
    A. HTMLに書き出しているところはありませんので、気付いた人は削除してスコアアップできるサービスポイントです。

    Q. PHPで初期でFAILが出ます
    A. PHPは初期状態で負荷が高すぎてFAILがでてしまいます。これはセッションストアのmemcachedに接続する際に高負荷でタイムアウトとなっていることから発生しているのですが、現在のMemcachedモジュールにはセッションストアに接続する際のタイムアウトを設定できないため、やむをえずこのようになっています。なお、Memcachedモジュールのgithubにはタイムアウトを指定できるものが上がっているのですが、まだ正式リリースされてないため採用できませんでした。

    Q. Perlで謎の空 < h1> がありましたが罠ですか?
    A. Kossyにはもともと$greetingとか$site_nameという変数に文字列を入れる機能が入っていたのですが、それを潰したときに< h1>タグを削除するのを忘れていたようです。罠ではありません。

    ベンチマークツールについて


    Q.なんの言語で作ったんですか? 中身を解析しようとおもったけどバイナリでした
    A. @fujiwaraがGoで実装してネイティブバイナリにコンパイルしています。

    Q. --workloadオプションにより上がる並列数はどのぐらいですか?
    A. (N+1) * (N+1) * 2で並列数を設定していますので、1で8並列、2で18並列、3で32並列、4で50並列、5で72並列、6で98並列…と上がっていきます。あまり並列数を上げても限界がありますので、私の感覚だとworkload=2か3でちょうどいいくらい、環境によっては4でいいスコアがでるかもしれないというところでした。

    基本的にコンテンツを返すのにかかる時間が短くなればなるほど低めのworkloadのほうがよりよくベンチマークが回るといった印象です。

    Q. もしかして○○を○○するチートができませんか?
    A. いくつかチェックが甘い点が見つかっております! それにつきましては解答編でおしらせする予定です…


    その他にもなにかご質問などありましたらTwitterに #isucon タグを付けてつぶやいていただけると解答できるかもしれません。

    参加いただいたみなさん、ありがとうございました! 正式な最終結果は木曜日に発表予定となっておりますので、もうしばらくお待ちください。