#ISUCON 2013に参加しました
ISUCON2013 に参加したやったこととか感想とか。
@w650、@nobu_ohtaとチームを組んでの参戦。
横浜会場の様子です #isucon pic.twitter.com/M7F9yac21o
— NAGATA Hiroaki (@handlename) 2013, 10月 5
DS置いてあるけど狩りに行ってたわけじゃないです。 あ、始まる前は狩りに行ってたけど始まってからは行ってないです。 さっきHR51になりました。
最終的な構成
perlアプリ + nginx + mysql + redis
memcachedを使っていると思ったら実は使ってなかった。
やったことを覚えている範囲で書いてみましょうか。
git
とりあえずサーバー上にgitリポジトリを作る。 各自このリポジトリからcloneして、変更を加えたらpushする、とういうやり方にした。 スコアが下がる変更を入れてしまった場合にもすぐに以前の状態に戻せて便利。
post-recieve hookをいじって、pushと同時にアプリの再起動をするようにしていたけど、 ベンチを走らせている時にうっかりpushして502が出る事故が何度かあったので 結局後半はhookをつかわなかった。
apache -> nginx
apacheは最近全く触っていなかったので、勝手のわかるnginxに置き換え。 もしかしてLuaを使って高速化できるんじゃないか? ということでわざわざopenrestyを入れなおしたけど、やっぱり使わなかった。
アクセスログの解析
nginxのアクセスログをtailしつつベンチマークを回して、 一度のベンチマークでリクエストされるURLをチェック。
$ cat access.log | perl -nE 's!/\d+!/__id__!g; say $_' | perl -nE '/"((:?GET|POST) \S+)/; say $1' | sort | uniq -c | sort -nr 3076 GET /js/jquery.min.js 3076 GET /js/bootstrap.min.js 3076 GET /css/bootstrap.min.css 3076 GET /css/bootstrap-responsive.min.css 2482 GET /memo/__id__ 2430 GET / 1150 GET /recent/__id__ 384 POST /signout 382 POST /signin 382 POST /memo 382 GET /signin 382 GET /mypage
集計結果を見て、
GET /memo/__id__
GET /
GET /recent/__id__
を重点的に攻めることに。
各テーブルのインデックス
WHERE句に指定されているのにインデックスが張られていないカラムにインデックスを追加。 ここは @nobu_ohta におまかせだったので追加でどこにはたのかは把握してない。
ORDER BY created_date -> ORDER BY id
created_dateとidの並び順が同じだったので、ORDER BYの対象をidに変更。 stringよりintの方がソートは速かったはず。
slow logの解析
my.conf の long_query_time=0.1
にして、
吐かれたslow logをpt-query-digestにかけてチェック。
GET /
と GET /recent/:page
で呼ばれるmemosを取ってくるクエリの、
SELECT * FROM memos WHERE ...
を
SELECT id FROM memos
と SELECT * FROM memos WHERE ID IN (...)
の
2回に分けることで多少は速くなった。
OFFSETがしんどそうだなーと思いつつもこれをなくすことはできなかった…。
アプリ周り
StarmanをStarletに変更。 worker数は変更なし。 静的ファイルはnginxから返す。 Markdown返還後のテキストをmemcachedにキャッシュ。 その他諸々をキャッシュ。 memosのcountはRedisのincrに置き換え。memosにinsertするたびにincr。 このあたりも @nobu_ohta と @w650 におまかせだったのであんまり知らない。
my.cnf
ほとんどいじってない。
query_cache_size
を0にしたのと、innodb_buffer_pool
を設定したくらい。
反省点とか
こうして書いてみると8時間あったのにあまり手を動かせていない。
インフラ担当だったのにアプリも弄りたくなって行ったり来たりしていた。 ボトルネック探しに専念していれば効率よくスコアを伸ばせたかも。
「memcachedみたいなもの」にはぜんぜん気づいてなかった。
最初から動いてるperlのアプリがどこで起動しているのかさっぱりだった。 探しまわって無駄な時間を使うことに…。
ベンチマークツールのworkloadを変更できることをすっかり忘れていた。 READMEには「スコアの集計はworkloadの値によらず〜」みたいな事が書いてあったのに、 スコア集計はworkloadを固定して行うから変えても効果はないよ、みたいな意味に勘違いしていた。 2とか3とかに変えていればもう少しマシなスコアになったのかも…。
トップのチームはスコア30000超えてますね。ぱねぇ
予選敗退と相成ったので、運営お手伝いに回ります。 本戦出場のみなさまがんばってくださいね!