ISUCON3出題の裏側

acidlemonです。今日はもうなんだかいろんなところに記事を書かなきゃならなくててんてこまいとなっております。

さて、最初に告知です。

毎週カヤック技術部では金曜日の夜に技術部勉強会を行っています。今週末はISUCON3の優勝チームのtagomorisさんとkazeburoさんをゲストにお迎えして、出題担当のfujiwaraとともに今回のISUCONを振り返ってもらい、せっかくだから外部の人をバンバンよんで酒のみながらLTとかもしてもらっちゃおう! みたいな感じになっています。

追記(2011/11/11 20:15): kazeburoさんのスケジュールも確認取れましたので追記しました

ということで、ISUCON3反省会というイベントを立てましたので参加希望の方はこちらから参加表明をおねがいします。費用はカヤック持ちで参加無料となっておりますので好きなだけビール飲んでいってください! 年の一度のお祭りですから!

ISUCON3 の出題について

さてここからはどんな感じで出題を詰めていったのかというお話ですが、話はたぶん春くらいまで戻って、941さんよりfujiwaraさんにISUCON3の出題依頼が来て快諾したところからはじまります(快諾は快諾なんですけど、賞金がどーんと100万円になるのならむしろ出場したいというのが本音でした)。

月日はながれ、8月下旬くらいに「そろそろ始めないとならないな」「じゃあISUCONのネタを考える飲み会でもやりますか!」ということで崎陽軒本店の地下のビアレストランでネタを考えました。

その時挙がったネタを既に酔っ払っててぼくは結構忘れてるんですが、その時出たネタで使われたものは大体以下のような感じです。酔って忘れないようにメモらないといけないですね!

  • やっぱ画像のアップロードじゃないですかねぇ
  • 帯域詰まる系のネタとかやりたいねー
  • SSL有効にしてSPDY使ったり使わなかったりとかどうですかねぇ
  • リアルタイム通知とかやりたいですねぇ、WebSocketとかロングポーリングとか
  • ログインしてセッション維持するタイプのお題は過去2回なかったよね
  • プッシュ通知に反応してクライアントからの接続が殺到するタイプのアプリとかもあるなー
  • 過去2回はPOSTして○秒後にチェックというのがあったけど、あのルールを入れるとまたワーカーぶん回してフロントキャッシュ勝負になるので今回は避けたい
  • 検索エンジンのクローラがやたら深いページまで潜ってきてLIMIT OFFSETでDBが死んだりとかしますよね

上記のネタをうまいこと織り込んで予選の問題と本戦の問題ができています。本当は本戦でSSL使いたかったんですがSSLセッションまわりでよく分からない挙動を観測して意図通りの出題ができなさそうということでこれは見送りになっています。

予選の問題作成

予選の問題作成はだいたい2週間くらいかけてメイン業務の合間をぬってやる感じで進めました。予選はカヤックから12人もエントリーしたおかげで問題作成で稼働できるエンジニアがほぼfujiwaraと私しかおらず、腹をくくってやるしかないなーという感じでした。

大体予選の10日前にPerlのアプリとGo製のベンチマークができあがり、そこから私は事前解答を開始。fujiwaraより「ベンチマークの中身を読まずにガチで解いてください」と言われて「こ、これはオレが試されている…!」みたいな感じで一通り解きおわり、動作確認がおわったのが1週間前。第1回と第2回の優勝者から「ガチで解いてください」って言われることのプレッシャーはんぱない。

そこからは2人で手分けして5言語に移植する作業を行い、Ruby(Rack)とPython(WSGI)というPerlとほぼ同じ構成で移植できる言語とベンチマークにつかったGoをfujiwaraが担当し、残りのコールバック地獄のNodejsと使用者の多かったPHPを私が担当し、木曜日に大体移植が完了しました。

あとは金曜日にAMIの作成とスコア送信システムを整えて土曜日曜に予選を実施! いやーホントギリギリですねぇ。

本戦の問題作成

本戦は問題の構成が複雑になることもありさすがに2人でやっていたら間に合わないということで、予選に落ちたメンツとその他予選の感想ブログを読んで面白そうだと手を上げてくれたメンバーをくわえて6人体制となりました。作業分担は、

  • fujiwara: 問題作成、ベンチマーク作成、スコア集計システム作成
  • acidlemon: 事前解答作成、ベンチマークチェック、オープニングストーリー作成、レギュレーション作成
  • handlename: Node.js移植 (バグ1個)、本番環境を使った動作確認
  • mix3: Go移植、本番環境を使った動作確認
  • nobu_ohta: Ruby移植、Python移植 (バグ1個)
  • m0t0k1ch1: PHP移植、封筒の中の紙とチーム表示の紙のデザイン

となっています。

作るものの仕様がfujiwaraより出てきてキックオフを行ったのは10/17で、実際に全員の作業がはじまったのは10日前でした。fujiwaraが最初の1台構成を作って、私がそこで解き始めたのが10/29くらいで、そのタイミングで他の言語も移植を開始しています。実際に5台にして解き始めたのは4日前の11/5で、そこでNFSマウント試してみて頭を悩ませて「もうオレNFS使わんo(`ω´*)o」とかやってるうちに2日前です。

ロングポーリングやら画像の差分確認やらでベンチマークにも色々問題がみつかり、高速化するに従い並列度が挙がってフォロー関係が変化したことにより404を期待するところが200になったりその逆が起きたりといったことが発生しましたが、2日前までにほぼ潰しきりました。

移植も3日前くらいまでに完了し、2日前の時点で本戦サーバに一度デプロイしてみたところギリギリでタイムアウトが発生して初期状態でFAILしたためベンチマークの負荷を軽くしてみるなどの調整を行いました。また、一部の移植ではfujiwaraチェックが通らずいくつか修正した点もありました。

移植したものを動かすのに一番苦労したのはPHPですね…。PHPはsession?_startを呼んでいるとリクエストの処理が同期的になるため、タイムラインを取るためにsleepしてる間他のリクエストの処理が一切進まずガンガンタイムアウトが出ました。ただ、たまたま(?)API Keyで毎リクエストごとに認証をするようになっておりsession_startをする必要が無かったのでWAFで勝手にsession_startしていたのをしないように設定することで解決できました。

前日は仕上げということで私の事前解答も大分速くて安定的になり、大分動くなーという感じだったのですが、夜中になってまた不安定になり、エラーメッセージのURLを突き合わせてもダメになった原因が分からず、ベンチのソースコードを読みまくってよく見てみると私の実装にバグがある & ベンチマークの吐くURLが間違っている(コピペミス)という事が分かってこれを修正して一件落着、というところで当日を迎えました。

朝に自宅に一度帰る電車で寝ないようにベンチマークを各処理ごとに回してみたところ、プロフィールアイコンを全部キャッシュするとよく回るベンチマークがあったため「これは予選の再来になるのでは…!」ということでアイコンのスコアを0.1にするというレギュレーション変更を2時間前に行ってこれで出題内容の調整作業が完了となりました。


さてみなさんいかがでしたでしょうか?

今回は「いやー出題つれーわー」みたいなことを言うためのエントリではありません。出題は大変でしたが、やはり出題してみないと分からないことってたくさんありました。また、出題を通してむしろ出題側がスキルアップするという側面もあるかと思いますので、まずは社内ISUCONなどのイベントで出題の仕方を知ってみて実際に本戦の出題をやってみてはいかがでしょうか! という話でした。

なお、カヤックでは今年の春の新人研修時に社内ISUCONを実施しています。これを通してfujiwaraと私は出題作成の流れがわかり、社内ISUCONに出たメンバーはスコアを残すことの重要さと残せなかったときの悔しさを知り、今回の本戦にそれが生きました!!

って書きたかったんですが、うちの出場チーム3チームもいたのに全チーム0点FAILで終わったんですよねー…。fujiwaraも「春にスコア残すのが大事って教訓を得たはずなのになー」と嘆いておりました。

カヤックではISUCONが大好きなエンジニアを募集しています!