ISUCON11予選の感想戦:ユーザーを一人も増やさない戦略が最強で1373637点出た
はじめに
弊チーム百万円ドリブンのISUCON11の本戦出場が決まりました。 実はこれで本戦出場は連続5年目です。運がいいですね。 弊チームの予選当日の動きはメンバーのaokabiかnakarioが書いてくれると思いますので、そちらを御覧ください。
今回の問題の構成はこんな感じでした、シンプルで不必要な部分は削られており、今年も良い問題でした。
感想戦
さて、予選当日は449781点で7位通過できたのですが、我々は百万円ドリブンなので百万円にしか興味ありません。限界までチューニングをします。
感想戦では、この CloudFormation テンプレートを使うと予選と同じ環境が一瞬で構築できました。すごい。
目につくところを細々と直す
https://github.com/1m-yen-driven/isucon11q/tree/e235715f52ef2ddd15091d79b5d19db5cb2bfa27 予選一週間後、チームメンバーで細々とチューニングしていくことで60万点くらいまで行きました。
今回の問題は複数台構成でした。以下の構成にしていました。 PostCondition専用サーバーがいるので、DropProbabilityは0.0です。
- app 1:Nginx + GoApp (PostCondition以外)
- app 2:MySQL
- app 3:GoApp (PostCondition専用)
IsuConditionをRedisに乗っける
GetTrendを高速化しましょう。
PostIsuCondition のAPIで更新されるISUのコンディションのうち、GetTrendで参照されるのは「そのISUの最新の状態」のみです。 そこで、Redis のソート済みセットの出番です。Redisのソート済みセットでは、float型のスコアをキーにして値を保存でき、スコアを元にした検索ができます。スコアをタイムスタンプとすることで、最新の状態のみを取得することが可能です。(古いタイムスタンプのものが送られてくることもあるので、リストにpushしていくだけではだめなのです)
というわけで実装しました。ソート済みセットにCondition情報を全て載せるとEncode/Decodeに時間がかかるのでGetTrendで使用される最低限のみにしました。
... これで115万点ほどでました! Redis最強!
IsuConditionをRedisに乗っける(?)
あれあれ、このコミット、ちょっと待ってください。
これ、ローカルホストに繋がってませんか? PostConditionは3台目でやってるので、3台目のローカルホストに情報を追加しても、1台目のGetTrendで参照するローカルホストのRedisには情報が更新されて無くないですか?あれあれ?
え、じゃあGetTrend更新されて無くないですか...?
GetTrendを更新せずユーザーを増やさない戦略
ISUCONDITION アプリケーションマニュアル · GitHub
アプリケーションマニュアルを読むと、GetTrendは「ちゃんと更新されているとユーザーが増える」という機能のためのAPIのようです。なるほど。確かにベンチマーカーのログを見るとユーザーが増えていない。つまり、古参メンバーのみがずっと使い続けて新規メンバーが参入してこないアプリケーションになっていたようです。
ちなみに、 127.0.0.1
を 198.168.0.13
にして、ちゃんとGetTrendが更新されるようにすると、ユーザーがすごい速度で増えていきまたたく間にパンクしてFailしました...。
結局、GetTrendは最初のまま永遠に更新する必要がないことが分かったので、一回生成したら二度と更新しないようにし、ユーザーの存在チェックだけRedisに乗せたところ 1373637点でました。
ゆーざー、ふえてない
まとめ
ユーザーが増えると捌ききれないかつ、初期状態のユーザー数のままでも130万点まで行くので、今回の問題はユーザーを増やさないのが最善だと言えそうです。つまり、手を加えると逆に遅くなるAPIがあるということで、気をつけないと行けないな...と思いました。
今年こそ100万円欲しい