出題担当のfujiwaraです。

ISUCON3予選にご参加いただいた皆様、ありがとうございました。 本選進出者の皆様、おめでとうございます!

おかげさまで大きなトラブルもなく、無事に2日間の予選を終えることができました。楽しんでいただけたでしょうか。

出題内容

今回の予選問題は以下のようなWebアプリケーションを題材としました。

  • 要するにGithub Gistのようなもの
  • ログイン機能がある。Cookieによるセッション維持が必要
  • プライベート投稿機能がある。プライベート設定されたものはログインしているユーザにしか見えない
  • Markdown形式で投稿できる
過去のISUCON1,2での題材はユーザごとのログインという機能がなかったため、その点が大きく異なる部分ですね。

詳細については、問題作成に協力してもらった同僚 @acidlemon が解説記事を書いていますのでご参照ください


講評

予選参加者の皆さんから提出された AMI から運営がインスタンスを起動してベンチマークを行い、予選期間中に記録された最高スコアに近い値が計測されたのを確認して本選進出確定、というレギュレーションでしたので、こちらでベンチマークを実行しつつ内部を軽く見せていただきました。それを元に講評したいと思います。

アプローチとしては大きく分けて三つあったようです。

  1. アプリケーションを再実装しオンメモリにデータを保持して高速に処理する実装を作り上げる
  2. フロント(nginx, varnishなど)でキャッシュを積極的に行い性能を出す
  3. アプリケーションを着実に改善していくことで性能を出す
スコアが20,000以上の上位チームの中では、「山形組」「ぜかまし」が1.のアプローチ、それ以外が2.のアプローチのようでした。

1.のアプローチについては、今回の初期データが200MB、数万件程度でメモリに十分保持できるサイズだったこともあり、非常に高速に動作させられるようですね。 アプリケーションの変更点が大きくなるため、時間内に作り上げるのはなかなか困難だと思いますがそれをやりきって速度を出した2チームでした。

2.のアプローチですが、フロントでキャッシュするといっても、今回の設問はログイン中ユーザに配信するページにはそれぞれのユーザ名が書き込まれているなど、キャッシュすることがなかなか難しい作りです。

ただし /recent/* という投稿された一覧画面のみ、非ログイン状態のクライアントが大量にアクセスしてくる作りになっています。(一部、ログインセッションを持ったクライアントもアクセスします)

しかもこの非ログイン状態のクライアントはページ内容のチェックが若干甘く、そのためキャッシュをある程度長く保持していてもfailにならずにスコアが上がる、という特性がありました。

ここは実は出題意図にはなく、たまたまHTMLをチェックするコードの実装が足りなかったために、このような特性になってしまっていたのを告白します。このことは初日の競技中に気がついてしまって、かなり動揺してしまいました…

とはいえプログラムは「意図したとおりではなく書いたとおりに動く」ものですし、チェッカーが検出できないものは失点ではないので、そこを突いてスコアを上げることは正当な行為です。(初回のISUCON1の時も、サイドバーは10秒以内ならキャッシュしてもチェッカーが検出できないことを、結果的に利用して優勝スコアを出したのでした)

また、今回はページ内容に問題が検出されたとしても1発アウトではなく、合計のfail数が3までは減点なし、それ以上は fail数の自乗% (たとえば fails=6 なら 3 * 3 => -9%) で減点されるというスコアリング方式でしたので、多少のfailは厭わずキャッシュで稼ぐという戦略が有効に作用していました。

正直なところここでスコアを稼げる作りにするつもりではなかったので、出題者としては大変負けた気分ですがこれは本選への反省として生かしたいと思います!

そしてフロントのキャッシュに頼らす、実直にアプリケーションの作りを改善していってスコアを出していったチームもあります。ボトルネックとなっている問題点を潰していけばそれなりにスコアが上がるようになっていますし、事前に出題を解いてもらった感触では、正攻法で遅いところを全部潰してスコア10,000程度が予選のボーダーラインになるかなと思っていたので、まずは想定通りという感じでしょうか。

recentでスコアを稼げないようにチェッカーがもう少し厳しかった場合、おそらくフロントキャッシュ戦略をとったチームの大半がfailするはずですので、正攻法で10,000点というのは決して低いスコアではないと思います。

AMI確認中は最低5回のベンチマーク試行をしましたが、多少のfailを覚悟の上でキャッシュ戦略をとったチームはやはりスコアのばらつきが大きく、そうでないチームは安定して数%程度の誤差でスコアを出していました。ここは一発アウトでない、複数回の試行で最高スコアが出ればよいというレギュレーションを生かした戦い方ですね。


本選に向けて

予選では1台のインスタンスでベンチマークツールも同一ホストで実行されるという環境でしたが、本選は複数台構成になります。また、ベンチマークも別のマシンからおこなわれますので、今回の予選でスコアを出した手法がそのまま通じるかどうかは分かりません。

また、予選のスコアや順位は本選において特にアドバンテージはありませんので、また心機一転、楽しんでいただけたらと思います。 出題者としても意図しない挙動やスコアが出ないように頑張りますので、本選進出者の皆様よろしくおねがいいたします!