第4回ISUCON予選にチーム「ご注文はPHPですか?」で参戦して1日目暫定10位になりましたがPHP使ってません
いい感じにパフォーマンスチューニングするコンテスト第4回ISUCONに参戦しました。まだ現時点で本戦に進めるのかわからないのですが、1日目で暫定10位になりました。
PHPでも十分に戦える!と思った方、ごめんなさい。Go言語使いました。
チーム紹介
- チーム名
- ご注文はPHPですか?
- チーム略称
- ごちぺち
- 予選スコア
- 44000〜45000ぐらい(暫定)
Go言語の勉強について
Go言語の経験はほとんど無く、9/18からA Tour of Goを始めた程度の素人。
9/20あたりから前回のISUCON3予選のAMIに含まれてるGo実装でチューニング実践してみた程度。三人ともISUCON出場経験がはあったのでチューニングはなんとかなりました。ISUCON3予選問題のチューニング結果は50000ぐらい。Go言語つええええ。
ISUCON3の予選問題はGo言語の勉強に最適ですよ奥さん。
今回の予選の対応方法
基本的にnginxのアクセスログとにらめっこです。
アクセスログに応答時間を出力するようにして、リクエストURIごとのトータル時間、アクセス回数、平均応答時間を算出する簡単なスクリプトを用意。その数字をみて、どのリクエストを改善すべきかを決定していきました。
いきなりソースを見たり、topやdstatなどでボトルネックを調べたりしたくなるんだけどもそこはグッと抑える。これは過去にISUCONに出た経験から導き出されたやり方でした。
ソースの編集について
幸い全員Vim使いで、ターミナル上で編集することに抵抗がないので、3人とも1台のインスタンスにSSH接続、役割分担しながらプログラムや設定などを書き換えていく感じでした。
BitBucket上のgitにリポジトリを作りましたが、そこからデプロイ&継続的インテグレーションの類は使ってません。サーバ上で編集したものを同じユーザ名でcommit&pushした程度です。
また、リポジトリを一応用意しましたが、綺麗に保つ努力はしませんでした。時間がもったいないから。main.go.hogeファイルとか平気で作ってました。短時間決戦なので気にしない。
どんな実装になったか
ミドルウェアはGoに変えた以外殆ど変わってません。nginx+Go+MySQLです。NginxとMySQLのバージョンアップもしませんでした。
できるだけ前の方で返すべく以下のような実装にしました。
- スタイルシートや画像ファイルなどの静的ファイルはnginxから返す
- ログイン失敗でbanされたIP/ユーザをチェックするためにlogin_logをSELECTしている部分は、ログイン失敗した回数をGo上でカウント、banされたリストもGo言語上で保持してMySQLを参照しない*2
- usersテーブルは初回のデータ投入以降増えないので、初回に全部Go実装上にキャッシュしてGoで返す
- 最終ログイン日時もユーザ毎にGo上で記録しておき、Go上で返す
- トップページは出力パターンが4パターンしかないので、4パターンの静的HTMLファイルを生成しておき、nginxでCookieの値を見てrewriteして静的ファイルを返す
それぞれの修正を適用するたびにアクセスログの応答時間を見て遅いリクエストを改善していく感じですね。
結果としてこのような対策になったので、今回MySQLのチューニングは殆どやってません。my.cnfの設定も大した設定は追加してないし、インデックスも結果的には何も追加しませんでした。
なお、プログラム以外の具体的な変更内容はnetmarkjp先生がブログに詳しくかかれているのでそちらをご参照ください。
便利情報
いくつかピックアップ
BitBucketのプライベートなgitリポジトリと連携できるCIはWerckerが便利
wercker、便利ですよ!今回使ってないけど。boxにwercker/golangを使えばGo1.3系をにも対応してます。
mysqltuner.plが便利
MySQLのざっとしたチューニングはこれを少し参考にしてます。
curl http://mysqltuner.pl > mysqltuner.pl
perl mysqltuner.pl
でも今回は殆ど使わなかった。
iotopコマンドが便利
disk ioを発生させているプロセスが何かわかります。
yum install -y iotop iotop -o
dstatのオプションは-tlamp -N loが便利
今回は1台構成でloしか使わないので-N loをつけると便利です。
yum install -y dstat dstat -tlamp -N lo
loの通信量が多くなれば、おそらくたくさん捌けてるんだな(スコアがあがるかもな)と判断できます。
Goのつらかったこと
いくつかピックアップ
経験が浅い
基礎的なことを把握してなかった。例えばinit()ってどこでどう呼ばれるのか知らなかった。
まとめ
よく言われる「推測するな、計測せよ」ですね。
dstatやtopを見てると計測してる気になるんですが、計測すべきはスコアに直結する応答時間でした、って感じです。