ISUCON5 本戦に参加して5位でした

去年 に引き続き†空中庭園†《ガーデンプレイス》として @ryotarai@gfx と参加して、結果は5位でした http://isucon.net/archives/45869121.html 。コードは https://github.com/ryotarai/isucon5

ISUCON5 予選の反省として、最初はプロファイルと手元での動作に最低限必要な変更以外はせずにコードを読むと決めていて、nginx の log_format を変えたり stackproflineprof を仕込んだりしてベンチマークを実行した後は、各自アプリケーションの理解に集中していた。 僕は /data から叩かれている外部 API の挙動をとくに調べていて、

  • GET リクエストしかないし、エンドポイントの情報は DB に入ってるけど更新されることもない
  • ken と ken2 という2つの似たエンドポイントがあるけど、実は全く同じっぽくて、しかも zipcode に対して返ってくる答えは一定っぽいので、2つをまとめた上で zipcode をキーにしてキャッシュできそう
  • surname、givenname もそれぞれ q をキーにしてずっとキャッシュできそう
  • tenki は毎回違う値が返ってくる
    • 実際には3秒くらいで変わることに @ryotarai が後で気付いて、その期間だけキャッシュするようにしていた
  • perfectsec、perfectsec_attacked の2つは https でリクエストするようになっていて、http だと通らない
  • perfectsec、perfectsec_attacked の2つも毎回違う値が返っていてキャッシュできなさそう
    • 実際には perfectsec_attacked は20秒くらいはキャッシュできることが後からわかって、最終的にはキャッシュが入ってた
  • それぞれのエンドポイント間に依存関係はなくて、全部並列にとってこれそう
    • このときは適当に Thread.start すればいいかと思っていたけど、@gfx が並列化を実装するときにちゃんとスレッドプールくらいは使いたいという話から expeditor 使おうということになった

あたりを見ていた。

だいたい12:30頃から実際に app.rb を編集し始めて、僕は

  • ken2 の結果を Redis に無期限でキャッシュしてベンチマークが通るかどうか → 通った
  • endpoints を DB から Ruby の定数にもってくる
  • ken を ken2 にマージしてベンチマークが通るかどうか → 通った (これで実質 ken もキャッシュされている)
  • surname、givenname も無期限でキャッシュしてベンチマークが通るかどうか → 通った
  • users を PostgreSQL から Redis へ。同時にパスワードをハッシュするのをやめて直接保存するように

ということをしていた。このへんが終わったのが15時過ぎくらいで、1台のみ使って2万点くらい出していた気がする。 ここから @ryotarai が3台使うような構成に変更していって、5万点をこえ始めていた。 Web API コールがどうしても遅くて /data が詰まると unicorn のワーカを使い切ってしまうので、unicorn のワーカ数をかなり大きめにしつつ3台に配置し、a にはベンチマーカからリクエストを受ける nginx を置いて3台にプロキシし、b には Redis を置くようにした。 endpoints は Ruby の定数にしたし、users は /initialize で Redis に入れてるし、subscriptions も @gfx が /initialize で Redis に入れるようにしていたので、すでに PostgreSQL は /initialize 以外では不要になっていた。

ベンチマークがたまに fail するようになっていて、そのデバッグで16:30頃から1時間くらい使っていた。何で fail しているのか分かるまで時間がかかってしまったのがつらい。 最終的にわかったのはどうも /initialize がたまに30秒以内に終わってないっぽくて、/initialize は Redis がいる b に常にプロキシするようにしたら安定した。 スコアは5万点だったり3万点だったりして、あんまり安定しなくて結構不安だった。

最後は a にいる nginx の CPU 使用率が高いのが気になっていて、@ryotarai が振り分けの重み付けを調整しながら僕はアセットを gzip して gzip_static するようにしたりしていた。 終了15分前くらいに念のため3台とも reboot してみて、ちゃんと Redis が起動してベンチマークが fail しないことを確認して終了。 最終結果のスコアは86,210点で、競技中のベストよりも高い結果だった。

終了後に聞いた話の中では RACK_ENV=production が非常に痛かった http://diary.sorah.jp/2015/11/02/isucon5f 。3位との差はそんなに大きくなかったので、もしかしたら3位には入れていたかもしれないと思うと悔しいけどしょうがない。

去年から参加し始めたけど去年よりよくなってる感触はあるので次は入賞したい。