isucon

ISUCON6予選参加記

More than 1 year has passed since last update.

会社の同僚(J_ogawa,hama_du)とチーム「週5労働撲滅委員会」で参加した。


背景

常日頃J_ogawaが週5労働は体に悪いと力説していて、そのためには相応の開発スキルや生産性の高さが必要なので、チーム名を「週5労働撲滅委員会」とした。(命名は私)

業務ではRuby/RailsなのでRubyで参加することに。


練習1 pixivの社内ISUCON

各自で予習する。普段はRailsを使っていて、Sinatraは未経験なのでまずそこから。

NginxやMySQLの設定、ローカル環境で動かす、indexを貼るなど、基本的なところのみやってみた。

Slackを使い始める。


練習2 ISUCON4予選

実践的な練習ということで、部屋を借りて4時間ほどやる。なお部屋はSpaceeで探した。(安くて良かったけど、レビューを読むとWifiが使えない部屋も多いようなので、確認したほうがよい)

各自で環境構築や、重そうなところの共有など。

rack-lineprofで解析、Redisでキャッシュするなど、ISUCONでよくあるアプローチをやってみた。

refererがないときはNginxで静的ページを返せば爆速になりそうだが、そこまで至らず。


練習3 ISUCON5予選

同じ部屋が予約できなかったので、会社でやることに。

ちょうどこちらの記事があがっていて、Azureだしこれに挑戦。

isucon5 予選の復習を Azure 上でやってみる(1)

当日はUbuntu 15.04だったようだ。最初にUbuntu 14.04で試したらsystemdの仕様が違っていて起動スクリプトが使えなかった。openjdk-8も非公式だったり。

Ubuntu 16.04では大丈夫だった。

当日と同じような感じで進められるように練習した。

githubのリポジトリで、個人でブランチを作って各自で適宜デプロイいつつ、いいものはmasterにマージする、という感じ。

デプロイはrsyncでローカルディレクトリをコピー。

ベンチでUnicorn直接だといけるけど、Nginxを通すと「リダイレクト先が / でなければなりませんが http~ でしした」というエラーが出てNginx経由のベンチができず。

#TARGET=IP_ADDRESS:80

TARGET=IP_ADDRESS:8080
jq '.[0]' < ../webapp/script/testsets/testsets.json | gradle run -Pargs="net.isucon.isucon5q.bench.scenario.Isucon5Qualification $TARGET"

のように切り替えていたのだけど、あとでわかったが、Nginx経由かつポート番号を指定するとだめだったらしい。

userを丸ごとキャッシュした。最初(クラスのメンバ変数ではなく)インスタンスのメンバ変数に入れていたせいで、アクセス毎に全ユーザを読み込んでいて実は遅くなってたとか、いろいろなバグをエンジョイする。

帰宅後、こちらを読んで一通り試す。

ISUCON5 予選問題の解説と講評

rack-lineprof、ログの取り方、Nginxの設定、kataribeの使い方などを復習した。

1000件取得してから友達かどうかでフィルタして10件取得するのと、relationをjoinして10件取ってくるのだと結果が違わないか? とか、push型(ユーザー毎に友達の日記ID用のテーブルを用意して、自分が日記を書いたときにそこに配信するやりかた)のときに、友達を追加したら過去のぶんにも配信しないといけないのでは、などコーナーケースを考えてみたり。(今回のベンチマーカーはそこまでチェックしていないっぽい)

予選突破ラインは13898点だったらしいが、解説記事の手法なども取り入れたけどAzure Basic A3 (4 コア、7 GB メモリ) だと7000点くらいしかいかなかった。やりかたがまずいのか、GCEの性能が高いのか?


その他

UnicornをPassenger(Raptor)に切り替えたら速くなるのか、調べたり試したりしたが、全体に与える影響は軽微なようなので、やらなくて良さそうだった。

Why is FastCGI /w Nginx so much faster than Apache /w mod_php?

速さに違いが出るのが謎なときはシステムコールの呼び出し回数を測ってみるといいかも、みたいな記事を読んだりした。

一応C++でもいけそうか試した。

Writing Hello World in FCGI with C++

このページのFCGIのサンプルはとてもわかりやすく、簡単に試せた。ただ今回はRubyでチーム戦をするというのと、MySQLやRedisにアクセスするコードまでは書かなかったので、使わなかった。


当日

10時

初期設定はPerlでスコアは3283。Rubyに切り替えたら0になった。

Nginxでcss,img,js,favicon.icoを配信するようにした。

11時

isutarをisudaにマージしてdeployする。がホームディレクトリを全部消してしまいインスタンスを作り直す。ちょっと焦る。

クア・アイナの配達を頼んで気持ちを盛り上げる。

12時

keyword_lengthをカラム化したり、インデックスを貼ったりしてスコアが4000くらいを記録。

htmlifyが一番重そうなので、キャッシュするのと、処理の中身を軽くする方法を模索する。

13時

キーワード一覧をRedisにキャッシュするが、いくつかのページにキーワードが含まれていないと言われ、FAIL

14時

htmlifyの結果をキャッシュする。キーワードの更新(追加または削除)を記録するテーブルを用意して、キャッシュの作成時間よりもあとに更新されたキーワードがdescriptionに含まれていたときだけhtmlを再生成するようにした。スコアが10000を超える。

16時

キーワードの一覧をviewで一回だけ取得するようにした。スコアが30000を超える。

17時

ハッシュ化したキーワードをキャッシュしてみたが、FAIL

17:59

masterブランチに戻してqueueに投入して終了。18時ちょうどに見えなくなり、最終スコアは不明。33000くらい?


感想

事前に練習したおかげで、共同作業はおおむねうまくいったと思う。

VMのインスタンスを作り直す際、運営の方のレスが早くてとても助かった。(ストレージがacceptedから進まないので質問したが、結局待つだけでよかった。まっさらから作ると15分くらい必要だった)

CSSのcontent-typeがtext/plainでChromeで見たらプレーンになっていて、それを直したりしたが、ベンチマークには関係ないので無駄な時間を使ってしまった。午前中の時間の使い方はあまりよくなかった。

キャッシュのバグがつぶせなくて先に進めず、スコアが出なかったが、基本方針は間違っていなかったのかなと思う。くやしいのであとで復習する。

週5労働を撲滅する日は遠い。

とても面白かったので、運営の方々とチームメンバーに感謝!

また来年も出たい!