isucon練習記 private-isu
ISUCON本を読みながらいろいろ試す
最初はAWSに環境構築するも、推奨構成だと課金額が1日半で1000円とかになったので断念
使わないときはEC2インスタンスを停止すべきだった
動作確認程度で良ければスペック落としても良いよね
スペックは2GB/3Coreをアプリとベンチで2台
packagesを無視するのかansibleが入らずansible-playbookで落ちてた
ansible入れて手動実行。cloud-configの意味無し
とりあえずベンチ回してみる
code:console
$ /home/isucon/private_isu.git/benchmarker/bin/benchmarker -u /home/isucon/private_isu.git/benchmarker/userdata -t ${ip}
{"pass":true,"score":0,"success":77,"fail":66,"messages":"リクエストがタイムアウトしました (GET /)","リクエストがタイムアウトしました (GET /@alyson)","リクエストがタイムアウトしました (GET /@beverly)","リクエストがタイムアウトしました (GET /@magdalena)","リクエストがタイムアウトしました (GET /@raquel)","リクエストがタイムアウトしました (GET /@sharlene)","リクエストがタイムアウトしました (GET /@wilma)"," リクエストがタイムアウトしました (GET /css/style.css)","リクエストがタイムアウトしました (GET /favicon.ico)","リクエストがタイムアウトしました (GET /image/10000.png)","リクエストがタイムアウトしました (GET /image/10002.png)","リクエストがタイムアウトしました (GET /image/7419.jpg)","リクエストがタイムアウトしました (GET /image/9006.jpg)","リクエストがタイムアウトしました (GET /js/main.js)","リクエストがタ イムアウトしました (GET /js/timeago.min.js)","リクエストがタイムアウトしました (POST /login)","リクエストがタイムアウトしました (POST /register)"} 落ちた
p.80 インデックス追加
ALTER TABLE comments ADD INDEX post_id_idx(post_id);
ベンチを回す。点数が出るようになった
{"pass":true,"score":3389,"success":2920,"fail":0,"messages":[]}
p.89 unicorn workerプロセスを4に
worker_processes 4
{"pass":true,"score":8570,"success":7611,"fail":0,"messages":[]}
p.135 インデックス追加
code:p135-1
mysql> EXPLAIN SELECT * FROM comments WHERE post_id = 100 ORDER BY created_at DESC LIMIT 3\G
(略)
Extra: Using filesort
code:sql
ALTER TABLE comments DROP INDEX post_id_idx, ADD INDEX post_id_idx (post_id, created_at);
code:p135-2
EXPLAIN SELECT * FROM comments WHERE post_id = 100 ORDER BY created_at DESC LIMIT 3\G
(略)
Extra: Backward index scan
インデックスにcreated_atを含めることでソートする必要がなくなった
Backward index scanは逆向きでインデックスを捜査した
code:sql
ALTER TABLE comments DROP INDEX post_id_idx, ADD INDEX post_id_idx(post_id,created_at DESC);
code:p135-3
mysql> EXPLAIN SELECT * FROM comments WHERE post_id = 100 ORDER BY created_at DESC LIMIT 3\G
(略)
Extra: NULL
インデックスを逆順にすると消えた
スコアはあまり変わらず
{"pass":true,"score":9573,"success":8387,"fail":0,"messages":[]}
p.145 DB設定
本の内容がGoで書かれていたので参考実装を manual.md を見て切り替える
{"pass":true,"score":9988,"success":8663,"fail":0,"messages":[]}
PREPARE ADMINはプリペアドステートメントというらしい
設定でオフにできる。少しスコアが上がる場合がある
{"pass":true,"score":11038,"success":9556,"fail":0,"messages":[]}
プロファイル結果からPREPARE ADMIN消えた
p.172 Nginx設定'
js,cssファイルをnginxから配信
スコア変わらず
{"pass":true,"score":10872,"success":9455,"fail":0,"messages":[]}
gzip有効化
スコア少し上昇?
{"pass":true,"score":11248,"success":9826,"fail":0,"messages":[]}
画像もnginxから配信
スコア変わらず
{"pass":true,"score":11138,"success":9697,"fail":0,"messages":[]}
このあたりで気分転換に一旦付録に移動
画像をファイルとして保存するように
POST → ローカルに保存、GET → Nginxから配信またはDBからローカルに保存
code:isucon.conf
location /image/ {
root /home/isucon/private_isu/webapp/public/;
expires 1d;
try_files $uri @app;
}
location @app {
internal;
}
try_filesはじめて知った
/image/が高速化
Mean 0.0498 → 0.0055
Total 186.881 → 158.017
スコアも伸びた
{"pass":true,"score":25965,"success":24579,"fail":0,"messages":[]}
makePostsのN+1改善1
/が平均そこそこ重くて回数が多いので、ここを改善
スロークエリは下記が重い
code:sql
SELECT id, user_id, body, mime, created_at FROM posts ORDER BY created_at DESC\G
getIndexは投稿全件を取得して、各投稿の詳細をさらに取得する(N+1)。実際は20件しか表示しない
単純にJOINしただけではまだ全件取得してしまっている
これ過去問でやってしまってそう、describe大事
インデックスを追加して全件見なくて良いように
ALTER TABLE posts ADD INDEX posts_order_idx (created_at DESC);
N+1倒す。スコア爆伸び
Mean 0.3214 → 0.1307
Total 575.037 → 247.743
{"pass":true,"score":52696,"success":50178,"fail":12,"messages":["リクエストがタイムアウトしました (GET /posts)"]}
謎タイムアウト
makePostsのN+1改善2
1はpostsとusersが1対1だったのでJOINで良かった
postsとcommentsは1対多なので取得対象が不定 → キャッシュを使ってみる
memcached がエラーを吐くのでここまで