ISUCON 9 予選に isucon_friends として参加し、予選総合3位でした。
久しぶりの本戦出場
ISUCON3 以来なので 6 大会ぶりですね。。。思えばずっと予選で負け続けてきたものです。
yosuke-furukawa.hatenablog.com
結果どうだったか
予選3位通過でした(棄権含む)。最終スコアは 27,470 ですね。 isucon.net
1位 nil 1 [1] 52,440 2位 にがり 1 [1] 36,270 3位 isucon_friends 3 [0] 27,470 ★ 4位 いんふらえんじにあー as Code 3 [0] 26,460 5位 ようするにメガネが大好きです 3 [0] 25,200
僕らよりもスコアが跳ねている、にもかかわらず、学生が1名でやっている、nil
と にがり
は本当にすごいと思います。
何をやったかまとめ
言語は Go でした。 (Node.js ではありません。)
- Index貼ったり、OR検索をUNIONに変えるなどでチューニング 2100点 => 2800点
- キャンペーン還元率を 0 => 1 に。 この時点では3300点前後になるも、ボトルネックがログインに移った。
- 3台構成にして、 nginx, app, DB にした。 この時点で 8800点程度、ただこの時点ではボトルネックはログインのまま。
- bcrypt 剥がして SHA256 に rehash することに。ベンチマークを何度も回してその都度 rehash された password の結果をdumpし、パスワードハッシュ部分だけ書き換えるように。ベンチマーク流すたびに 10000点から少しずつ伸びていくので楽しかった。この時点で14000点
- キャンペーン還元率を 1 => 2, 3, 4 と一気に変えていった。16000点に。
- /buy 内でAPI 呼び出ししてる所を並列処理化、また同時に /users/transactions.json 内で API 呼び出ししてるところを並列処理化。25000点に一気に伸びた。
- もう後は Lock wait 待ちが多くなったので、 N + 1 を改善しようとするも断念。Transaction Levelを REPEATABLE READ から READ UNCOMMITTED に変えてみたりして、悪あがき。 26000点になった。 (fail されないかビクビクしてた)
- 最後にすべてのログをオフにしてレギュレーション確認しながらベンチマークを実行、 27420点 が出たところで終了。
細かく効いたかは定かではないがやったこと
- nginxのエンドポイントを HTTP/2 にした
- Accept-Encoding が gzip だったら gzip 返すようにした (JSON のサイズが劇的に下がってた)
- キャンペーンテーブルをインメモリに持った
- 外部 API へのリクエストをする際に HTTP Agent の MaxIdleConns と MaxIdleConnsPerHost を拡張、1 ホスト 3000 コネクションまで持てるようにした。
やってみようと思いつつもできなかったこと
- N+1 の解消
- API のレスポンスが done status ならキャッシュする
この辺が思いついてはいたものの、残り時間で実装しきれず、断念した所です。 N+1 を IN 句に変えるだけでもやってもよかったかも。 この辺をやれていればもう少し伸びたかもしれません。
ISUCON9の感想
まずは予選突破できて本当に良かったです。若手や同僚にパフォーマンスの考え方を教えている身でありながら、本戦突破がそもそも1度しかできてなかったことを歯がゆく思ってました。
突破できて安心しました。
余談ですが、社内でR-ISUCONというISUCONを自分たち向けにカスタマイズした問題を作って会社全体で合宿しながら半年に一度のペースで会社全体で競っています。
今回、予選を突破している同僚が毎回社内ISUCONで一緒にしのぎを削ってるチームで、とても嬉しく思いました。
・theorem 3 [0] 12,360 ・ふんばり温泉チーム 3 [0] 12,060
R-ISUCONという社内ISUCONをやっていた結果、自分たち含めて3チームも予選を突破した事を本当に嬉しく思います。 このスタンプを社内でも使っていこうと思います。