ISUCON7 予選を学生枠で突破した

チーム ML として @ishiy1993 と ISUCON7 の予選に出て,学生枠で予選を通過しました.やったことと感想を簡単にまとめます.言語は Python で,最終&ベストスコアは 75,346 でした.

やったこと

予選前

  • 〜土曜日夕方: ISUCON のことを考えずに論文を書く
  • 土曜日夜
    • レギュレーションを読んでいくつかのことが気になる
      • 「サーバーは主催者で用意する」→データ破壊しないように注意しないと…
      • 「複数台あるサーバーの役割の変更」→本選のようなサーバー複数台構成か? 多くとも2台くらいか?
      • 「レスポンスJSONが、データとして等価であること」→API がありそう
      • 「例外として、並列度の高い負荷で発生するステータスコード500のエラーとタイムアウトは失格扱いにせず、加点も減点もしない」→失敗で減点されないのは珍しい?
    • GitHub に private repo. を作って,チームメンバー間での共有準備
    • 設定の秘伝のタレをサクッとまとめる

当日

  • 開始が1時間遅れたので,camph.net のバグを直して時間を潰す
  • 3台のサーバーの構成を把握
  • 当日マニュアルを読む
    • /fetch へのアクセスで点数が加算されないのが気になる
    • 帯域制限が気になる
      • ベンチマーカーとの通信に使う帯域が100Mbps
      • ローカルの通信の帯域が500Mbps
  • アプリケーションのコードを Git で共有する
  • デフォルトがアプリケーションサーバー2台で,それらの間では設定を共有したい感じだったので設定用の Git リポジトリを作る
  • 最高のエディタである Vim を入れたり,パフォーマンス測定用のツール (dstat, htop, netdata など) を入れたりする
  • アクセスログを LTSV で取ったり,スロークエリログの設定を入れる
  • いい感じのデプロイスクリプトを書く
  • ベンチマークを走らせて,アクセスログやスロークエリの解析をする (ここまで大体1時間)
  • とりあえずアイコンが DB に載ってて異常に遅いので簡単に対処するとちょっと早くなる
    • アイコンを適当にファイルに書き出し
    • アイコンを特定のサーバーから返すようにする
      • メインAP・アイコン関係AP・DB の3台構成にする
      • メインAP のみに外部からのアクセスが来るようにする
  • 静的ファイルの配信が詰まっているので gzip_static で配信するようにする
  • N+1 を直し始める
  • 色々インデックスを貼ってみて,いい感じのインデックスを残す
  • アイコンの配信でグローバルIP側のインターフェースが詰まっているので,
    • Nginx で expires を設定する
    • アイコン用のサーバーでもアプリケーションを動かすようにする
  • 未読件数を Redis に載せて高速化する
  • DB サーバーのリソースが余ってるので,
    • DB サーバーでも Nginx を立てて静的ファイルを配る
    • 2台の AP サーバーに proxy_pass する
  • アイコンの proxy_cache を設定して,ローカルの通信を削減する
  • その他,秘伝のタレを入れたり…
  • 最後に,ログや netdata を止めて,いい感じのスコアが出るまでベンチマークを実行

気づき

良かったこと

  • チームメンバーを2人にした
    • 無理に3人目を入れなかったのは良かった
    • 信頼できる人とチームを組むことでコミュニケーションコストが低かった
  • ボトルネックをちゃんと測って向き合おうとした
    • ちゃんとログを取って,解析スクリプトにかませる仕組みを最初に仕込んだ
    • 解析結果をチームメンバーと一緒にきちんと考察した
  • アイコンのファイルを一つのサーバーに置いた
    • 無理にすべてのサーバーでファイルを共有しなかったのでバグりにくかった
    • proxy_cache をきちんと設定したので,サーバー間のアイコンファイルの通信は最初の1度で済んだ
  • 落ち着いていた
    • /fetch の気持ちとか time.sleep の気持ちとかを冷静に JS を読んだりして把握できた
    • コードを読んでいて気になった部分があっても,パフォーマンス上重要でないならとりあえず無視できた
    • ベンチマーカーとの間の貴重な帯域 100Mbps x 3 = 300Mbps を使い切れた

悪かったこと

  • アイコン配信の帯域がボトルネックになっているまま終わってしまった
    • Cache-Control: public を設定していればもう少しスコアが伸びたはず
    • ボトルネックともっとちゃんと向き合うべきだった
  • Redis とか Python で素の MySQL 叩くことが少ないので慣れていない
    • このあたりは事前にちゃんと練習すべき
  • ワーカー数とスレッド数の調整がうまくいかなかった
    • 感で調整した部分が多かったので,もう少し考えて設定したかった
    • Python インタプリタの気持ちをもう少し考えるべき (GIL とか)

最後に

  • 今年の問題は良問だった
    • サーバー複数台構成は面白い
    • 色々と改善する場所があった
  • PyCon JP で ISUCON の話とかをしてしまった手前,とりあえず (学生枠ですが) 本選に出場できて良かった
  • 運営の皆さま,ありがとうございました