handlename's blog

コード片など

#ISUCON 2013に参加しました

ISUCON2013 に参加したやったこととか感想とか。

@w650、@nobu_ohtaとチームを組んでの参戦。

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 memosSELECT * 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超えてますね。ぱねぇ

予選敗退と相成ったので、運営お手伝いに回ります。 本戦出場のみなさまがんばってくださいね!