ISUCON8に出場して予選で散りました。

isucon.net

@kazeburoさんと@masartzさんとそたぶろるっつという名前のチームで一緒に出場しました。ありがとうございました!

結果

後半、少し追い上げるも予選突破ラインに遠く及ばず…。

fail地獄がつらかった。

やったこと

私は主にアプリケーションを見た。つらつらと。言語はNode.jsを選択しました。

  • 環境整備
    • lintツール導入(TypeScriptだったのでtslint入れた)
    • ts-nodeでのアプリ起動をやめてcompile後のjsを実行する
    • Node.jsのバージョンをv10.10.0へ変更
  • サーバ構成を変更
    • リクエストを受けるサーバにはh2oとMySQL、h2oはリクエストを残り2台にbalancingする
    • アプリサーバではpm2使ってCPUコア数分、Node.jsのクラスタを立てる
  • 無駄にsheetsテーブルを見てるところをハードコード
    • 1000件程度のデータだったがranknumカラムがわかればsheet_idがわかるし、ranksheet_idがわかればnumがわかるデータ構造になってたのでそこを参照したりJOINしてるところをつぶした
    • reportのところのJOINをつぶすのだけ時間無くてできなかった
      • SQL呼び出しが減るわけでなかったので後回しにしてしまった
  • getEventsでアプリでpublic_flgのfilterをかけてるものをflag見てSQLを変えるよう分岐
  • いくつかのgetEvent呼び出し部分を単一のSQLに変更
    • getEvent内はいろいろやっているが読んでみるとシンプルなSELECT文で置き換えられる場所がいくつかあった
  • ORDER BY RAND()をやめる
    • 予約されてない席でなく、予約してる席を全件取得するようにした(最大でも1000record)
      • SELECT sheet_id FROM reservations WHERE event_id = ? AND canceled_at IS NULL
      • これだと全ランク混ざるがrankがわかればsheet_idのrangeがわかるのでその範囲だけでループを回す
    • 予約してる席が分かれば予約されてない席がわかるのでそこからrandomで引っ張って処理した
      • 最初、randomじゃなくても行けないかなと思って試したけどだめだった
    • あとから「固定シーケンシャル番号を作って擬似ランダムにする」というアイディアが出て、頭を壁に打ち付けた

その他、チームメンバーには

  • INDEXの追加
  • getEventsのN+1撲滅
  • 残り座席数のtable化
  • SQL調整
  • その他環境整備やアプリレイヤー以外のチューニング

をひたすらやってもらってた

反省

  • 去年に引き続き凡ミスが多かった
    • ローカルでアプリ環境を作るという選択をしなかったので本番デバッグすることが多く、効率が悪かった
    • 他チームが「30分で作れなかったらやらない」という基準で取り組んで、作れたと言ってて時間で区切るのは賢いと思った
    • TypeScript実装だったので実装が堅牢だったかというと必要最低限の型付けしかなかったので思い切って最初20分くらい、コールドリーディング&型付けに投資もありかとおもった
      • 特にSQLの返り値周りはなんの値がどう加工されてるのか読み解くのに苦労した
    • やろうと思ってやらなかったがInspector立ち上げてデバッグするのもありだった
      • pm2立ち上げた後から設定入れるのが面倒でやらなかったがやるべきだった。判断ミス
  • 後半、ほとんど何もできなかった
    • 予約/キャンセルエンドポイントとずっとにらめっこしてたがどうすれば改善できるのかわからなかった
    • わからないならわからないで割り切って、きな臭いSQLを丁寧にチューニングしていくとかできることはあったはず
    • 正直、failの絶望感に打ちひしがれてる感が強かった(本戦出場チームもこのあたりは同じだったらしい)
  • pm2の使い方はもっと調べておくべきだった
    • inspector付きで立ち上げるとかloggingとか
    • このあたりは仕事で触る機会もある可能性あるしISUCON問題の復習で丁寧に触っておく

まとめ

仮にもハイトラフィックなアプリのBackendを1年半やっての敗北なので強い気持ちで1年間修行します。