ISUCON公式Blog

WINNER'S PRIZE \1,000,000



   

予選の問題作成を担当したDeNAのkarupaneruraです。

予選に参加した皆様、お疲れ様でした。 楽しんで頂けましたでしょうか。

お陰様で大きなトラブルもなく無事に予選を終えることができました。 参加者の皆様をはじめとした皆さんのご協力がなければ成し得ないことでした。 ご協力いただいた皆様、ありがとうございました。

課題アプリケーション

今回の課題はイベントのチケット予約アプリケーションでした。


ユーザーを作成、またはログインを行うと座席を予約することができます。 座席は抽選で決まる仕組みになっており、ランダムに決まった座席が即座に分かるようになっています。 埋まっている座席は黒く塗りつぶされ、自分の獲得した座席は緑色の字で表示されています。 また、自分の座席をクリックするとキャンセルを行うことができます。


マイページでは自分の最近予約(orキャンセル)した席を5件、最近予約(orキャンセル)したイベントを5件、そして予約総額を表示していました。 また、未ログイン時は予約/キャンセル/マイページの閲覧はできませんが、座席の空き状況を確認することができました。

管理画面もあります。 管理画面は一般向けの画面とは異なりログインするまでどのような情報も見ることはできません。 ログインすると、一般向けに公開していないものも含めてすべてのイベントを表示できます。 座席の予約状況も同様に閲覧することができるほか、イベントの状態を変更することができます。 イベントの状態は公開/非公開/終了の3パターン存在し、公開/非公開は何回でも変更することができますが、終了にすると二度と状態を変更できません。

そして、管理画面にはレポート機能もあります。 全体/イベント毎のチケットの購買履歴をCSVとしてダウンロードすることができます。

実装としては、フロントエンドはvue.jsを用いたSPA風の構成になっており、ラウンドトリップを減らすため初期レンダリングに利用するデータだけJSONでHTMLに埋め込んで、 あとは基本的にAPI経由でデータを取得するという仕組みになっています。(Instagramなどで行われています)

バックエンドは3台のCentOSのサーバー(2core/1GB)で、初期状態では3台起動して1台だけですべてのリクエストを処理していました。 データベースはCentOS7の標準パッケージのMariaDB 5.5、リクエストはHTTPでtcp/80にh2o 2.2.5で受けて、Perlの参照実装にリバースプロキシして渡していました。

初期データとしては101人の管理者アカウント、18個のイベント、5000人のユーザーアカウント、キャンセルを含む予約データ約20万件が入っていました。

問題のコード群は github.com/isucon/isucon8-qualifyで公開しています。

テーマ

気付いていた方も何人かいらっしゃいましたが実はこの問題はISUCON2の問題のリバイバルです。 ISUCON2ではログイン、マイページ、キャンセル、イベントの公開状態、レポートなどはなく、今回新たに要素として取り入れました。 これによってずっと複雑度が増していて、同様のアプローチでは問題を解決しづらくなっており、これを壊さずにチューニングするのはとても大変だったと思います。

今回は実際のWebアプリケーション運用の現場で起きる実際の問題解決に近いものを課題にしたいと考えていました。 具体的には以下のようなポイントを押さえることを目指しました。(事前のディスカッションの議事録から抜粋)
  • メモリに乗っけるだけでおしまいの問題にはしない
    • 実務でそこまでやる場面はほぼ皆無
    • ある程度のCPUバウンドにして複数台でCPU負荷を分散することでスコアアップできる問題にする
  • CPUバウンドに寄せすぎない
    • (おそらく)Goが無双してしまう
    • 実際の言語選択はパフォーマンスだけでない様々な要因で決めることになるし、言語選択が大きく勝敗を分ける問題にはしたくない
  • 攻略ポイントとそこに行く道筋がわかる問題にしたい
    • ちゃんと計測すれば計測結果とコードから仮説を立てて問題を解決していくヒントが得られる
  • 限られたマシンリソースでどう捌くかを考えるようなものにしたい
    • スケールアップ/スケールアウトがこれ以上できないほどサービスが成長してしまったとき、しばしばそういう場面に陥る
また、近年のISUCONは参加人数が1000人を超えるなど非常に大規模な競技になっている反面、本戦に進める枠はわずか30チームに限られています。 そのために、予選でかなりハイレベルな戦いになるような難易度に設計しなければ、上位陣のスコアに差が付かずほとんど抽選のような形で決まってしまい、予選が予選としての意味を成さないものになってしまうリスクがあります。 それを避けるために予選問題もそれなりの難易度になるようにすることを目指しました。

これらのポイントを押さえるため、レースコンディション問題を題材に大量の並行トランザクション地獄を作ると、自分たちが実際に向き合うことの多い課題に近く良いのではないか? 過去のISUCON2がこれに近かったし過去問のリバイバルというのは新しいし、面白いのではないか?ということでこういう問題になりました。

ということで、今回は一芸では突破できない様々なハードルを用意しましたが、メインテーマは強いて言えば「大量の並行トランザクションによるロック地獄をどう解決するか?」でした。 様々な問題の解決が要求されるので、これを突破できたチームは本当にすごいと思います。おめでとうございます。

参照実装

参照実装の作成では、悪い設計の上でそこそこ読みやすいコードをなるべく愚直に実装しました。具体的には、以下の2つのポイントを意識しました。
  • 悪いDRY
    • get_event /
      get_events
      が万能すぎる
  • 悪いDB設計
    • reservations
      テーブルが万能すぎる
これに初期データ量とマシンスペックや台数の制約、API仕様が組み合わさり、今回のような難易度の問題をつくることができました。 ちなみに、参照実装(問題)の開発には今回は自分が一番慣れているPerlを利用しました。他言語の実装はPerl実装を参考に移植されたものです。 さらに余談ですが、感想戦のgame master実装もPerlでした。

しかし、開催後に気付いたことですが、参照実装にはいくつかバグが残ってしまっていました。

予約エンドポイントの予約成功するまでの無限ループはキャンセル時刻をテーブルに保存する仕様を入れる前の実装の名残がうっかりそのまま残ってしまったものでした。 また、その歳にトランザクションの範囲も直しそこねていて、それによってレースコンディション問題が低確率で発生するようになっていました。パフォーマンスが上がるとこれがエラーとして出て来るようになってしまったと思います。

Discordの感想部屋で話題になっていた
GROUP BY event_id HAVING MIN(reserved_at) = reserved_at
のクエリはMySQLでは結果が不定になります。 これは一見、最初の予約が有効な予約として扱われる用に見えますが、
HAVING
の条件は集計「後」の絞り込みであり、集計後のカラムの値は集計の基となるカラムまたは集計関数を通したカラムでなければ不定となるため、正しい結果となりません。 もともと、これは上記のトランザクションが正常に機能する前提で「最初の予約が有効な予約として扱う」という無駄な防御機構として入れたものだったのですが、トランザクションのミスも相まって結果的にダブルブッキングが可能なようにミスリードできてしまうものとなってしまいました。

また、Go実装においてはレポートの生成処理で消費するメモリ量が、意図せず他言語における実装に対して有意に少ない実装になってしまっていました。 要因は大きく3つあります。
  • 他の言語の実装において非破壊ソートを行っていたが、Goでは破壊的なソートで移植してしまっていた
    • とはいえ、これは他の言語では非破壊ソートとはいえ実体は参照で扱われるためあまり大きな影響は無い(Goでは直のstruct)
  • database/sql
    のインターフェースで自然にDBを扱った為に他の言語において作っていたSELECT結果の配列を作らずに済んでしまっていた
  • (上記と関連して)
    go-sql-driver/mysql
    の実装がMySQL Connector Cベースではない独自のものとなっていることに気付かなかった
    • MySQLドライバの実装で一般的に利用されるmysql_store_resultで行われるレコードのバッファリングがライブラリ側で行われなかった
これらの要因によって、Go実装においては参照実装で他の言語の挙動と比べてレポートの生成処理で要求するメモリ使用量がおおよそ半分から3分の1程度で済む実装になってしまっていました。(Swap Outするメモリ量で言えば最悪のケースで他言語と実環境下で1GB以上の差が出ることが試験してわかりました。) これによって後述のSwap Out地獄がGo実装ではあまり大きな問題にならなかったと考えられます。

database/sql
go-sql-driver/mysql
の問題に関しては、事前にこれに気づいていれば
go-sql-driver/mysql
による実装とあまり差が出ないようにmysql_use_resultSELECT .. INTO OUTFILE構文を使った参照実装にするなど、なるべく言語選択の差を減らす工夫が出来たかもしれません。 しかし、この問題は基本的に愚直に手続き書いてるコードを移植しただけで起きたことです。他の部分でも(たとえば)HTTPのパスルーティングの計算量などもおそらく言語間の差異はあったかと思います。 つまり、単にこれはその言語やライブラリの持つ性質と言えるので、それを踏まえてどこまで近い条件に揃えるようケアするかという塩梅の問題と言えます。 ただ、そういった側面がある一方でこれは意図して用意したボトルネックの一つではあったので、Goで挑んだ場合は少し難易度が落ちていたことも否定できず、参照実装でそういった部分にここまで差が出てしまうことはあまり良くなかったと考えています。

その他、言語によっては
db/init.sh
のエラーをハンドルしていないケースがあったり、Go実装ではGetEventsとGetEventの間でトランザクションオブジェクトが渡っていなかったり、Node.js実装では参考に用意したindex.jsのビルドが古かったりなど、細かいバグがいくつか存在しました。

これらの参照実装の不手際で不要な混乱を招いてしまい本当に申し訳ありませんでした。運悪くこれらに躓いてしまったチームもあったと思います。 ただ、競技としては皆さん同じ条件の下で競っていますので、参照実装のバグも込みで時間内に問題を解決できたかどうかが結果ということでご容赦頂ければと思います。

講評

皆さんお疲れ様でした。特に見事予選を突破したチームは本当におめでとうございます。 予選を突破したチームは8時間という短い時間の中でこの問題に対してその成果を残せたということで、それは本当にすごいことだと思います。 とはいえ、スケジュールや体調、環境などの偶然で一定は運の要素も入るし、得意不得意も人それぞれですので、必ずしも予選を通過できなかったチームが予選を通過したチームに劣るということはありません。 惜しくも予選を突破できなかったチームも、ほとんどのチームではかなりの改善が進められていて、本当に惜しかったと思います。

さて、皆さんのブログやGithubのコードを軽くざっと眺めさせてもらいました。 最初のボトルネックがうまく特定できたチームとそうでないチームが半々くらいでしょうか。

上位陣のチームはやはり皆さん
get_event
地獄を解消しないとどうしようもないことに早々に気づけていたようです。 初動がうまく出来たチームは午前中には5000を超えるスコアを残せてたようでした。 反面、スコアがうまく伸ばせなかったチームは、ボトルネックの特定がうまくできなかったり、あるいはその後の改修のデバッグに手間取ったり、インフラ構成の変更に手間取ったり、 チームの力を発揮しきれずに開発スピードが出せなかったり、などなどのトラブルを時間内にうまく解決出来なかったのかなと思います。

特に、惜しかったチームには改修のバグ修正に手間取ったチームが多かったように見えました。

たとえば、
events
sheets
のキャッシュなどは毎度DBからデータを作っているコードでは破壊的に扱っても問題がないために破壊的に扱われがちです。 しかし、いざキャッシュしようと思うと多くの実装ではキャッシュしたsheetを参照として受け取る実装になりがちで、それを破壊的に扱っている部分がバグにつながりやすい構造になっていました。 キャッシュは簡単なようで扱いが難しくその上に途中で辞めることが難しいため「キャッシュは麻薬」という言葉もあるほどですが、上記のような問題をさっと見抜けないと今回の問題もキャッシュの適用は困難だったと思われます。 これはあくまでも一例で、ロックを甘くしたことによって起きるレースコンディション問題など、バグを生みやすい要素が多々ある問題になっていた為、ほとんどのチームがバグに遭ってそれを修正を試みる(あるいはrevertする)といった問題を踏んでいました。

こういった問題をすばやく解決するためにはデバッグ(QA)能力も重要です。 少なくとも1分以上は掛かってしまうベンチマークをわざわざ待たずに、デバッガを仕込んだり変数ダンプなどでデバッグを手早く行っていくという能力も重要な要素でした。 勝ち抜いたチームはバグで躓くことはありつつも、ある程度しっかりとバグを取ることができていたようです。

さすがに競技中にテストを書くチームはなかったようですが、予約→取得→キャンセル→取得といった流れくらいはシュッとテストできるようにしておくと開発スピードが上がったかもしれません。 ほうじ茶ラテ部はcurlなどでシュッと動作確認出来るようにしておいたようです。これは良いプラクティスだと思います。

また、チームによっては複数台展開を切ってほとんどメモリに載せてレスポンスをさばく戦略を取ったチームもあったようです。 さらに、この問題は(結果的に時間内にDBネックを脱出しきったチームは殆ど無かったようですが)DBネックを解消しきるとアプリケーションのCPUにボトルネックが移ってきます。 そのため、複数台展開を切るとその点で一定の不利を強いられる構造になっていました。逆に言えば複数台をうまく活用できれば8時間の競技ではオンメモリ戦略に十分対抗できるバランスだったかと思います。 この仕様とコード規模に対して、この戦略でベンチマーカーが見つけられるようなバグをほとんど出さずに見事にスコアを上げられたチームは見事と言うほかありません。完敗です。 とはいえ、正攻法ですばやくチューニングを進めていけばちゃんとスコアップが期待できる問題には出来ていたと思いますし、実際そういうチューニングを行って予選を突破したチームが多かったようです。

h2oとMariaDB

h2oやMariaDBでハマったり面食らった方も多かったようです。特にMaria DBはsystemd上も mariadb.service なので知らないと混乱したかと思います。 例年の選択を考えると少し不思議に見えるかもしれませんが、これらはそこまで変な選択ではないと考えています。

また、ISUCONのコンセプトは初見のシステムを短期間で良い感じにスピードアップさせることなので、必ずしも自分の知ってるor得意なものが当たるとは限りません。 ISUCONはそういうポイントも含めたWeb技術の総合格闘技的な競技だと僕は考えているので、必ずしも既存のものに合わせた技術選定にはこだわりませんでした。

h2oはkazuhoさんの作った高速なHTTP1/HTTP2サーバーです。今回はHTTP1のフロントサーバー(LB)として採用しました。 昨今のWebサーバーの事情を追っていれば一度はh2oを触ったことがあるだろうし、そうでなくともLBがボトルネックになることは無いと考えていたため、 h2oをちゃんと追っている、あるいは日常的に使っている人にとっては嬉しいし、そうでない人にはnginxなどをイチから構築する能力を要求するということで、 Webサーバー運用という観点でのインフラスキルを問うものとして妥当だと考えて採用しました。

MariaDBは単純にCentOSの標準のyumリポジトリで入るMySQL ServerがMaria DBだからです。募集のタイミングでCentOSを採用する予定であることは明示していたので、 これも下調べをすればMySQL Serverの標準パッケージが最新のCentOSにはないことが分かったはずです。これもやはりOS知識という観点でのインフラスキルを問う要素になっていました。 このMariaDBは5.5なのでMySQL 8などへのアップグレードにもそれなりに知識が要ります。データディレクトリの初期化/アップグレードや必要に応じたパーミッションの修正、my.cnfの設定やそのチューニングにはDBAとしての能力を要求しています。 特に、後述のSwap Out地獄を軽減するためにもMySQLのメモリチューニングは必須でした。また、ロック地獄を低減するために出来るチューニングもいくつかありました。

ちなみに、MySQL 5.7 or 8へのアップグレードはオプティマイザが賢くなるほか、8ではウィンドウ関数がサポートされるので、それを用いてマイページの初期データ生成を楽に行える。などの特徴からMySQL 8は個人的には密かにおすすめの選択肢でした。

get_event地獄

get_event
の実装はイベントIDに対して全席ぶんのステータスを含めてイベントのすべての状態を返す実装になっていました。 すべてのシート(1000個)に対して都度クエリを発行するN+1問題になっているなど、かなり非効率的な処理をしています。

この
get_event
がアプリケーションのあらゆる箇所で呼び出されていました。曖昧な命名による悪いDRYの典型です。 さらに
get_events
の実装では
get_event
を対象のイベントIDごとに呼び出しています。 そのため、
get_event
GET /
GET /api/events/{id}
などのボトルネックになるほか、構造的に全体的なパフォーマンスを劣化させる要因になっていました。

これに気付くためには、関数/メソッド単位でのプロファイリングも併せて見る必要があります。 死闘の果てにの手法はシンプルながらこれを攻略するのには大変有効なプロファイリング手法だったと思います。

分かってしまえばあとは単に解消するだけなので詳しい解法はここでは省略します。

Swap Out地獄

最初にベンチマークを走らせるとPerl実装では500MBほどの大量のSwap Outが発生することに気付くかと思います。dstatで見るとこんな感じになります。

[isucon@XX-XX-XX-XX ~]$ nice -n 19 dstat -tc -C 0,1 -lmdrns 10
----system---- -------cpu0-usage--------------cpu1-usage------ ---load-avg--- ------memory-usage----- -dsk/total- --io/total- -net/total- ----swap---
time |usr sys idl wai hiq siq:usr sys idl wai hiq siq| 1m 5m 15m | used buff cach free| read writ| read writ| recv send| used free
22-09 23:54:47| 3 2 95 0 0 0: 2 1 96 0 0 0|0.23 0.18 0.07| 296M 22.7M 318M 356M|3191k 63k| 133 5.16 | 0 0 | 0 2048M
22-09 23:54:57| 13 1 85 0 0 0: 26 3 69 1 0 1|0.27 0.19 0.08| 378M 23.0M 336M 255M| 729k 6705k|7.50 41.1 |1675B 42k| 0 2048M
22-09 23:55:07| 3 1 96 0 0 0: 82 11 4 0 0 4|0.46 0.23 0.09| 398M 23.0M 336M 236M|1638B 87k|0.10 3.50 |2467B 11k| 0 2048M
22-09 23:55:17| 58 8 32 0 0 2: 77 10 10 0 0 3|0.95 0.34 0.13| 436M 23.0M 336M 197M| 0 312k| 0 9.10 |6927B 510k| 0 2048M
22-09 23:55:27| 88 10 0 0 0 3: 85 11 0 0 0 3|1.72 0.53 0.19| 523M 23.1M 336M 110M| 0 124k| 0 8.30 |3850B 375k| 0 2048M
22-09 23:55:37| 86 10 0 0 0 4: 85 11 0 0 0 4|2.76 0.79 0.28| 525M 23.1M 336M 108M| 0 123k| 0 9.20 |4534B 184k| 0 2048M
22-09 23:55:47| 85 11 0 0 0 4: 86 10 0 0 0 4|3.49 1.01 0.36| 528M 23.1M 336M 105M| 0 132k| 0 9.90 |6307B 447k| 0 2048M
22-09 23:55:57| 86 11 0 0 0 3: 85 12 0 0 0 3|4.03 1.21 0.43| 668M 9.88M 151M 164M| 153k 29M|10.3 71.9 |2063B 129k| 72k 2048M
22-09 23:56:07| 58 11 30 1 0 1: 32 15 51 1 0 1|3.92 1.28 0.46| 857M 136k 14.4M 121M| 98M 87M| 546 329 |2881B 1221k| 557M 1491M <-- report!!

最後の総合レポートのチェックで行われるレポート作成で大量のSwap Outが発生していることが分かります。 これは、多くのMySQLクライアントライブラリの実装で使われているMySQL Connector C(libmysqlclient)の挙動とも関係があります。 MySQL Connector Cではクエリの結果を読み込むためにmysql_store_resultmysql_use_resultのどちらかを利用する必要があります。 多くの実装では
mysql_store_result
がデフォルトで使われるようになっています。パフォーマンス面での主な違いは前者が全ての結果を一度にMySQLから受け取るのに対して、後者は1レコードづつ受信する点です。(詳しくはMySQLの公式ドキュメントを参照してください)

レポートの生成ロジックではreservationsテーブルの全てのレコードを参照します。このテーブルには初期データだけでも20万件弱のレコードがあります。
mysql_store_result
を用いた実装では、MySQL Connector Cが20万件ぶんのデータをMySQLから受け取ってメモリ上に展開することになります。 さらに、今度はそのデータを各言語のデータ構造に変換し、もとのデータが解放されるまではこれでざっくり2倍です。そして price などを計算して整形したデータを作って、これでざっくり3倍です。 おまけにそのデータに対して非破壊ソートを行います。最後にCSVの文字列データをメモリ上で作って、ざっくり4倍です。

死ぬほどメモリを食うことになることがおわかり頂けるかと思います。最後に一気にSwapが膨らむのが大きなヒントでした。 topやpsでメモリの専有度合いを見てみるとよりはっきりと分かったかもしれません。 これによってSSDとはいえメモリアクセスはやはり遅くなってしまい、MySQLなどがSwapを掴んでしまうとスコアが安定しない要因になります。 また、Swap Outの過程でディスクキャッシュが追い出されるため、やはりそれもパフォーマンス劣化の要因になることがあります。

これを解消するには
mysql_use_result
SELECT .. INTO OUTFILE構文を使うと良いでしょう。 またレスポンスを返す際にもレコード毎にWriteすることでアプリケーションの消費メモリ量はかなり抑えることができます。ファイルに書き出す場合はsendfileシステムコールを使うという手段もあるでしょう。 ファイルを作る際にファイルシステムのキャッシュを消費することも考えると
mysql_use_result
のほうが効率は良かったかもしれません。

席の乱択とロック地獄

参照実装では予約時の席の乱択はこのような実装になっていました。

SELECT * FROM sheets WHERE id NOT IN (SELECT sheet_id FROM reservations WHERE event_id = ? AND canceled_at IS NULL FOR UPDATE) AND `rank` = ? ORDER BY RAND() LIMIT 1

サブクエリの
reservations
テーブルへのSELECTはインデックスではevent_idぶんの絞り込みしか行えず、さらに
FOR UPDATE
が付いています。 ちなみに、キャンセルが速くならないうちは event_id で絞り込めていればそれなりのレコード数まで減らせた為、
event_id
canceled_at
に対してインデックスを貼ることでそれだけでも一定の高速化はできます。

このクエリは参照実装では(ミスでトランザクションの外側にありましたが、これを内側に入れた途端に)ロック競合が増えてロック待ちが一気に増加します。

本来、実際にロックを取らなければならないのは予約しようとしている席のレコード1つだけです。しかし、もとのスキーマではsheetsは共用であり、予約しようとしている席の予約レコードは存在しないレコードです。 つまり、これは存在しないレコードにロックを取る代わりに広範囲のロックで予約を直列化して凌いでいた。というものになります。

そこまで理解すればこれを解決する方法は単純で、空き席をレコードとして予め用意してそれに対してロックを取れるようにすれば良い事がわかります。 もちろんRedisのSet型やList型を利用する手もありますが、空き席のテーブルに対して
ORDER BY RAND() LIMIT 1 FOR UPDATE
などとするだけでも十分なスコアアップは狙えたかと思います。 MySQL8では
FOR UPDATE SKIP LOCKED
が使えるので、ランダムな順番(ord)を予め振っておいて
ORDER BY ord LIMIT 1 FOR UPDATE SKIP LOCKED
などとする手もありました。

ちなみに、これとぶつかるレポートのFOR UPDATEはMySQL(InnoDB)のREPATABLE READにおいて意図的にファントムリードを引き起こす効果がありますが、 レポート処理としては必要性がなく、完全に無駄なコードなのでそれを見抜ければこれは外すことができました。

また、これらを抜けるとキャンセルも詰まりはじめ、さらにそれを改善すると
reservations
テーブルへのINSERTが詰まりはじめます。 これはMySQLで
innodb_autoinc_lock_mode = 2
などを設定したりその他のロックや書き込み周りの設定調整をすることで一定の改善が見込めます。

ランダムfail地獄

ランダムfail地獄に苦しんだ方もいらっしゃるようでした。 これはベンチマークと問題の性質から起きてしまう問題です。

マニュアルからベンチマークの実行方法を引用します。

ベンチマーク走行は以下のように実施されます。

初期化処理の実行
GET /initialize
(10秒以内)
アプリケーション互換性チェックの走行 (適宜: 数秒〜数十秒)
負荷走行 (60秒 - 2.の互換性チェックにかかった時間)
負荷走行後の確認 (適宜: 数秒〜数十秒)
各ステップで失敗が見付かった場合にはその時点で停止します。 ただし、負荷走行中のエラーについては、タイムアウトや500エラーを含む幾つかのエラーについては無視され、ベンチマーク走行が継続します。

最後の行に注目してください。負荷走行中のエラーについてはタイムアウトや500エラーを含む幾つかのエラーについては無視される旨が記載されています。 つまり、バグが残った実装であっても、たまたま問題が起きたケースに当たらずにベンチマークを通過してしまうケースはありえます。

実際の高負荷環境でタイムアウトや500エラーをゼロにするということは殆ど不可能に近いと思います。 特に今回はロックを扱う問題であることから「デッドロックが低確率で発生するが高速」な実装も選択できるようにこのようなルールとなっていました。

チェックする側で言うと、ユーザーは初期データで5000人ぶんが登録されており、これら全ユーザーぶんの状態を全てチェックすることは困難を極めます。 そのため、チェック対象を乱択してチェックを行う実装にせざるを得ませんでした。

その結果として潜在的なバグに気づけなかった場合にランダムfail地獄に陥ってしまっていたかと思います。 点数あがる=試行回数も増えるということになりますので、確率的なものであるためにスコアが上がれば上がるほどFAILしやすくなるということです。

実サービスでもユーザーやオペレータからの問い合わせで発覚するようなバグは同様に再現が難しいことが多く、 実際はバグに気付いたらなるべく早く修正するのが筋ですし、これ自体はISUCONのあり方としては適切かなと思います。

ベンチマークガチャ

皆さんスコアがベンチマークを回すごとに大きく変わり、まるでガチャのようで苦しんだとおっしゃる方が多かったですがその理由を解説します。

ベンチマーカーから「負荷レベルが上昇しました」「レスポンスが遅いため負荷レベルを上げられませんでした」というメッセージを見たかと思います。 マニュアルにも以下の通り記載がありました。
負荷走行中は、毎秒負荷レベルが増えていきます。 ただし、過去5秒以内に何らかのエラーが発生していた場合は負荷レベルが上昇しません。 終了時の負荷レベルや、負荷レベルが上がらない原因になったエラーについてはポータルサイトから確認することができます。

しかし、負荷レベルそのものについての説明は少々説明不足だったかもしれません。 質問が無かったため問題なかったかもしれませんが念のために改めて説明します。

負荷レベルというのはベンチマーカーの並列度のようなものと考えてもらって差し支えありません。 ISUCONという競技の性質上、参照実装はそれなりに遅い実装になっています。対して、チューンアップするとそれよりも全然速い実装が生まれます。 すると、性能が全然違う実装に対してどのようにベンチマークを実施するかという問題が発生します。

遅い実装に合わせると速い実装に対してベンチマーカー側がサチってスコアの伸びが悪くなってしまいます。 逆に速い実装に合わせると遅い実装でタイムアウトが発生します。 負荷レベルを徐々に上昇させていけば、速い実装にも遅い実装にも適切にベンチマークを掛けることができるというのがその存在理由です。 もちろん、遅い実装に対して負荷レベルを上げすぎては同様の問題が発生するため、エラーやレスポンスタイムでキャップを掛けて一定以下に性能や安定性が落ちなければレベルが上がる。という仕組みになっていました。

負荷レベルが上昇すると並列度が上がるため、アプリケーションはより多くのリクエストを受け取ることになります。 そのため、十分にチューニングされていれば負荷レベルの上昇に伴ってより多くのスコアを稼げていたはずです。

上記の前提を踏まえて、ベンチマークガチャに陥った人は何かしらの理由で負荷レベルの上昇が不安定になっていたと考えられます。 たとえば、ロック競合が解決しきれておらず、ときどきロック待ちがすごく長くなってしまうような実装だと、たまたまロック待ちに掛からなかった回には負荷レベルの上昇が見込めます。 しかし、ロック待ちに掛かった回には負荷レベルが上昇しません。

そのため、十分にロック競合が解決しきらないとベンチマークガチャに陥ってスコアが安定しなくなってしまいます。 それでも予選を突破出来たチームは幸運だったかもしれません。

ポータルやサーバーについて

xaicron先生が一晩(一晩ではない)でやってくれました!超スピードでみるみる完成していって迫力がありすごかったです。 ベンチが一瞬だったのはGMOさんのご協力がすごく手厚くて、数チームにつき1台のベンチマークサーバーを用意できたからです。 (本当はVM自体は各チーム1つ用意していたのですがベンチマーク結果への影響を最小限にするために並行で稼働する数を抑えていました。それでも爆速だったと思います。)

サーバーのプロビジョニングについては、種VMをAnsibleでセットアップしてそれをもとにディスクイメージを作り各インスタンスを建てるという方法を取ることで実現しました。 (チームごとにサーバーへのログインパスワードが違いましたが、これもGMOさん側でやって頂けました。) もちろん、当日や前日に微調整が入ることはよくある(というかあった)わけですが、それはAnsibleでプロビジョニングすることで差分だけをスムーズに適用できました。

今回の問題が快適に提供できたのは手厚くインフラを整備してくださったGMOさんのおかげです。本当にありがとうございました!

言語間の公平性、あるいはGoは本当に有利だったのかという話

この話は個人的にブログに書くだけに留めようか迷いましたが、こういう議論を野放しにして変な言説が広まっても良くないと思ったため、あえて講評に含めました。

まずはじめに、今回の問題は言語間の公平性にかなり気を揉んで、あまり言語間で差が出にくいように作ったつもりです。 アプリケーションが全てのデータをメモリ上に持つスタイル(いわゆるオンメモリ戦略)で書き換えにくいボリュームと仕様、 ランダムな席選択における純粋な実装でのロック範囲の広さなどのDBネックとなる問題の数々の解決の解決が主です。これらを8時間で全て解消するのは至難の技です。 そのため、ボトルネックを効率よく潰していくチームワークを競うという側面もありました。

Goが圧倒的に有利なのではないかという話は毎回挙がります。 もちろん、ネイティブコードを吐いて実行するGoが中間コードをVMで実行するLLよりCPUやメモリ領域を効率的に使えます。IOストリームの処理も並行プログラミングも得意です。 対して、PerlやRubyなどのLLはロジックをゆるふわに書き換えて試行錯誤したり、メタプログラミングでワークアラウンドを取ったりといった手早い修正が手軽に出来る強みがあります。 ISUCONは制限時間がある競技ですので、その制約の中でどの言語が持つメリットを取るのが有利かはその使い手の力量と問題のボリュームや性質に大きく依存します。

ちなみに、今回の問題でアプリケーションのCPU利用効率がスコアに影響してくるのは(全ての言語でチューニングしたわけではないので一概に言えませんが)だいたい15万スコア以上になってからかと思います。 予選中に出た最高スコアは10万ほどですので、どのチームもDBネックは潰しきれないまま終了したと考えています。ちなみに、今回の予選で最終スコアが最も高かったチームが選択していた言語はPHPでした。

また、型付けという観点では、今回はJSONを扱う機会が多かったため、LLではJSONの型を変更せずに修正を進めるのにはコツが必要だったかと思います。 Goでは構造体が用意されていたので、それに合わせてデータを整形すればなんとかなるため、そういう意味では少し楽ができたかもしれません。

しかし、今回の問題をそれなりに解こうとすると大量のコードの書き換えが発生します。書き換える量が増えれば当然バグを生んでしまうリスクも高まります。 静的な型チェックによる恩恵が多いかと思いきや、WebアプリケーションはIOが多いため、入力を構造体にマッピングする過程で暗黙的に型変換が発生します。 型変換の問題は実行時エラーになるため、コンパイル時に問題を検出しきることはやはり困難で、型の修正は影響範囲が広いためIDEの支援を受けても修正の足取りは少し重くなると思います。 今回の問題はロジックらしいロジックも少なく、ほとんどがDBから受け取ったデータをJSONで返しているだけの処理で、なおさらその比率が高いと言えます。

対して動的型付け言語では、(TypeScriptを除き)静的な型チェックは行なえませんが、前述の通りIOが中心のアプリケーションで静的な型チェックによる恩恵が少ないと考えると、バグを作りこんでしまうリスクはそこまで変わらなかったと考えられます。 むしろ、迅速にトライ・アンド・エラーしたり、動作確認のためにコード片を簡単に動かしたり、メタプログラミングで強引に状態を確認したりできることで、比較的足取り軽く動けるかと思います。

今回の参照実装においては
go-sql-driver/mysql
の性質によってGoが少々有利になってしまったことは否定しませんが、 それによってGoが他の言語と比べて圧倒的に有利になったかというと、そうとまでは言えないと考えています。 今回はたまたまレポート生成部分でGoに有利な方向にこの特徴が働きましたが、他の点においてはたとえば並行プログラミングが得意な部分もほとんど活きる部分が無かったかと思います。 実際のところ自前でgoroutineを管理する機会があったチームはなかったのではないでしょうか。 また、他の問題においては必ずしも不利にならないとは限りません。たとえば、ISUCON6の予選問題では参照実装に正規表現が使われており、Goの正規表現エンジンの速度では他の言語と比較して不利な状況でした。

いろいろ書きましたが、つまるところパフォーマンス面での言語選択の違いは、単純な良し悪しでは語れずパフォーマンス上の問題に対する解決策としての相性でしか語れないということです。 ISUCONに限って言えば、単にその言語の特徴が問題にマッチすればボトルネックを簡単に解消できるというだけの話です。

チューニングコンテストである以上はどうしてもCPUとメモリが絡んでくるため、その点においてGoは比較的有利であることは否定しませんが、 PerlのXSUBやRubyのC Extensionなどでボトルネックとなる部分をネイティブコードで実装することは可能で、実際にネイティブコードで実装されたテンプレートエンジンやWebServerなどは実際の仕事でも常用していることと思います。 そのため、有意な差が出るほどGoがCPU利用率で有利になる場面という場面はそうそうなく、またボトルネックがCPUに変わるまでチューニングする過程で勝負が決するため、Goを選択することが必ずしも有利に働くとは限りません。

ちなみに、ベンチマーカーはなぜGoで書いているのかといえば、HTTPベンチマーカーの性質から並行処理が非常に多くなり、 かつ必ずベンチマーク対象より高速に動くことを要求するためにCPUがボトルネックになるレベルでチューニングするために、Goはその問題解決に適した選択肢のひとつになるからです。 同様の特徴で言えばErlangなどでも良かったわけですが、比較的慣れており過去のISUCONのベンチマーカーでも実績があり、なにより過去のコードを使い回せるのでGoを採用していました。

そういうわけなので、各位なかよくお願いします。

まとめ

課題アプリケーションやそれをチューニングする過程で起きる問題、そしてそれを皆さんがどのように解決していったかについて解説しました。 この問題を通じて、実際のアプリケーションのパフォーマンス改善と同じように地に足つけてデバッグしながらチューニングを進めていく重要さと難しさ、そしてそれを解決できたときの楽しさを感じてもらえていたら良かったなと思います。

なお、この問題を作るに当たり合宿や事前回答会で問題やベンチマーカーに対してのフィードバックをいただけたことが完成度を高めるために非常に役立ちました。 これらを企画してくださった941さん、フィードバックを頂いたカヤック出題チームのfujiwaraさん、ken39argさん、そして事前回答にご協力頂いたtagomorisさん、gfxさん、arabikiさん、macopyさん、mix3さん、gurisugiさん、改めてありがとうございました! また、言語間移植に協力して頂いたgfxさん、arabikiさん、omegaさん、daisuzuさん、polidogさん、本当に助かりました。ありがとうございました!

今回、DeNAではこちらのメンバーで予選問題を準備しました。
  • karupanerura (問題作成、ベンチマーカー実装)
  • sonots (ベンチマーカー実装)
  • rkmathi (インフラ、プロビジョニング等)
  • xaicron (ポータル作成)

  • DeNAではゲームのバックエンドサーバーなど大量のトランザクション/ロックと戦う仕事も数多くあり、プラットフォーム事業では捨てるわけにはいかない大量のデータを扱いながら如何に大規模アプリケーションを高速に保ち安定運用するか、などといった課題が数多くあります。 僕自身も業務内で何度かチューニングする必要性に迫られ、その問題を解決してきました。実際の問題解決とISUCONはやはり違いますが、それでもこれらの課題の解説に興味がある方はぜひDeNA社員に声を掛けてみてください。

    以上をもって解説と講評とさせていただきます。ありがとうございました。
    Read more...

    オンライン予選の利用言語比率を公開します。オンライン予選は528組の参加があり、起動に成功したチームは508組となりました。

    オンライン予選 利用言語比率

    利用率の全体ランキングは以下の通りです。

    Go   203組 40.0%
    Ruby  106組 20.9%
    Perl   70組 13.8%
    Python 65組 12.8%
    PHP   44組 8.7%
    Node.js 20組 3.9%


    本選出場が決まった30チームに限定すると以下となります。

    Go   19 63.3%
    Python 6 20.0%
    Perl   2 6.7%
    PHP   2 6.7%
    Ruby  1 3.3%

    ※複数言語のサーバーが立ってたときは(そのチームの持つサーバー郡の中で)最も立ってる台数が多かった言語を採用言語とみなしています
    ※ログインしていない場合は初期状態であるPerlとして換算されている場合があります
    ※起動に成功しなかったチームが一定数あります


    ご参加いただいた皆さんの感想などはこちらにまとめています。
    ISUCON8 オンライン予選 関連エントリまとめ : ISUCON公式Blog
    Read more...

    全てのチームの順位とスコアを参考値として掲載いたします。

    順位 スコア チーム名 (チーム人数)
    1位 90,933 †漆黒のすぐちむ† (3)
    2位 69,489 FetchDecodeExecWrite (3) [学生]
    3位 58,252 👨‍👨‍👦💭💰 (3)
    4位 52,661 tailed 学生(1) [学生]
    5位 48,698 .dat (3)
    6位 45,586 ここで一句 (3)
    7位 45,283 死闘の果てに (3)
    8位 44,295 takedashi (3)
    9位 44,100 NaruseJun (3) [学生]
    10位 42,181 DiamondPrincess (3)
    11位 41,195 チーム人間性 (3)
    12位 41,000 MNSYS (3)
    13位 40,867 ディメンジョナルハイソサイエティぬれねずみ (3)
    14位 40,069 しゃかラン (3)
    15位 39,677 山形組 (2)
    16位 39,282 k02 (3)
    17位 38,588 最大の敵は時差 (3) [学生]
    18位 36,471 飲んだくれ穏健派 (3)
    19位 35,648 流れ弾 (3)
    20位 35,379 ワイハリマ (3)
    21位 34,719 リュウグウ (3)
    22位 34,178 ほうじ茶ラテ部 (3)
    23位 33,818 (´・_・`)( 'ω') (2)
    24位 32,957 焼肉ジャンボチキン (3)
    25位 32,853 白金動物園 (3)
    26位 32,053 サイバー丼 (3)
    27位 30,699 ドラえもんズ (3)
    28位 30,491 REQLY (3) [学生]
    29位 30,195 狂犬 (3)
    30位 29,908 SPF (3)
    31位 29,879 Third Party Cookies (3)
    32位 28,435 ワイルドワイクボタ (3)
    33位 27,608 ガネーシャ (2)
    34位 27,118 isucon_friends (3)
    35位 26,873 RE: ゼロから始めるISUCON (1)
    36位 25,442 スロークエリに自信ニキ (3)
    37位 24,619 隼(Hayabusa) (3)
    38位 24,353 箱 (1)
    39位 23,601 メガBIG丼 (3)
    40位 22,785 おすぎ (1)
    41位 22,227 コマリン (3)
    42位 21,998 TRICK (3)
    43位 21,372 きりんさんチーム (3)
    44位 20,679 チームzono '18 (3)
    45位 20,654 ソレイユ (3)
    46位 20,110 チームりんご (3)
    47位 19,915 †漆黒ノ戦士達† (3)
    48位 19,723 エイサイハラマスコイ (3)
    49位 19,677 MRTとNKNの愉快な仲間たち (3)
    50位 19,470 体調不良により16:00頃出社します。 (3)
    51位 17,993 meowntailn (3)
    52位 17,606 都営三田線東急目黒線直通急行日吉行 (3)
    53位 17,601 百万円ドリブン (3) [学生]
    54位 17,554 へしこず (3)
    55位 17,423 瞬殺の美学 (3)
    56位 17,390 水田 (3)
    57位 17,267 うどんきれいなGo (3)
    58位 17,095 TopChiyogiras (3)
    59位 17,022 :money_with_wings: (3)
    60位 16,577 reiga (2)
    61位 16,567 IQ1 (3) [学生]
    62位 16,156 チーム rehash.fm (3)
    63位 16,003 GPUバウンド (3)
    64位 15,842 バナナマン -4thの覚醒- (3)
    65位 15,671 国際高等教育院棟 (3) [学生]
    66位 15,649 システムオペレーターズ (3)
    67位 15,355 kstm (3) [学生]
    68位 15,354 みかん技術部 (3)
    69位 14,285 zin-gonic (3) [学生]
    70位 14,206 autorun (3)
    71位 14,175 ちかろうどうしゃ(╹◡<)⌒☆ (3)
    72位 14,055 APTG3-RR428 (3)
    73位 13,992 せあぶら (3) [学生]
    74位 13,980 受験生の仇 (3) [学生]
    75位 13,978 ケーキ屋さん見習い (3)
    76位 13,816 golang勉強中 (3)
    77位 13,628 ultra_fast_gopher (3) [学生]
    78位 13,621 :thinking_face: (3) [学生]
    79位 13,450 sunpro'); DROP TABLE member... (3) [学生]
    80位 13,153 (´・ω・`) (3) [学生]
    81位 13,149 おっさんずラボ (3)
    82位 12,695 チーム鉄塔 (3)
    83位 12,568 松之助プレートライス普通 (3) [学生]
    84位 11,957 俺出ると優勝しちゃうけど大丈夫? (3)
    85位 11,878 ISUCON8は律儀で真面目な国民ならば十分乗り切れる (3)
    86位 11,499 redstone (1)
    87位 11,467 チームプロ開 (3)
    88位 11,309 うさぽとくまぽと時々パフォーマンスチューニング (3)
    89位 11,191 3N (3)
    90位 11,104 百万円で寿司を食べたい (2)
    91位 11,065 Abema Towersの最上階に住みたい (3)
    92位 10,859 眠い (1)
    93位 10,562 itf (3)
    94位 10,531 (**´ >ω<)゙;`;:゙;ヘックス (3)
    95位 10,221 えす爺 (2)
    97位 10,135 サンフランシスコ (3)
    98位 10,131 ちくわ物語 (3)
    99位 10,129 chirimenjako-- (3)
    100位 10,066 たねまき (3)
    101位 9,939 みかんちゃん (3)
    102位 9,786 家に帰ると炉端焼きが必ず死んだふりをしています (3)
    103位 9,763 nil (3) [学生]
    104位 9,439 OyG MkIII Custom Zero Type ... (3)
    105位 9,336 カニオムライス (3)
    106位 9,229 すたぁらいと (3)
    107位 9,036 ARINE (3)
    108位 8,805 エンジニアはみんな河合荘 (3)
    109位 8,346 getting_over_32 (3) [学生]
    110位 7,953 LIFE〜夢のカタチ〜 (2)
    111位 7,908 かっぱぺんぎん㌠ (3)
    112位 7,829 株式会社イーグルジャンプ 秋葉原ラボ (3)
    113位 7,776 Z/2Z (2)
    114位 7,506 アトラエネス (3)
    115位 7,435 しょラーさんのおかげ (3) [学生]
    116位 7,388 きせ重 (2)
    117位 6,897 sabanomisoni (3) [学生]
    118位 6,799 sv-soc (3)
    119位 6,452 sushicon (3)
    120位 6,323 yugo (1)
    121位 6,186 theorem (3)
    122位 6,134 ITABASHI_WARD (2)
    123位 5,823 予選落ち (3)
    124位 5,753 ドラゴンアイランド (3)
    125位 5,688 クソアニメ同好会 (3)
    126位 5,489 ホッシャニスト (3)
    127位 5,278 フレンドシップマネジメント部直行目安箱 (3)
    128位 4,682 BlackPolo (3)
    129位 4,680 なる 学生(2) [学生]
    130位 4,555 脆弱性アタック太郎 (3)
    131位 4,518 チーム川村 (3)
    132位 4,469 イスコンズ (3)
    133位 4,378 ゆるふわ過激派 (3)
    134位 4,366 sengine (2)
    135位 4,094 ウデムシマニア (3)
    136位 4,015 okn (3)
    137位 3,964 ラディカル・グッドスピード/脚部限定 (3)
    138位 3,933 クラフツマン (3)
    139位 3,896 しあわせプリン (3)
    140位 3,838 kst (3)
    141位 3,756 889ba7a73 (3)
    142位 3,403 kkk (3) [学生]
    143位 3,360 fatware (3)
    144位 3,335 p2mine (1)
    145位 3,283 髪の毛 (3) [学生]
    146位 3,215 かすふぇ (1)
    147位 3,097 道玄坂旅情 (3)
    148位 3,046 dark-matter (3)
    149位 3,026 と (1)
    150位 2,896 青山サンライトビルズ (3)
    151位 2,894 Not飲んだくれ (3)
    152位 2,473 Pusic (3)
    153位 2,387 railsへの執着はもはや煩悩の域であり、開発者一同は... (3)
    154位 2,124 MT1 (1)
    155位 1,965 NICO★おばけちゃん (2)
    156位 1,948 ebi (3)
    157位 1,783 ( ^ ^ )/( ' ' )/( * * )/ (3) [学生]
    158位 1,709 TEAM Copper IV (3)
    159位 1,636 無限ネットワーク (3)
    160位 1,580 イスッ コンッ コンッ (3) [学生]
    161位 1,561 gsn (1)
    162位 1,520 indo8 (3)
    163位 1,514 ツンデレムササビ研究所 (3) [学生]
    164位 1,480 Team werewolf (1)
    165位 1,469 もうC#無かったら他言語でいく (3)
    166位 1,436 イス投げスクアッド (3) [学生]
    167位 1,416 温野菜 (3)
    168位 1,404 makibishi (3) [学生]
    169位 1,391 しげお 学生(2) [学生]
    170位 1,384 NULL (3)
    171位 1,340 わんにゃん動物園 (3)
    172位 1,321 イラブチャー (3) [学生]
    173位 1,318 FWT5 (3)
    174位 1,315 にころかわいい (3)
    175位 1,314 東亜飯店(サテライト店) (3)
    176位 1,308 チームfreeedom (3) [学生]
    177位 1,305 ISDN (3)
    178位 1,302 ばなな 学生(2) [学生]
    179位 1,286 おくむらファミリーハウス (2)
    180位 1,283 papico (2)
    181位 1,282 sohmens (3)
    182位 1,271 winjisucon (3) [学生]
    183位 1,267 墨でそう (3)
    184位 1,260 おいしい++ (2)
    185位 1,257 Mofmof-w 学生(2) [学生]
    186位 1,250 Lakers (2)
    187位 1,242 みんな幸せみんなハッピーシステム (3)
    188位 1,228 チーム沼津 (3)
    189位 1,226 5_apples (3) [学生]
    190位 1,217 いんふらえんじにゃー (2)
    191位 1,209 river-1 (2)
    192位 1,208 oxtair (3) [学生]
    193位 1,201 グガグガ (3) [学生]
    194位 1,193 チームトラベルブック (3)
    195位 1,185 FKS (3) [学生]
    196位 1,183 中身が少し赤い程度王国の営業時間が23時までに短縮されただよ (3) [学生]
    197位 1,180 ばくそく (3)
    198位 1,174 TEAM そっ閉じ (3)
    199位 1,165 チーム 松樹 (3)
    199位 1,165 725 (2)
    201位 1,162 Abrams (3)
    202位 1,160 ID厨 (3)
    203位 1,157 むりぽ (2)
    204位 1,138 チームますらぼ (2)
    205位 1,121 チームわいちゃん (2)
    206位 1,105 Booooost (1)
    207位 1,102 シャンシャンちるどれん with K (3)
    208位 1,101 nkmr-lab (3) [学生]
    209位 1,094 実務では AWS に載せ替えるのが最初の施策 (3)
    210位 1,092 RF 学生(2) [学生]
    211位 1,089 あかいタコヤキ (3)
    212位 1,086 recode 学生(2) [学生]
    213位 1,073 GVA (3)
    214位 1,072 drink and root (3) [学生]
    215位 1,069 キラッと落☆単 (3) [学生]
    216位 1,055 YSK (3)
    217位 1,054 危機管理同好会 (3) [学生]
    218位 1,047 nika (1)
    219位 1,045 kouheiszk (1)
    220位 1,044 DDSペンギンズ (3)
    221位 1,027 深海少女 (2)
    222位 1,024 たけぱん (1)
    223位 1,023 ISUCONチョットデキルズ (3)
    224位 1,022 駆け出しプログラマー's (3)
    225位 1,014 ippai (1)
    226位 1,014 フィード三銃士 (3)
    227位 1,005 veget (2)
    228位 1,002 mi (1)
    229位 1,000 yskoht (1)
    230位 990 不整脈B (3)
    231位 975 みんとランチャー (3)
    232位 974 三島ブラザーズ (3)
    233位 973 ニンジャくん (3)
    234位 959 平成最後のISUCONだね。そだね〜そだね〜 (3)
    235位 946 元SIerと現SIer (2)
    236位 945 インターンとの兼ね合い 学生(2) [学生]
    237位 918 髭物語 (3)
    238位 911 body_make (3) [学生]
    239位 902 過渡期 (2)
    240位 892 nyannyanOL 学生(1) [学生]
    241位 874 よしだとすずき (2)
    242位 849 ※チーム名に公序良俗に反する名前は使わないでください (3)
    243位 843 70.7kg (3)
    244位 827 プログラムも忖度すれば速くなる (3)
    245位 816 はぐれ艦 (1)
    246位 809 愛花 (3)
    247位 803 人生どうでもAES (3) [学生]
    248位 784 ゆ (1)
    249位 777 munepom (1)
    250位 728 rm -rf --no-preserve-root / (3)
    251位 694 SushiSobaRamen (3) [学生]
    252位 687 そんなこと言うのはこの口(53番ポート)か?...んっ... (3)
    253位 655 YO!HEYHEYHEY! (3)
    254位 444 あ 学生(2) [学生]
    255位 339 urchin (2)

    ■以下は再起動試験を通らなかったチームですが参考値を掲載しています
    fail 65,801 わんこポテト (3)
    fail 55,982 hhkb (3) [学生]
    fail 41,852 チームブルベアくん (3)
    fail 36,640 negainoido (3)
    fail 34,342 chanmiss (3)
    fail 33,914 335 (3)
    fail 30,824 yokohama-north (3)
    fail 29,841 TeamYVR (3)
    fail 29,298 ENIAC (2)
    fail 28,641 ハーゲンダッツ100円 (3)
    fail 26,221 SELinuxはEnforcing以外あり得ない (3)
    fail 25,452 チーム終活 (3) [学生]
    fail 25,362 おいで夏の境界線 (3)
    fail 24,658 さばかんちゃーはんかれー (3)
    fail 24,491 わんだほー (2)
    fail 24,410 g0tiu5a (3)
    fail 23,958 .tar.gz (3)
    fail 23,034 Oysters1 (3)
    fail 22,336 メンチコロッケカレー (3)
    fail 21,775 そたぶろるっつ (3)
    fail 21,690 オシャレ怪盗スワロウテイル (3)
    fail 21,447 チームいいだばし (3)
    fail 21,356 nihonshu (3)
    fail 20,524 モテスパイラル (3)
    fail 20,469 ラーメン・カロリー ゼロ (3)
    fail 20,326 巣牛茶 (3)
    fail 20,304 sayotan (2)
    fail 19,045 DMZ (3)
    fail 16,694 ドン勝 (3)
    fail 15,982 さわやか (3)
    fail 15,801 xxxxx (3)
    fail 15,577 QPM (3)
    fail 14,697 株式会社イーグルジャンプ 六本木ラボ (3)
    fail 14,473 一元 (3)
    fail 13,689 FCCPC_arisugawa (3)
    fail 11,843 Redirect (3)
    fail 10,900 ブレーキ踏まない (3)
    fail 10,550 ベッドから飛び起きたくなる名前 (3)
    fail 10,507 ボラギノール (2)
    fail 10,212 会社の犬(放し飼い) (3)
    fail 10,208 マーブルチョコ (3)
    fail 9,422 gcf (3) [学生]
    fail 9,032 tmp (3) [学生]
    fail 8,938 console.log (3)
    fail 8,570 福岡ハリケーンズ (3)
    fail 8,464 Dack (3)
    fail 8,195 D. D. Akihiko (2)
    fail 8,188 バーチャルのjaホリネズミ競プロISUCONおじさん (3)
    fail 7,329 :thinking_face: (3) [学生]
    fail 7,131 Malaysian (3) [学生]
    fail 6,974 cm-osaka (3)
    fail 6,894 ポテチはのり塩派 (3)
    fail 6,883 okuribunt (3)
    fail 6,247 音楽大大大人間 (2)
    fail 5,973 Landau (2)
    fail 5,941 塩昆布 (3)
    fail 4,974 Rubyはいいぞ (3)
    fail 4,834 くもキャスト (2)
    fail 4,098 牛久大仏「う〜ん、顔採用w!」 (3) [学生]
    fail 3,739 チームカリスマ (2)
    fail 3,674 ✟みんなで一緒に堕天しない?✟ (3)
    fail 3,510 SystemEngineers (3)
    fail 3,441 メキシコ沖 (3)
    fail 3,203 LGTM☆ (3)
    fail 3,135 早くなったらラッキー (3) [学生]
    fail 3,111 saltydog (3)
    fail 3,098 hetenko (3)
    fail 2,891 ツナ缶 学生(2) [学生]
    fail 2,714 よんちぇる (2)
    fail 2,692 Bremen (3)
    fail 2,654 GolangじゃなくてRubyで参戦したい (2)
    fail 2,627 キボーソーレン (3)
    fail 2,521 東亜飯店(南平台) (3)
    fail 2,356 坂寝 (3)
    fail 1,590 LANケーブルが挿さってないだけでした。 (3)
    fail 1,551 ソースコードオンライン (3)
    fail 1,467 今夜がyyyymmdd (3)
    fail 1,430 転送戦隊PacketMen (3) [学生]
    fail 1,422 スタイル・エッジですがよろしくおねがいします (3)
    fail 1,411 大和路線ウンバボ (3)
    fail 1,401 イヤホンジャックでカレーライス食べたい (3)
    fail 1,399 ゆるふわギャング (2)
    fail 1,350 PwnPwnPain (3) [学生]
    fail 1,336 hackenduro (3)
    fail 1,323 cinnamons (3)
    fail 1,323 Team Karin (3)
    fail 1,321 01cpp (2)
    fail 1,320 ttt (1)
    fail 1,319 勤怠時間が30分足りてませんでした (3)
    fail 1,310 Future Works (3) [学生]
    fail 1,300 GS (2)
    fail 1,290 citrus (1)
    fail 1,289 川にいる猫が可愛い (3)
    fail 1,281 文鳥 (1)
    fail 1,257 そり (2)
    fail 1,254 ISUWAT (3)
    fail 1,241 okdog (2)
    fail 1,225 ふぁん (1)
    fail 1,210 29 (3)
    fail 1,210 浅はか (3)
    fail 1,209 CheapLearning (3) [学生]
    fail 1,209 Proudit (2)
    fail 1,207 くにきやらぼって名前から変えようって話してたら応募忘れ... (3)
    fail 1,187 sushiro (3)
    fail 1,178 rat123 (3) [学生]
    fail 1,166 ワイルドライゴライ (3)
    fail 1,155 mi_chan (3) [学生]
    fail 1,154 元scoutyインターンず (3) [学生]
    fail 1,146 By end of Sunday (3)
    fail 1,136 躁鬱シャトーブリアン (3)
    fail 1,115 たまごじゃがりこヨーグルト (3) [学生]
    fail 1,101 おやすみパーリータイム (1)
    fail 1,059 motsu鍋 (2)
    fail 1,043 REY (3) [学生]
    fail 1,025 No Budget No Life (3)
    fail 1,013 F.R.A.N.K.S. (3)
    fail 1,005 土曜のほうが気持ち的にRubyyyyyy (3)
    fail 999 chang (1)
    fail 999 mk5 (2)
    fail 984 松研 (1)
    fail 967 チームトークノート (3)
    fail 967 18hogehoge (3)
    fail 924 仙白岩 (3)
    fail 920 声優オタク (2)
    fail 910 あんず (3) [学生]
    fail 896 ズッコケ三人組 (3)
    fail 891 だーくねす☆らいじんぐ (3)
    fail 852 Axe (1)
    fail 848 上智大学エレラボ (3) [学生]
    fail 777 忘年会炎上 (3)
    fail 744 へんさちさん (3) [学生]
    fail 692 チームひとり (1)
    fail 681 denys (2)
    fail 627 チームプリン (3)
    fail 571 木 (3) [学生]
    fail 571 柴犬 (3)
    fail 562 1人でも頑張れる🗿 (1)
    fail 523 tar (3) [学生]
    fail 479 涙で予選しか見えねえ (2)

    ■以下はベンチマークを1度も実行していない、または最終スコアが0点のチームです
    0 石油王 (2)
    0 ぶっちぎり (3)
    0 ゴースト (1)
    0 ふんばり温泉チーム (3)
    0 feel (2)
    0 Re:Fから始めるWeb生活 (3)
    0 ぞい (3)
    0 Bayesian (3) [学生]
    0 enomotodev (1)
    0 Let's build (3)
    0 kyouken (3)
    0 しましまスペシャル (3)
    0 普通のエンジニアが【いすこん】やってみた。 (3)
    0 DICE (3) [学生]
    0 だってウチらポンデライオンやし (2)
    0 おいしいおやつロール(モカ) (3) [学生]
    0 Oops (3)
    0 準新作 (3)
    0 予算/Zero (3)
    0 typoの達人 (3)
    0 BigTreeDeer (3) [学生]
    0 ニューウェーブ (3)
    0 luminous (3)
    0 GrilledMeat (3)
    0 #PTH (3)
    0 ガチムチレンジャ (3)
    0 nusec 学生(2) [学生]
    0 定時退社主義 (3)
    0 urabu (3)
    0 Beef Chicken Pork( ゚ρ゚) (3)
    0 Catechine (3)
    0 DARC (2)
    0 インフラ勉強会 (3)
    0 円山町 (3)
    0 DRMTLS2010 (3)
    0 YKM (3)
    0 カタカタッターン (3)
    0 ポン (3)
    0 青眼の究極竜 (3)
    0 アンダーザブリッヂ (3)
    0 5000兆円欲しい!! (3) [学生]
    0 Universal type (2)
    0 プリン少年 (3)
    0 格安sim (3)
    0 centくん (3)
    0 OpsBear (3)
    0 ( (0) / (0)) ☆祝☆ (3)
    0 そんなバナナ!! (3)
    0 めんじにあ (2)
    0 生.jpg (3)
    0 UNITES (3)
    0 だいちゃんず (3)
    0 news (3)
    0 WestWebWorld (3)
    0 鯖の水煮 (2)
    0 ニキータ三銃士 (3)
    0 チーム焚き火 (3)
    0 Eine Maus (3) [学生]
    0 TKDNJ2018 (2)
    0 marumarus (2)
    0 チンパン (3) [学生]
    0 ギー岡東京部 (2)
    0 S3 (3)
    0 吞み歩き部 (3)
    0 おでん (3)
    0 tickerwall (2)
    0 スーパーテクニカルテク (3)
    0 TechCircle 1号 (3)
    0 SEGA Revo (3)
    0 36 Breakers (3)
    0 404 Not Found (3)
    0 Docking🌟Heart (3)
    0 M.K.O. (3)
    0 月末期末世紀末 (3)
    0 ダークイルミネイト 学生(2) [学生]
    0 とりあえずモヒート (3)
    0 西アジア代表 (3)
    0 a.p.t (3)
    0 DJバーチャルうし(六段, 元十段, 中伝) (3)
    0 イカ焼きワイン (3)
    0 ANTI-WCDI (3)
    0 チーム高円寺 (2)
    0 チームタピオカ (3)
    0 面白いチーム名を (3)
    0 はんぺんズ (3)
    0 WCDI (3) [学生]
    0 チームand factory (3)
    0 あたまのわるいひと (2)
    0 N+ (3)
    0 galbo (2)
    0 ♲ペンダホワイト♲ (3) [学生]
    0 MoriMoriForest 学生(2) [学生]
    0 KoBAR (3)
    0 絶賛リリイベ真っ最中 (3)
    0 fugusuki (1)
    0 三原工務店 (2)
    0 チーム光合成 (2)
    0 会員証 (1)
    0 🈚️ (3) [学生]
    0 マンガチームOB (3)
    0 meno mosso (3)
    0 これでも娑婆かいな (1)
    0 ヘルシーボーイズ 学生(2) [学生]
    0 おばかずき (3)
    0 チームスパルタン (3)
    0 ガラスボッチ (2)
    0 まな板 学生(1) [学生]
    0 白丸 (2)
    0 庭師の塔のおっさんs (2)
    0 まだ1hage目 (2)

    Read more...

    ISUCON8 本選出場者が予定よりも早く決まりましたのでお知らせいたします。
    今回のオンライン予選は合計528組(一般 432、学生 96)、1,392名の皆さんにご参加いただき過去最高の規模となりました。

    本選への出場枠についておさらいです。LINE株式会社 新宿ミライナタワーオフィスにて開催される本選出場へ参加する30チームの選出条件は以下となっています。

    1. 予選各日の終了時スコアにおける上位3チーム
    2. 予選両日を通し、1の該当チームを除いた中での上位12チーム
    3. 予選両日を通し学生枠参加チーム内における上位12チーム
     ※ただし、学生チームが一般枠の基準で通過した場合、学生枠はそのチームを含めずに12チームを選出する

    それでは2日目の結果とあわせて、ISUCON8 本選出場30チームを発表いたします。

    1日目 上位3チーム
    ・👨‍👨‍👦💭💰 58,252
    ・ここで一句 45,586
    ・NaruseJun [学生] 44,100

    2日目 上位3チーム
    ・†漆黒のすぐちむ† 90,933
    ・FetchDecodeExecWrite [学生] 69,489
    ・tailed [学生] 52,661

    両日3チームを除いた上位12チーム
    ・ .dat 48,698
    ・死闘の果てに 45,283
    ・takedashi 44,295
    ・DiamondPrincess 42,181
    ・チーム人間性 41,195
    ・MNSYS 41,000
    ・ディメンジョナルハイソサイエティぬれねずみ 40,867
    ・しゃかラン 40,069
    ・山形組 39,677
    ・k02 39,282
    ・最大の敵は時差 [学生] 38,588
    ・飲んだくれ穏健派 36,471

    学生枠上位12チーム
    ・REQLY 30,491
    ・百万円ドリブン 17,601
    ・IQ1 16,567
    ・国際高等教育院棟 15,671
    ・kstm 15,355
    ・zin-gonic 14,285
    ・せあぶら 13,992
    ・受験生の仇 13,980
    ・ultra_fast_gopher 13,628
    ・ :thinking_face: (team id 18)  13,621
    ・sunpro'); DROP TABLE member... 13,450
    ・(´・ω・`) 13,153

    以下のチームは最終スコアが上位12チームに含まれていましたが再起動試験をパス出来なかったため失格となりました。
    ・わんこポテト 65,801
    ・hhkb[学生] 55,982
    ・チームブルベアくん 41,852
    ・negainoido 36,640

    なお、本選出場が確定したチームが出場を辞退した場合にはスコアが高い順で繰り上がりとなる場合があります。繰り上がりとなった場合は9月19日(水)までにご連絡いたします。


    以上です。
    本選は10月20日(土) LINE株式会社の新宿ミライナタワーオフィスにて行います。本選参加は当日お越しいただける方のみとし、オンラインでの参加は不可とします。(インフルエンザなど感染力が高い病気に罹患している場合は特例を認める場合があります)また、予選と本選でチームメンバーの交代は出来ませんのでご注意ください。

    本選出場チームの代表の方へはあらためてご連絡いたしますので、お待ちください。オンライン予選にご参加いただいた皆さん、まことにありがとうございました。
    Read more...

    ・9/26 17:00 更新
    オンライン予選にご参加いただいた皆さん、ありがとうございました!
    こちらでは感想エントリや何をしたかに言及されたエントリをまとめていきます。見つけた順ですが後で何かしらのルールで並び替えます。もしここに載っていないものがある場合は ISUCON8 オンライン予選のブログ書いたよ!フォームで教えていただけると助かります。重複はこちらでチェックしますのでドシドシお願いします。

    ブログを書くまでがISUCON予選です!

    予選のTweetはこちらでまとめています
    ISUCON8 オンライン予選 Tweet まとめ#isucon - Togetter


    参加者
    本選出場
    ISUCON8予選で1日目に2位で本選出場が決まりました – catatsuy – Medium
    ISUCON8予選2位(一日目)で通過しました - 考える人、コードを書く人
    ISUCON本戦に出られることになった - hitode909の日記
    ISUCON8予選を突破した - $shibayu36->blog;
    ISUCON8予選は学生枠6位で本戦出場が決まりました - 爆速でGo!
    ISUCON8予選参加記 - ちゃっくのメモ帳
    ISUCON8予選参加記 - math314のブログ
    ISUCON8予選参加記 #isucon - MIS.W 公式ブログ
    ISUCONに初参加して予選突破した | Aim Developer
    ISUCON8予選突破しました - あおうさ@日記
    ISUCON8の予選を学生枠で突破しました | あれがながてち
    ISUCON8の予選に出てみた - /var/log/hikalium
    ISUCON8の予選を通過しました。 - DC4
    ISUCON8予選で全体2位をした - cookies.txt      .scr
    ISUCON8予選を突破しました!!!!!!! - きょこみのーと
    死闘の果てに ISUCON 8 予選を全体7位で突破した記録
    ISUCON8 :thinking_face: 学生枠で予選通過した #isucon - 私が歌川です
    ISUCON8で予選を通過しました! : KLabGames Tech Blog
    初出場3人でISUCON8予選を学生枠1位(?)で通過しました - REQLY開発ブログ
    ISUCON8にk02で参加し予選突破しました - Alligator Swamp
    ISUCON8に参加して予選通過してきました
    ISUCON8の予選突破できました
    ISUCON8 で予選を突破したのでまとめる - stop-the-world


    ISUCON8予選1日目にチーム「SELinuxはEnforcing以外あり得ない」で参加しました - netmark.jp
    ISUCON8で予選敗退してきました - 男女比はカレーと福神漬けと同じくらい
    ISUCON8予選1日目にチーム「SELinuxはEnforcing以外あり得ない」で参加して最終スコアは26,221でした - Dマイナー志向
    ISUCON8の予選に出場して負けました | わたしろぐ
    ISUCON8 予選参加してきました。 - 暇を持て余せないタイプのエンジニアブログ
    #isucon8 予選参加して、無事爆死してきたンゴ - モヒカンは正義
    bmf-tech - Road to ISUcon
    ISUCON8予選2日目に『チームますらぼ』で参加してきた! - 継続は力なり
    ISUCON8 オンライン予選に参加してみて、あらためて Web の世界は広すぎると実感した話 - shimabukuromegの日記
    ISUCON8 予選敗退した #isucon - tknzk's tech log
    ISUCON 8 予選に参加した話 | にろきのメモ帳
    ISUCON8予選の感想 - 角待ちは対空
    ISUCON8に出て予選に落ちた #isucon - はらへり日記
    ISUCON8に参加してした - 紙魚寿司のあれ
    ISUCON2018予選敗戦記 | ブログにしてブログにあらず
    ISUCON8に参加した - ぶていのログでぶログ
    ISUCONで学生2位通過...のはずが再起動でこけてしまって非常に悔しいクギイィ! - 抹茶うまい
    ISUCON8 予選に参加して再起動試験に落ちました | monolog
    isucon8予選に参加してきました
    ISUCON8予選に参加した話
    cormoran's note - ISUCON8 予選
    ISUCONの予選落ちする戦い方を公開します
    ISUCON8予選で敗退しました... - bati11 の 日記
    ISUCON 8 予選に参加しました - mayoko’s diary
    ISUCON8予選に参加して敗退した #isucon - petitviolet_blog
    ISUCON8予選で負けました - chigichan24のお気持ち表明
    ISUCON8 予選敗退した - すぎゃーんメモ
    ISUCON8 予選に参加した - k5342.hatenablog.com
    ISUCON8にRustで参加するためにしたこと - 簡潔なQ
    ISUCON8 予選で敗退した(くやしい) - 半空洞男女関係
    isucon8に参加して予選敗退してきました - azihsoyn's blog
    ISUCON9 に出る自分に言いたいこと(ISUCON8 敗退記録)
    ISUCON 8 出たそして負けた - osyoyu.hatenablog.com
    ISUCON 8 で惨敗してきました
    ISUCON 8予選のKPT
    DSAS開発者の部屋:ISUCON 8 予選で惨敗しました(リュウグウ)
    isuconでよく使うツールをまとめてみた
    ISUCON 8 予選に参加した & 敗退した - s平面の左側
    チーム「さばかんちゃーはんかれー」でISUCON8に参戦してきました。 - pe10’s diary
    初参戦のISUCONで予選敗退した話 (ヽ´ω`) < 22位 - aeroastroの日記
    ISUCON8に1人で参加してきました - 開発^3
    ISUCON8予選に参加して見事に敗北した - tpdn blog
    ISUCON8予選に参加した - a_kawashiroのブログ
    ISUCONに出てみた話 - Ryuの備忘録
    ISUCON8参加メモ - やきにくとくにきや
    ISUCON8に参加して予選通過してきました
    ISUCON8予選に参加して800点程届かず敗退しました - Konboi Note
    ISUCON8に参加しました — みんなのウェディングエンジニアリングブログ
    ISUCON8予選に参加、敗退しました - matsukaz's blog
    ISUCON8予選に参加した - yu3mars’ diary
    ISUCON予選落ち。 - /dev/nona (いっと☆わーくす!)
    ISUCON8 予選に参加して敗退しました | tkuchiki's blog
    ISUCON8予選参加記 - ぽえええええ(´・ω・`)
    console.log('ISUCON8に参加して今年も予選敗退しました') - れみゅーぶろぐ
    ISUCON8(予選)参加記 - blogpat
    ISUCON8予選で惨敗してきた話 - Goryudyuma’s blog
    ISUCON8予選に参加しました - hogashi.*
    ISUCON8に参加して轟沈した話
    ISUCON8予選に参加しました – ソフトウェア工房
    ISUCON8予選爆死しました @nitoli視点 – ソフトウェア工房
    ISUCON8予選、イイカンジになりませんでした@沖縄 - イケイケエンジニアへの道
    ISUCON8の予選で敗戦した話と感想戦で1位の点数を超えるまで頑張った話 - ◯ △ □
    ISUCON8予選に「西アジア代表」として参加してきました - kasari blog
    #isucon 8 で 惨敗してきました - ps aux | grep serinuntius
    #ISUCON8 予選に参戦してきました! - Dabits
    【ISUCON8レポート】Typetalkの若手チームでISUCON8に出場してみた。 | ヌーラボ
    ISUCON8に参加したのでその雑記
    clog
    ISUCON8の予選に出場しました。 · eviry tech blog
    Read more...

    ↑このページのトップヘ