ISUCON9予選、2日目5位で通過しました

今年に入って開発する時間どころかこういった記事を書く時間すらも圧迫されているため、今回の記録は手短に雑多にやったことを列挙するに止めようかと思います。

ちなみに今年もチーム.datでいつものメンバーで出陣でした。担当としては、@kani_bがインフラなど足回り整備とチューニング、@takatoshimaedaがファシリ、戦略整備、Go周りの改善、自分がRedisで大手術、という感じでした。オンメモリ化、毎年やっててお家芸化してます。

今年も問題が非常に良くできており、簡単にはDeadlockが外せなかったり、また毎年やってしまうパスワードハッシュ計算外し、などもレギュレーションで潰されていました。またあまり活用はできなかったのですが、実際のアクセス傾向に応じたチューニングが奏功するのではないかなという雰囲気を漂わせているレギュレーションも確認できておりワクワクしながら取り組みました。

前日の晩に海外出張から戻ったばかりだったので準備は全くせず、ぶつけ本番で取り組みました。自分が担当した改善は以下のような内容になっています。

  • 初手でRedisの活用に踏み切る。シングルスレッドであるため、ある程度順序の整合が期待できるためtransaction_evidencesとshippingsテーブルの2つを一つのレコードとして扱いRedisに格納。
  • インクリメンタルなID採番についてはredisのincrコマンドを活用。
  • フラグの状態を整理し、transaction_evidences + shippingsの存在有無とそのフラグ関係を整理すればitemsテーブルの確認をある程度スキップできる箇所があると分かったため、全力でクエリを排除。
  • 上記の結果でpostShip, postDone, postCompleteについては、MySQL叩かず返せるようにした。
  • usersのnum_sell_itemsとlast_bumpもRedisにそれぞれ別なキー構成で記録するように変更。
  • redisの初期データはMySQLの初期データをtsvでdumpしておき、それをgoで読んでredisに投入する動作をPOST /initializeで実装。
  • 最終的にdbx.MustBegin()を3箇所以外削除。またその中身でもできる限りクエリを排除。
  • トランザクション中に存在した外部APIリクエストをsync.WaitGroupとGoroutineでいい感じに並列化。
  • (2019/09/10追記)GET /users/transactions.jsonの外部APIリクエストを削除し、Redis上のshippings.statusに相当するフラグを利用するように変更。

おおよそこんな感じでほか二人の施策も組み合わせ最終的なスコアは15660となんとか本選参加ラインに到達しました。

正直、現場離れて久しく実装が遅くなったなという気持ちが強いです、実際終わった直後は完全なお通夜モードでした。

本選では自信持って回答提出できるようにしたいですね…

最後に運営の皆さん、予選では最高に楽しい問題をありがとうございました。本選もよろしくお願いいたします。

正座エンジニア。DMM CTO, GunosyおよびLayerX Technical Advisor。早く電脳化させてください。ここには雑に考えた個人的な諸々を投げ込む。

正座エンジニア。DMM CTO, GunosyおよびLayerX Technical Advisor。早く電脳化させてください。ここには雑に考えた個人的な諸々を投げ込む。