こんにちは @sonots です。 チーム Miami として同僚の @niku4i 氏、@Spring_MT 氏とISUCON2013 に参戦してきました。 perl の会社に所属していながら、ruby で出る人いない?と声をかけて三人集まったのがすでに奇跡でした。ありがとうございます。
結果は、ギリギリ本選出場のスコアということで、基本的なことだけやってブレークスルーは起こせず終わってしまったかなー、という感じです。 他の参加者にはあんまり参考にはならないと思いますが、将来の自分のためにも何をやったかを残しておきます。
事前準備
1週間ぐらい前から isucon3_cheatsheet という private github レポジトリを作って、メンバーで共有した。 チートシートなので基礎的な所もとにかく全部あげて、当日コピペで作業できるように準備しておいた。
チームメンバーの技術レベルがあんまりわかってなかったりもするけど、 最低限このチートシートの内容は共通認識であるものとして話を進められるようになるので、 コミュニケーションの土台としても良かったかなと思っている。
前日
cheatsheet 作成業に勤しんでた。ここではじめて varnish 触った。
早く寝ようと決めていたのに、気が高まってあまり眠れなかった。コンビニで聞いただけのきゃりーぱみゅぱみゅ - インベーダーインベーダー が頭の中でずっとリフレインしてた。遠足前の小学生状態。
当日やったこと
10:00
- あれ、@Spring_MT さん来ないなー、と思っていたら 9:45分頃に「今家出ましたー」と D が来たので、うおー、と思ってた。
- 時間になったので早速マシン起動。結構待つなー遅いなー、とぼうっとしてた。すでに眠かった。RedBull 飲んだ。
- よし、起動したぞ!と思ったけど、22番ポートでつながらない。ssh できない。なんでや!とかやってた。この頃にはAWS慣れてる @Spring_MT さんが到着しててセキュリティグループじゃね?この辺のはず、とか教えてくれて入れた。早いな、と思ったらタクシーで来たとのこと。
- で、dstat 入れて前もって shebang おかしい問題直しておいたり、tmux いれたり、みんなの ssh 公開鍵登録して入れるようにとか初期設定的なことをしたり、まず一度ベンチが通ることを確認したりしてた。
- なんかもうこの辺で 10:40 とかになってた気がする。
10:40
- チューニングポイントを見極めるためにもまず MySQL のスロークエリログを吐くようにしないと、ということで前もって用意してたチートシートの my.cnf コピペしてログ出すように。
- しようと思ったけど、MySQL のバージョンが 5.6 で「うわー、5.6 実は触った事ねーわ」、とか思ったけど、ぐぐったらすぐ /usr/my.cnf なことに気づいたし、5.6 への my.cnf の移植は近所の(ひ)の人のメモ がヒットしたのでそれを参考に対応した。あまりハマらずにすみ感謝。hirose31++
- でも、スロークエリは全然出てこなかったので、
log-queries-not-using-indexes
でインデックス使ってないクエリをログに出すようにしてmysqldumpslow
でカウントしてどこにインデックス貼ればいいか把握 - インデックス貼るのとかはベンチスクリプトに初期化スクリプト指定するんだっけ?とかレギューレション確認して初期化スクリプト作ってインデックス貼るようにしてた。
- この間チームの二人はアプリコードを読んでいた、と思う。
11:40
- ここから情報共有してもらってアプリ動作確認したりアプリコードちょっと読んだ。
- @Spring_MT さんが rack-mini-profiler とか newrelic とか仕込んでプロファイリングできるようにしておいてくれたので、その結果を見てちょっとだけ相談した。
- 上位チームはこの辺もっとしっかりやってるやってたっぽいので反省
12:20
- アプリの改変はまかせて、とりあえずチートシート消化しとこう、と思って unicorn に GC 切る設定追加したり、nginx 前段において静的ファイル配信する構成をコピペして作った。
- この時点では 3084.4 点
12:30
- やはりアプリの改変はまかせて、自分は引き続きチートシート消化しようと varnish の導入をしてた。
- ただログインユーザー名が表示されるアプリなので、そこにチェック入ったら FAIL するだろうな、なにか varnish で対応する方法探さないといけないな、とは思いながらやってた。
- けど、POST が 400 になってめっちゃ FAIL した。GET ならわかるけど、なんでキャッシュしてない POST が FAIL するんだ?
- ということで default.vcl 見直ししたり、アプリのコードのぞいてみてたりしたら、CSRF 対策のコードで
halt 400
入ってるのを発見。後ろめたい気持ちを持ちつつ、とりあえずこれをまるっとコメントアウトして試してみたら POST が通った。 - けど、結局 GET は FAIL するわけで、そこに対して対策を見つけられず断念。「めっちゃ時間無駄したー、@ijin さんなら何かやり方知ってるんだろうけど varnish 力が足りない」とか思ってた。※ やっぱり varnish つかって 20000 点台出したようですね。varnish 力が足りない orz ISUCON3の予選を通過した(はず) - @ijin
他の二人はアプリの改修やってた。そちらについての記事は二人に任せよう。この時点のスコアがこんなかんじだったので、提出してないけど、6位ぐらいか、、、、と思ってた。
1位 : 9781.2
5位 : 4664.9
10位 : 3731.9
Result: SUCCESS
RawScore: 4567.1
Fails: 0
Score: 4567.1
14:00
この辺から意気消沈しながら自分もアプリ改修に加わった。
- ログインユーザの username を SELECT してたのを session に保存してそこから取るようにしたり、
- url_for メソッドで毎回 URL 組み立ててたのでキャッシュするようにしたり、
- newer, older のコードのあたりをなんとかしようと奮闘してたりした
そこそこスコアあがったけど、ブレークスルーってかんじじゃなかった。
二人が作業してた
- total を SELECT COUNT(*) せずに memcached (memcached じゃなかったの最後まで気づきませんでした)にいれて incr させたり
- 外部プロセスフォークして markdown 展開してたのを redcarpet 使って ruby 内部で展開するように
の対応で大分スコアあがった。
あとは newrelic のプロファイリングを見る限りネックになっているのが /recent/:page だけだったので、ここをなんとかしようと皆で取り組んでとかやってたらいつの間にか 17:15 とかなってた。ここ結局終わらなかった。
17:15
- ここで自分が前もって考えておいた MySQL のデータを tmpfs に突っ込む案を実行。レギュレーションの「サーバの設定およびデータ構造は任意のタイミングでのサーバ再起動に耐えること」に引っかかるかと最初は思ったけど、シャットダウン時に tmpfs からディスクに rsync しておいて、起動時にディスクから tmpfs に rsync すればいいってことだよね?と考えてたのでやってみた。※これ大丈夫ですよね?ドキドキ
- これで 1000 ぐらいあがった。「1000 か・・・まぁそんなもんか・・・」と思ったけど、たぶんこれなかったら残れてなかった。
17:30
- あとは、プロファイラとかログ吐き出しをオフって、
- unicorn worker の数とか nginx worker の調節とか mysql のパラメータ調節やりながら、ベンチスクリプトの --workload の値を調節してスコアあげてフィニッシュした。
最終スコアは以下のとおり
Result: SUCCESS
RawScore: 8756.6
Fails: 3
Score: 8756.6
「はー、10位入れなかったわー」とか思ってたけど、最後に結果みたらギリギリ予選通ってた。
良かった点
@Spring_MT さんが「去年の反省を生かした」と言っていたけど、最初のほうに newrelic、rack-mini-profiler といったプロファイラを仕込んで計測できるようにしておいてくれたのは良かった。これをやっていなかったら、効果のないところに注力してしまったり無駄なことをしてしまう所だった。Spring_MT++
改善点
今回は問題を見つけたら直して、問題を見つけたら直して、という進め方をしたけれど、 上位チームのブログを見てると、各々コードを読んで改善ポイントを見つける時間と、それを共有して戦略を錬る時間を充分にとってから、作業に着手していたようなので、そのやり方のほうが良かったのかなぁと思った。次はそうしてみたい。
あとは普通に瞬発力を鍛えておく。
おわりに
というかんじで、なんとか本戦に生き残りましたが、RubyConf 2013 と日程がかぶっていてすでに飛行機とかホテルの手配をしてしまっているので Miami に行くことになっているというオチです。
誰か代打をお願いします!!!!代打とかアリなんですかね?T T