こんにちは。フリーランスのエンジニアのあっとんです。
仕事が一段落したのもあってプチ夏休みという名の仕事が無い期間、ISUCON7 の予選問題をやったりしました。
それを改めてログにまとめる次第です。
結論から言えば、予選突破のボーダーの
21万点を越えられました。
ちなみに累計作業時間は58時間くらいで、最終スコアは
270957 でした。
あとリモートワークのお仕事を募集中(2018/09/13現在)です。
どうして ISUCON の問題を触ってみようと思ったのか
- Twitter でたまに見た単語で気になっていたので
- ミドルウェアをインストールする事はあってもガリガリにチューニングする経験が無かったので
- とりあえず数字で善し悪しが分かるので
自分レギュレーションと目標とか
- スコア的な目標は予選突破ボーダー(21万点くらい)
- とりあえず最初(ISUCON7予選)はブログとか見て良いのでノウハウを積む
- ノウハウを積んだ上で本戦問題を時間制限+解説見ずに解く
環境構築とベンチマーカを動かす
まずは環境構築から。
とりあえず GCP の上に 4core 8GB の instance を上げる。
初期スコアは5000点くらいだったと思います。
ベンチマークをかける側も 4core 8GB で環境構築。
なんとなくの知識で高速化をする
とりあえず知ってる範囲で適当に進めていく。
- nginx の proxy を経由せずに直接 puma で 80番を bind するように
- rackup する時に environment を production にする
- logger を無しにして log を disk に書かないようにする
- css と js を minify する
- yui-compressor なるものを使う
- $ yui-compressor main.css -o minimain.css # とか
- Validation に失敗するのでこの手は使えない
- gzip で圧縮してみる
- .gz を置いて配る
- そんなにスコアが変わんなかった
- N+1 を解決したいが SET IN ... に書き換えるのが面倒
- SELECT * の結果に対して first していた部分に LIMIT 1 を付ける
- メモリの上に DB の全データを載せる
- tmpfs + rsync で載せてしまう
- 19340 点になる。倍。
- mysql の log の WARN を取り除く
予測するな計測せよ
結局何が一番のネックなのかが分からないとどうしようもない。
ということで計測していく。
さてこれでどこがネックなのか探るか、と思ったら作成されたファイルが読めない。
結論から言えばファイルに書く前に Marshal.dump されているせいで Marshal.load しないと読めなかった。
Marshal.dump を JSON.dump に monkey patch して無理に plain text にして jq で読む。
しかしファイルが多すぎて(200個とか)まともに読めない。
profiler を使うのは諦めて top だけで行くというゴリ押しをする。
なお、初期の段階でベンチマークをかけると CPU を mysql が 55% 、puma が 35% くらい食っていて DB ネックだった。
参考文献を参照開始
11万あたりの伸び悩み
その後もチマチマと変更を加えるものの、12万点の壁は越えられず。
CPU使用率も合計100%にならなくなった。
気付くのに結構かかってしまったけれど、オチとしてはメモリ不足。
具体的には残り10k とかになっていた。
というわけでここからは複数台構成にする。
複数台構成
- まずは一番メモリを食っていたDBを別のサーバに移す。
- 次に複数台構成だと icon がどこに upload されるか分からない
- ので memcached で集中的に管理することに
- サーバ一台だと (score: 45464)
- かなり落ちた
- internal bandwidth 次第だけれど network access が発生しているので仕方がない
- nginx server を 2 台にする
- (score: 96002)
- 二倍になった。大変理想的。
- nginx を DB server にも立てる
- memcached の key に '/icons/' を prefix で置いてたのを修正
- あと namespace が必要なさそうだったので削る
- (score: 184209)
- 結構上がった。あと3万点。
- この辺で迷走することになる
lsyncd を使って画像の同期
解決すべき問題は icons を3台の間でどう整合性を取って返すか。
業務だったら S3 に置くなり CDN を使うのが良さそう。
しかし ISUCON なので、手元にあるサーバでどうにかする必要がある。
画像ファイル自体は1MB以下なのが保証されている。
なので書き込み時に memcached じゃなくて全サーバに書き込むことに。
そうすれば /icons を nginx が Cache-Control 付きで返してくれて良さそう。
(nfs で mount しても良かったのですが、結局 network access が発生するので早くならなそうだったので断念。)
(nfs の cache の config でどうにかなった可能性もゼロではないが……)
(rdiff-backup とか osync とか csync2 とか unison とか mirror とかあるがどれも古い)
サーバA は更新があったらサーバB に rsync。 B は C へ。 C は A へ。という形に。
これでファイルが upload されたら全サーバが共通のファイルを返せる。
結果、1台だけの時にスコアが 69770 に。3倍にできれば目標達成かな。
最終的な構成
3台 nginx にするより、2台 nginx + DB のがスコアが高かった。
最終的には score 270957 を達成したので脳内予選突破。
まとめ
- ISUCON7 の予選問題のスコアを 27 万点くらいまで上げました。
- 作業ノートによると58時間くらいかかっているらしい。
- これで夏休みの自由研究2018としましょうか。
参考