nakarioのほぼISUCONブログ

ISUCON出るたびブログ書く

ISUCON10本戦5位でした&感想戦88000点

百万円ならず!悔しい〜〜〜!

チーム「百万円ドリブン」としてISUCON10に出場し、良いところまではいけたもののどの賞にも引っかからない5位でした。それでも過去最高の成績だったのでそこは嬉しかったですね。

本戦でやったことと、今回は感想戦の機会が公式から提供されたのでそこで最高約88000点を取れたときにやったことを書いていきます。

チーム

百万円ドリブンは以下の3人組チームです
nakario: アプリ担当
aokabi: インフラ担当
murata: 色々担当

チームで取り組んだ記録は以下のリポジトリで公開しています
github.com

本戦

僕がやったことメインで、他メンバーの仕事にも触れつつ時系列順に書いていきます。

開始 ~ 11:30

まずログインしやすいよう.ssh/configを書いて共有します。今回は予選と同じipでアクセスできたのでやることはknown_hostsのリセットだけでした。
こんな感じでよく使うポートを開けておきます。

Host isucon-bastion
   HostName <踏み台サーバのip>
   Port 20340
   User isucon

Host app*
  ProxyJump isucon-bastion
  User isucon

Host app1
  HostName <サーバ1のip>
  LocalForward localhost:10443 localhost:443
  LocalForward localhost:10080 localhost:80
  LocalForward localhost:16789 localhost:6789
  LocalForward localhost:19876 localhost:9876
  LocalForward localhost:19999 localhost:19999

Host app2
  HostName <サーバ2のip>
  LocalForward localhost:20443 localhost:443
  (略)

Host app3
  (略)

ログインしたらデプロイキーをGitHubに登録してpushしました。

murataによく使うツール等をインストールしてもらっている間にGoのコードにpprofを仕込みます。複数バイナリに分かれていたので、pprofを仕込むのに少し手間取ってしまいました。

11:30~13:00

今回はNginxではなくてenvoyがリバースプロキシとして使われていて、不慣れなためにアクセスログを即座に出すことが出来ませんでしが、pprofとMySQLのslow.log&pt-query-digestを頼りに、GET /api/audience/dashboardが重く、またドキュメントにキャッシュ可能であることが明記されていたのでこれに取り組みました。これは典型的なボトルネックなので過去問を解いていた経験から迷わず実装できました。

このあたり(12:17)で17000点を超えていて、特別賞(20000点)を狙えそうだったのでパラメータなど色々細かい修正をしていたのですが特別賞は取られてしまいました。残念。

13:00~15:30

このあたりでaokabiがenvoyからnginxに切り替えてくれました。また、複数台構成に移行しました。この時点で1台目がnginx&bench、2台目がxsuportal、3台目がMySQLでした。このくらいの時点では1位を取れてました。

f:id:nakario_jp:20201005184159p:plain
ISUCON10本戦1位だった瞬間

自分はweb pushの実装に取り組み始めたのですが、提供されたサンプルコードを試しているときにcontestant_idとteam_idを取り違えていて、ずっと困惑していました……。

15:30~16:30

Web Pushの実装が終わり、35000点くらいになりました。

16:30~17:30

コンテストフリーズ後の /api/audience/dashboard のキャッシュの更新を止めました。これは振り返って考えると判断ミスだったかなと思います。影響範囲が限定的なので。せっかくnginxに移行してくれていたのに僕がアクセスログを見てなかったこと、直前に取り組んだログイン確認の軽量化とclarificationの軽量化がエラーでまくりで諦めたことが大きかった感じです。

17:30~終了

途中からいろんなエラーが出まくっていて(unexpected EOF、connection reset by peer、http2: server sent GOAWAY等)そのうちの一つである「あるべき通知を受信していない」エラーに取り組みましたが結局効かなかったです。
競技時間中は最高40924点を出していたんですが、上記エラーが解決できず、それに加えて(おそらく)DBコネクションのリソース超過による減点が多く最終結果は30834点でした。

本戦感想

今回はドキュメント量が多く開始時にあっけにとられ、初っ端からサーバの1台がOOMで死にかけ、pprofにも手間取るなど色々ありましたが出だしは良かったと思います。それに対して後半は冷静さに掛けていたかなと思いました。ボトルネックの解消はさんざん練習しましたが、エラーの原因絞り出しが弱いと分かったので何かしら対処はしたいと考えています。

感想戦

10万点目指して頑張りましたが、届かず最高88000点でした。くやしい〜〜〜〜〜〜!
やったことを列挙します。

  • freeze中のpublic dashboardで304を返す
  • clarificationsのn+1解消
  • list notificationsにsleepを入れてアクセス量をへらす(Cache-Control: immutable (?)に終了後気付いた)
  • アプリの1バイナリ化
  • leaderboardテーブルの作成
  • teamテーブルへのnon_student_countカラムの追加
  • contestantのオンメモリ化
  • clarificationsのオンメモリ化
  • contestant dashboardのキャッシュ
  • notificationsのオンメモリ化
  • push_subscriptionsのキャッシュ
  • interpolateparams=true

最終的にteam capacityは200、構成はapp1:なし、app2:mysqlm,app3:アプリ & nginxになりました。

まとめ

次回(あれば)今度こそ百万円とる!!!!