ISUCON13に@pikachu、@ikura-hamu、@h1rono_kで「リアクティブ二子玉川~♪」として出場し、全体34位、学生チーム内では6位(多分)になりました。
チームメンバー(役割分担)
全員学士2年の3人チームで出場しました。みんなウェブ系に関わり始めたのが大学入ってからにしては、結構頑張ったのではないかなと思います。
例年であれば学生枠で本選出場できる順位ですが、今年は30位までしか賞品が無いので、惜しくも獲得できず悲しい。
pikachu
traPでISUCON講習会を開催したものです。記事はこちら ISUCON初心者向け講習会のテキストを作り、開催しました!
2回目の出場で、競技中の役割は「ひたすら改善に集中する」で、スコアを上げまくりました。最上位チームの研究をして対策をしていたかいもあり、結果的に34位のスコアまで上げることが出来ました。
データベースのチューニング(インデックスを貼ったり)をした後、サーバー3台のリソースを全部良い感じに使えるように3台構成にしたり、インメモリキャッシュでN+1を改善したりしました。
本当は最後の方にN+1を4箇所くらい直す修正をしたのですが、failして間に合わなかったのが悔いです。手数を増やせるようにさらに演習を積んで来年も挑みたいと思います。
ikura-hamu
初出場でした。事前準備ではツールの整備を行いました。チームメイトからの評判もそこそこよかったです。記事はこちら 【 #ISUCON 】 最近の若者は ssh しないらしいですよ 僕はアプリの実装をずっといじってたのでほとんどsshしませんでした。DNSをいじるのにはさすがにsshしてたはず。
競技中は主にアプリの改善を担当して、N+1をJOINしたりキャッシュしたりしました。アイコンに304を返すやつは最初のuser
テーブルにハッシュを持とうとしたらなぜか整合性チェックで怒られ、メモリに切り替えたら通りはしましたが、304では返されておらず不思議でした。プリントデバッグしようとしたのですがログが出てこず、おかしいなと思っていたら、アプリが違うサーバーに移ったのを忘れて別のサーバーのログを見ていました。結果ダブルクォーテーションがついているかどうかの違いだったのですが、修正したらむしろ点が下がり、時間も無かったので諦めました。後半はこればっかりしていて時間を食ってしまったので申し訳ないです。
h1rono
git奉行とデプロイ→ベンチマーク実行、スコアのtag付け、緊急時のバグ修正を担当しました。
PowerDNSのMySQLバックエンドを1台目から3台目のサーバーに分けようとしましたが、失敗しました。
改善記録
レポジトリ: https://github.com/reactive-futakotamagawa/isucon13
初動やる事まとめ: https://md.trap.jp/s/BYNELQi-7
- スコアのタグを打ってあるので、レポジトリから大体追えると思います。
- 以下の改善記録では、ブランチがバラバラで前の改善を取り込んでたり取り込んでなかったりするため、スコアが上がったり下がったりしているように見える点に注意です。
10:00 競技開始
- 初動でやることはISUCON13 当日用 初動まとめに細かく書いてあります。
10:09 3742点 初期スコア
10:18 3442点 の環境構築ツールにより環境構築が完了
- pprotein
- alp
- pprof
- fgprof
- slp
- pt-query-digest
- grafana
- CPUやメモリの使用量
- journalのログ
10:24 3527点 アクセスログとスローログの有効か、秘伝のタレの流し込み
- NaruseJun や 織時屋 の秘伝のタレを参考にしています。
11:14 3992点 LivestreamRankingのN+1修正
- statisticsが重かったので、明らかに無駄なクエリをたくさん叩いてるランキングをとりあえずJOINで1クエリにした。
- 全LiveStreamのidとスコアを取ってきてGoで順位を計算するように書いたが、よく考えたらRANKクエリとかを使った方が通信量減ってよかったのかもしれない。
11:23 8930点 上位クエリにINDEXを貼り、アプリのコネクション数を増やした
- スロークエリ上位のクエリを片っ端から精査した。上位6個位のクエリにindexを貼った。
- Intellij IDEAの機能でサーバーのDBに直接接続できるので、そこでクエリを叩きまくる。
- EXPLAIN → ADD INDEX → EXPLAIN で効果が確認できれば追加。
- 今回は毎回DBを初期化しているわけではなかったのでGoでクエリを毎回実行させた。
- DBとHTTPクライアントのコネクション数を増やした。アプリの秘伝のタレ。
11:41 10251点 さらにINDEXを追加し、InterpolateParamsをtrueに変更
11:51 12016点 TagModelのキャッシュ
- 書き出すのが面倒だったので、織時屋のtokiさんが作ったscを使ってキャッシュした。
12:16 12652点 2台構成
- DB(isupipe)をs2に分離した。
- s1: app + nginx + DB(isudns)
- s2: DB(isupipe)
- どちらのサーバーもCPUを使い切っていたので、もっと点数伸びると思ってた。
12:49 13418点 unix domain socket
- とりあえず通信が早くなってスコアが上がる奴。
競技上の不備でベンチマークが回せなくなり、ベンチマーク実行待ちの改善が溜まり始める......
13:36 11935点 prepared statement を使う
- 適切にprepared statementを使えばより早くなると思っていたが、スコアは下がった。
- ボトルネックがあるうちはInterpolateParams=Trueで十分なのかも...
13:37 15464点 UserRankingのN+1修正
- LiveStreamとほぼ同じだったので、コピペで済ませる。
14:00 11661点 getUserLivestreamsとgetReactionsを並列処理
- pprofで上位に来ていたので、N+1を並列処理にすれば速くなるかなと思った。
- 実際にはN回のクエリが瞬間的にDBに叩かれ、500が帰るようになっていた。
- しばらくスコアが上がるが、このままだとfailするので3時間後に戻すことになる。
14:08 16565点 moderateのN+1修正
- pprof上位だったので改善。
14:30 17196点 INDEXをさらに追加で貼った
reservation_slots
のインデックスが効いていなかったので、追加でend_at
に貼った。
15:51 53054点 3台構成(s1:dnsDB s2:DB s3:アプリ)
- INDEXを貼ってからs2のDB(isupipe)に余裕ができ、s1が爆発していたので、s3のリソースを使いたいと思った。
- DB(isudns)を変更する方法が分からなかったので、アプリをs3に飛ばすことにした。
- s1: nginx + DB(isudns)
- s2: DB(isupipe)
- s3: app
- 結果として、どのサーバーもCPUを90%以上使うかなり良いリソース配分ができた。
16:22 49549点 jsonをsonicに
- jsonのエンコードがめちゃ速いGoのライブラリ。
- まだまだボトルネックが沢山ある段階ではあんまり効果がなさそう。
16:49 31898点 不正に500を返していたのを修正
- getUserLivestreamsとgetReactionsを並列処理にしたやつをrevert。
- スコアがめっちゃ下がって泣いちゃった。
- ベンチマークはpassするんだけど、エラーが沢山出るしその後の審査でfailすると思った。
17:11 55263点 cacheUser
- pprof上位、scでキャッシュ。同じように改善できる箇所があったが、時間が足りず断念。
17:23 39755点 アイコンでハッシュが一致したら304を返す
- ヘッダーがダブルクォーテーションに囲まれていることに気づかず、ずっと困ってた。
- この時間に気づいて直したが、点が下がったのであきらめた。ちゃんと計測結果を見てないが、たぶんボトルネックが変わったんだと思う。
- ハッシュ値自体のキャッシュは入っていて、毎回は計算していないのでその分はちょっと早くなっているはず。
17:28 fail点 cacheTheme cacheLivestreamTags
- 複数個所のN+1を改善するために、急ぎでキャッシュしたが、failしたため断念。