サークルでISUCONを開催したので、参加した話

自分で開催したISUCONに自分で参加してきた

運営側視点の記事 -> TODO: 後で貼る

作業用リポジトリ

github.com

注意

問題セットは、@showwinさんのISHOCON1です。(@showwinさんありがとうございます!)

github.com

この記事はISHOCON1のネタバレを多大に含みますので、ご注意願います。

やったこと

  • 【5/1】
  • あーちゃんが始めてるのを見て、やるかーってなってインスタンスを立てる
  • gitに沈める
  • 初手、usersをメモリに持たせる
    • 正直これはいい手ではない
      • なんの計測もせず、特に理由なくメモリに載せる判断をしているから
      • ユーザーが増えたり減ったり、パスワードが変わったりしないことをまず確かめて、そこがボトルネックになってるってわかってからやるべき変更
    • 何回かこの問題をやったことがあり、その時の淡い記憶が残っていたからできた判断
  • 適当にindexを貼る
    • slowqueryを見ながら感覚で
      • この時点で貼ったindexは、後で調整が必要であればやるつもり
      • まずはDBがボトルネックになってる状態を最速で解消して、他のボトルネックを直したかった
  • SQLから SELECT * をなくす
    • SELECT * は基本的に絶対悪
      • 何を取りたいクエリなのかわからないのでチューニングしづらい
      • カラムが増えたり減ったりすると死ぬ
      • 無駄な通信や無駄なdisk accessが発生する
  • idをLIMIT OFFSETで取っているところを直す
    • productsは増えたり減ったりしないので、pageの番号からproduct_idは確定できる
  • 大体2万点くらい
  • 何故かここでunix domain socket化してる
    • 将来的には点数が上がるところではあるし、やっても損ではないが、このタイミングか?と言われると正直微妙
  • template.Mustを起動時にして、毎リクエストごとにテンプレートを見に行かないようにする
  • pprofを仕込む
    • この辺から、ちゃんと計測しようとしてる意思が見える
    • pprofは神ツール
  • pprofで、byteをruneに変換してるところが遅いと出たので、できるだけ変換しないようにSQL側で最低限だけ返すようにした
    • SQLで先に71文字に削ってからgoで70文字を超えているか判定することで、長い文字列をruneに変換することがなくなった
    • Goのruneに変換する処理は重いが、SQLで切るのはそこまで重くなさそうだった
  • 大体4万点くらい
  • N+1の解消
    • productごとにcommentを取ってきてくっつけていたが、最初にcommentの必要な分を一回のクエリで取ってくることで、50回もクエリをたたかないようにした
  • 11万点くらい
    • 10万点の壁を超えられて、この時点で1位だったので一旦終わり
    • 大体5時間くらい?
  • インスタンスを消した
    • 僕とあーちゃんは、始めるときにインスタンスを建てて、やりたいところまでやったら毎回インスタンスを消していた
      • まあ無駄に使わないときに建てておく理由もないし、費用削減にもなるし
  • 【5/3】
  • あーちゃんに負けてて悔しかったので、第二部始める
  • インスタンス建て直しから
  • Goのhtml/templateは遅いので、パッとググって出てきたquicktemplateに書き換え
  • 15万点くらい
  • productも増えたり減ったりしないのでメモリに持たせた
  • 18万点くらい
  • productのdescriptionも、70文字以上だったら切る処理が重かったのでメモリにのせた
  • workloadが40くらいが安定することに気づく
  • 20万点くらい
    • また一位に返り咲いたので、ここで終わり
    • インスタンスを消した
  • 【5/5】
  • あーちゃんに抜かれてたのはまあいいとして、Noiriに抜かれてたのはめちゃくちゃ悔しかったので、もうちょっと頑張ることにした
    • Noiriめちゃくちゃ強くなってて凄かった
      • もうちょい経験値が貯まれば最強になりそう
  • historyをメモリに持たせる
    • どんどんメモリに乗っていく・・・
  • 23万点くらい
  • commentをメモリに載せる
    • この時代に作られたISUCONの問題は、メモリに載せるのが正義な奴が多いですよね
      • 対策として、複数台構成や、メモリに載せにくい問題セットになったりしていく
  • 36万点くらい
  • commentもruneに変換してから長かったら切る、という動作が重かったので、先に切っておく
  • 41万点くらい
  • この時点で、DBから読み取りがなくなり、書き込みだけになった
    • indexを全て消して、INSERTに特化する
  • クエリはprepareを使うようにする
    • あらかじめクエリを先にDBに投げて、クエリに使う値だけ後で投げる手法
  • 42万点くらい
  • 一位になったので、満足してインスタンス消した
  • 【5/8】
  • あーちゃんに負けていた。それはいいとして、試してみたい手法を思いついたのでやってみる
  • pprofによると、session周りでかなり重そうだった
  • ginのsessionに、memstoreなるものがあることを発見
  • pprofでみる限り改善されてそうに見えるが、点数的には上がらなかった
  • ふて寝するためインスタンス消した
  • 【5/9】
  • quicktemplateでも遅いって出てたので、生成されたHTMLをキャッシュすることにした
    • 少しだけ点数が伸びた
  • 44万点くらい
  • 僅差で1位でフィニッシュした

f:id:Goryudyuma:20210510004624p:plain f:id:Goryudyuma:20210510004619p:plain

この後できること

もうやれることを全部やり切った感があって、特にない気がする。細かい改善を積み重ねれば10000点くらいあがるかもしれないが、そこまでいける気もしない。

そもそもベンチマーカーのCPU使用率が150%を超えていて、もうどうしようもない感が出ている。

感想

  • やり切ったので満足!
  • 開催して良かった
  • 強い後輩たちが育ってくれるといいなぁ。
  • また開催できたらいいな!
    • (次の運営、誰かしてくれないかなー?)