ISUCON11予選の感想戦:ユーザーを一人も増やさない戦略が最強で1373637点出た

はじめに

弊チーム百万円ドリブンのISUCON11の本戦出場が決まりました。 実はこれで本戦出場は連続5年目です。運がいいですね。 弊チームの予選当日の動きはメンバーのaokabiかnakarioが書いてくれると思いますので、そちらを御覧ください。

f:id:CHY72:20210912210318p:plain 今回の問題の構成はこんな感じでした、シンプルで不必要な部分は削られており、今年も良い問題でした。

感想戦

さて、予選当日は449781点で7位通過できたのですが、我々は百万円ドリブンなので百万円にしか興味ありません。限界までチューニングをします。

github.com

感想戦では、この 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していくだけではだめなのです)

github.com

というわけで実装しました。ソート済みセットにCondition情報を全て載せるとEncode/Decodeに時間がかかるのでGetTrendで使用される最低限のみにしました。

... これで115万点ほどでました! Redis最強!

IsuConditionをRedisに乗っける(?)

あれあれ、このコミット、ちょっと待ってください。

f:id:CHY72:20210912213149p:plain

これ、ローカルホストに繋がってませんか? PostConditionは3台目でやってるので、3台目のローカルホストに情報を追加しても、1台目のGetTrendで参照するローカルホストのRedisには情報が更新されて無くないですか?あれあれ?

え、じゃあGetTrend更新されて無くないですか...?

GetTrendを更新せずユーザーを増やさない戦略

ISUCONDITION アプリケーションマニュアル · GitHub

アプリケーションマニュアルを読むと、GetTrendは「ちゃんと更新されているとユーザーが増える」という機能のためのAPIのようです。なるほど。確かにベンチマーカーのログを見るとユーザーが増えていない。つまり、古参メンバーのみがずっと使い続けて新規メンバーが参入してこないアプリケーションになっていたようです。

ちなみに、 127.0.0.1198.168.0.13 にして、ちゃんとGetTrendが更新されるようにすると、ユーザーがすごい速度で増えていきまたたく間にパンクしてFailしました...。

結局、GetTrendは最初のまま永遠に更新する必要がないことが分かったので、一回生成したら二度と更新しないようにし、ユーザーの存在チェックだけRedisに乗せたところ 1373637点でました。

1373637 · GitHub

ゆーざー、ふえてない

まとめ

ユーザーが増えると捌ききれないかつ、初期状態のユーザー数のままでも130万点まで行くので、今回の問題はユーザーを増やさないのが最善だと言えそうです。つまり、手を加えると逆に遅くなるAPIがあるということで、気をつけないと行けないな...と思いました。

今年こそ100万円欲しい