$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

ISUCON8予選を突破した

id:hitode909id:takuya-aとチーム「ディメンジョナルハイソサイエティぬれねずみ」としてISUCON8に参加し、40867点で本戦に行けることになった。ISUCON初参加でいろいろ不慣れではあったが、なんとか本戦に行けて嬉しい!

サーバ複数台構成かつボトルネックになる箇所が結構面白いところが多く、非常に楽しめました。運営の皆様ありがとうございました。

振り返りとして、チームでやったこと・良かった進め方をまとめてみる。

チームでやったこと

開始直後は役割分担して作業していった。言語は勉強がてらgolangにしようと思ったこともあったが、せっかくなら勝ちたいし慣れてるperlにした。

  • shiba_yu36: 鍵置いたりコードのバックアップしたりなどといったオペレーション周り
  • 他二人: アプリケーションの挙動を確認し、作戦を立ててもらう


以下が最初のオペレーションでやっていたこと。


作戦会議の結果、まずはget_event周りのN+1クエリをなんとかする、またサーバ構成はDBがボトルネックっぽいし普通にapp二つとdb一つで良さそうということになった。

  • get_eventのN+1クエリ直す diff
  • サーバ構成を変える。DBボトルネック感あったので、app2台、DB1台に。isucon01をdb、isucon02をapp、isucon03をnginx + appにし、ベンチは03に向ける。
    • diff1
    • diff2
    • ここでGRANTの設定がおかしくて他サーバからDBにアクセス出来なかったので、init-user.shを参考にGRANTをした
    • /initializeがDBサーバと同居な前提だったため、これだけisucon01に固定で行くように。今から考えると、これはinit.sh周りを修正するだけで良さそうだった diff


さらにpt-query-digestsで集計して発見した遅いクエリを調整したり、sheetsのメモリキャッシュをしたりした。

  • N+1クエリ直した後のクエリにインデックス効かせるように diff
  • ORDER BY RANDやめる -> diff
  • reservationsのuser_idにインデックス -> diff
  • sheetsをメモリキャッシュ -> diff


このあたりでISEによって負荷レベルが上がらないという事態に遭遇する。エラーログを見ているとデッドロックが原因に見えた。そこで出来る限りロックを取らなくてすむようにFOR UPDATEいらないところは外してはと会話した。特に/api/events/{id}/sheets/{rank}/{num}/reservationでのロック範囲を最小限にするためにクエリを二回に分けてはどうかというid:hitode909のアイデアが良くて、これによってスコアが安定した気がする。


ただFOR UPDATEを外すというのをやったことにより、全体レポート生成(/admin/api/reports/sales)が同時に動くことが多くなり、その結果アプリケーションプロセスがOOM Killerで殺されるということが起こってしまった。これは辛いけどFOR UPDATEでロックは取りたくないねということでMySQLのGET_LOCKを使って並列度を下げてみることに( diff )。これによりOOM Killerに殺されることがなくなった。

/admin/api/reports/salesがメモリを異常に食ってしまう問題があったので、その修正に取り掛かる。アプリでソートをしているのをやめてみたり、オブジェクトを作らないようにしたり、文字列連結を少なくしたり、最初に領域確保してみたりということをしてみたが、あまりうまく行かなかった。


このあたりで残り30分くらいとなったので、ログ周りをoffにして、再起動試験をした。ここでfinish。うまくいくと40000ちょっとくらいになっていたので、行けるか行けないか微妙なところだなとなっていた。


終結果は40867点。両日3チームを除いた上位12チームに入っていたので本戦に行けることになった。

良かった進め方

  • 開始前に出前で寿司とったのが良かった。途中で寿司を食べながら一旦落ち着いて作戦会議できて、次の対策が思いつくなどの出来事があった
  • 開始後やることまとめておいたのが良かった。
    • f:id:shiba_yu36:20180917011739p:plain
  • rsyncデプロイにしたのはかなり良かった。git commitしなくてもデプロイ出来て素早さが増した
  • 1時間くらいアプリケーションを観察しながら、アイデアリストをホワイトボードに書いていき、いろいろ出揃った後に良さそうなものをピックアップして進められた。結果、最初に効果的な対策を打てた
  • ベンチマーク結果のログをちゃんと読み込むことで、負荷レベル上げられない理由から潰すことができた
  • 3並列でボトルネック解消ってそこまで出来ないと判断し、コード書くのは2並列にして、片方はペアプロするとした。ペアプロすると変なハマり方を減らせ、高速化していたので良かった
  • 15:00くらいに一回再起動試験をしてみたことが良かった。やってみるとisucon01以外のサーバでアプリケーションがenableされてなく、再起動するとプロセスが立ち上がらないということがわかった。もし終了直前だった慌てて原因が見つけられたか分からない。

最後に

改めて運営の方、非常に楽しい問題を作ってもらってありがとうございました。これまでISUCON出てなかったのもったいなかった、今後は絶対毎回出ようと思えるほど楽しかったです。本戦も頑張って優勝したい。