$ cd ~/minisucon2020/webapp/ruby$ bundle exec rackup
Ruby 製のマークダウンのメモ&コメントアプリケーション
マニュアルをしっかり読む
「ログを仕込む」を多用してひたすら計測
#
GitHub にレポジトリを作る$ ssh-keygen -t ed25519$ cat ~/.ssh/id_ed25519.pub
$ cd ~/minisucon2020$ git init$ git add .$ git commit -m "Init repository"$ git remote add origin git@github.com:hi120ki/minisucon2020.git$ git push -u origin master
とりあえず全部アップする
/etc/ファイルも保存したりしてる
運営から与えられた環境はきちんとバックアップする
#
重いところを見つけるトップページが明らかに重たいので改善する
$ MYSQL_QUERY_LOGGER=1 bundle exec rackup
SQL のログが出てくる
本番では MYSQL_QUERY_LOGGER のような関数を自分で追加しないといけないのでスニペットを用意しておく
log の共有として gist をよく使うので慣れておく
#
トップページでの表示件数を環境変数で減らすhttps://github.com/hi120ki/minisucon2020/commit/2a4021348e54eba6955744ebae96a96a124f66dd
$ ARTICLES_PER_PAGE=3 MYSQL_QUERY_LOGGER=1 bundle exec rackup
#
トップページにコメントの取得は必要ないhttps://github.com/hi120ki/minisucon2020/commit/b77609a728aea238949fe14888f99cda9d556d16
無駄なクエリを見つけよう!
ループの中で呼ばれるクエリを「N+1 Query」と呼ぶ
別の関数として定義して変更を加えてコンフリクトを防止する
#
コメント取得の改善[SQL] (7ms) SELECT COUNT(*) as `count` FROM `comments` WHERE `article_id` = '800' AND `user_id` NOT IN ('2','3','4','5','6','7','8') ORDER BY `id` DESC, `user_id` ASC
7ms は遅い
$ mysql -u root
$ use `minisucon2020`;
mysql> EXPLAIN SELECT COUNT(*) as `count` FROM `comments` WHERE `article_id` = '800' AND `user_id` NOT IN ('2','3','4','5','6','7','8') ORDER BY `id` DESC, `user_id` ASC;+----+-------------+----------+------------+------+---------------+------+---------+------+-------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+----------+------------+------+---------------+------+---------+------+-------+----------+-------------+| 1 | SIMPLE | comments | NULL | ALL | NULL | NULL | NULL | NULL | 22780 | 5.00 | Using where |+----+-------------+----------+------------+------+---------------+------+---------+------+-------+----------+-------------+
「type all」全件検索
「possible_keys NULL」インデックスなし
「rows」22780 件から「filtered」5%しか取ってきていない
インデックスを追加する
INDEX idx_count (`article_id`, `user_id`)
https://github.com/hi120ki/minisucon2020/commit/3c4762c7acbce70ba8f9a82848ccc5f0137ac920
SQL の実行計画(EXPLAIN SELECT ~)を見て rows filter extra をチェックする
#
記事取得の取得mysql> EXPLAIN SELECT * FROM `articles` WHERE `user_id` NOT IN ('0') ORDER BY `id` DESC LIMIT 4 OFFSET 0;
type ALL
filtered 90
https://github.com/hi120ki/minisucon2020/commit/132580d6d97bff9377be0d9b9a85ee150a4a5c0e
https://github.com/hi120ki/minisucon2020/commit/2a92d6888ca2f917604e0d5e124c55331f157356
type index になる
EXPLAIN で調査から index を貼ることは大事
基本的には where 文の条件キーを加えていく
#
不変なクエリ結果をメモリにキャッシュしてみるget_user の結果をキャッシュする
複数台なら redis
https://github.com/hi120ki/minisucon2020/commit/1e73dea0f1db9fa115df7c92e09c3454063759a7
#
user icon の改善https://github.com/hi120ki/minisucon2020/commit/6d1ac93bad835a1b9b4378d1d0ed1bbab9a4f4e3
$ sudo cp ~/minisucon2020/nginx.conf /etc/nginx/nginx.conf$ sudo service nginx restart
#
user icon を静的ファイル化https://github.com/hi120ki/minisucon2020/commit/e6759df96fb252546503b237f92a9afcd6f62265
/initialize リクエストが飛ぶと静的ファイルが生成される
#
大切なことアプリケーションを壊さない
再起動試験に耐える
小さなことからこつこつと