Skip to main content

ISUCONもくもく会に参加しました

· 2 min read
hi120ki
$ 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 リクエストが飛ぶと静的ファイルが生成される

大切なこと#

アプリケーションを壊さない

再起動試験に耐える

小さなことからこつこつと