ISUCON8に同僚&元同僚と「チーム人間性」として参加し、本戦5位となりました。
記事を書くまでがISUCONという言もあり、来年以降の参考になるかもしれないので何点か書き残しておきます。
この記事では自分がやったことだけを主に書きます。チームメイト目線での記事はこちら。
本戦で自分がやったこと
問題内容はこちら。
ロウソクチャートをキャッシュ
過去の時刻のロウソクチャートは変化しないので、一度取得したらメモリにキャッシュするようにした。スコアも多少上がり採用。
が、のちの別の最適化(tradeの非正規化)の導入時に、噛み合わせが悪かったのかfailするようになったため無効化。その後failしないようにできたものの、スコアが下がるようになっていたので結局最後まで無効化していた。
結果論だが、ここに掛けた工数は勿体なかったのかも。
N+1問題の解消
GET /info
や GET /orders
で、各orderに紐付くtradeを取得するというN+1問題があったのでそれを解消。ついでに、同じuserIdのUserをDBから引き直していたのも解消した。
ここで t.Price = tAmount.Int64
という痛恨のコピペミス。チームメイトの手まで煩わせてしまった...猛省。
どう考えても速くなるはずと思っていたが、スコアはほとんど上下せず。でも採用。今考えると、シェアボタン有効化前だったので頭打ちになっていたり、各userに紐付くorder数(N)が小さかったからかもしれない。
その他
-
HasTradeChanceByOrder
で、lowestとhighestは片方しか要らないので必要な方だけ取得するように- 効果見えなかったか何かで結局採用せず。ベンチの振れ幅だった可能性はあるかも
-
POST /orders
を小手先の変更で速くできないか試すもfailしたため不採用
次回に向けて
計測してボトルネックとなっている箇所から速くする戦略自体は正しいと思うが、「効果大きいかは分からないが遅くはならないはず」且つ「割とすぐ直せる」ような箇所はさっさと手を出してマージしても良いかも知れない。序盤のコードリーディングで細々した改善点に気付いたりするが、序盤にしっかり測ろうとしても他のボトルネックやベンチの振れ幅で改善効果が分かりにくかったり、終盤には忘れてたり手を出す余裕が無かったりするため。
今回だとこの辺など。
-
LIMIT 1
にしたら良さそうと10:40に気付いたのに、導入したのは14:18だった - 静的ファイル配信はボトルネックにならなかったため手を出さなかったが、やって損は無かったはず
予選で自分がやったこと
問題内容はこちら。
sheetをメモリで持つように
sheetは最初からDBに入っているが、更新されず大した量でもないのでメモリ上で引けるようにした。
getEvent
の高速化
「全席についてループし、予約が入ってないか各席で毎回DBから引く」ような元の実装を、「入っている予約達をDBから引き、予約が入ってない席にはデフォルト値を仕込む」ような実装に変更。
これは滅茶苦茶効果が大きかったのだが、実装当初は後述の罠により延々failしていた。
ロックの掛け方がおかしいのを修正
ここの順番が逆という罠。getEvent
と直接は関係無いのだが、ここを直さないと上記 getEvent
高速化が効かなかったため大変苦しかった。
テーブルでロックするように
終盤、デッドロック系でどうにもスコアが安定しなかったため採った策。多少遅くなってもスコア0になるよりマシという考えで、 SELECT FOR UPDATE
している箇所を LOCK TABLES
を使うように書き換えた。
安定を取ったせいで予選落ちしたら辛いなぁと逆にハラハラしていたが、結果的にベンチガチャに失敗したチームも多かったようなので良かったと思う。
最後に
運営の皆様ありがとうございました。実際素晴らしかったと思います。