Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ISUCON4の予選問題をやってみる。(その2)

More than 5 years have passed since last update.

前回 基本的なチューニングまでやったのでその続きをやってみる。

MySQLのSQL発行状況を出力しEXPLAINする

ログ出力

一時的にMySQLに発行されたSQLを出力するのは my.cnf に以下を追記してMySQLを再起動する

# sudo vim /etc/my.cnf

[mysqld]
general-log=TRUE
general-log-file=/tmp/mysql_sql.log
$ sudo service mysqld restart

EXPLAIN

とあるuser_idについて前回ログイン成功以降からのログイン失敗数を求めるSQLは

ELECT COUNT(1) AS failures FROM login_log WHERE user_id = '12345' AND id > IFNULL((select id from login_log where user_id = '155328' AND succeeded = 1 ORDER BY id DESC LIMIT 1), 0);

であり、これをEXPLAINすると

mysql> EXPLAIN SELECT COUNT(1) AS failures FROM login_log WHERE user_id = '12345' AND id > IFNULL((select id from login_log where user_id = '155328' AND succeeded = 1 ORDER BY id DESC LIMIT 1), 0);
+----+-------------+-----------+------+---------------------+-------------+---------+-------+------+--------------------------+
| id | select_type | table     | type | possible_keys       | key         | key_len | ref   | rows | Extra                    |
+----+-------------+-----------+------+---------------------+-------------+---------+-------+------+--------------------------+
|  1 | PRIMARY     | login_log | ref  | PRIMARY,idx_user_id | idx_user_id | 5       | const |    1 | Using where; Using index |
|  2 | SUBQUERY    | login_log | ref  | idx_user_id         | idx_user_id | 5       |       |    1 | Using where              |
+----+-------------+-----------+------+---------------------+-------------+---------+-------+------+--------------------------+
2 rows in set (0.00 sec)

というふうに前回のチューニングでつけたindexを使っていることがわかる(Using index, rows=1)。ちなみにindexつける前は以下であり、Tableのフルスキャンが走っていることがわかる (row=37327)

mysql> EXPLAIN SELECT COUNT(1) AS failures FROM login_log WHERE user_id = '12345' AND id > IFNULL((select id from login_log where user_id = '155328' AND succeeded = 1 ORDER BY id DESC LIMIT 1), 0);
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
|  1 | PRIMARY     | login_log | range | PRIMARY       | PRIMARY | 8       | NULL | 37327 | Using where |
|  2 | SUBQUERY    | login_log | index | NULL          | PRIMARY | 8       | NULL |     1 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
2 rows in set (0.30 sec)

さらにIndexを複合indexにすることでSUBQUERYでもusing indexとなる。

mysql> CREATE INDEX idx_user_id on login_log(user_id, succeeded);

Redis

MySQLでやっている部分はRedisに変更することでさらにチューニングが期待できる。また、それ以上に、セッション管理している部分

# vim app.psgi
  enable 'Session',
    state => Plack::Session::State::Cookie->new(
      httponly    => 1,
      session_key => "isu4_session",
    ),
    store => Plack::Session::Store::File->new(
      dir         => $session_dir,
    ),

がセッションごとにファイル作成を行いパフォーマンスを劣化させているのでこれをまずなんとかする。 ( $session_dir をみるとえらい状態なのがわかる)

redis インストール & 起動

$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
$ sudo yum --enablerepo=remi install redis
$ sudo service redis start

perlのバインディングもinstall

$ cpanm install Redis
$ cpanm install Plack::Session::Store::Redis

セッション管理をredisに変更

# vim app.psgi
...
use Plack::Session::Store::Redis;
...
    store => Plack::Session::Store::Redis->new(
      prefix => "isucon",
      host => "localhost",
      port => 6379,
    ),
...
$ sudo /etc/init.d/supervisord stop

再びベンチマーク

$ ./benchmarker bench --workload 10
13:32:43 type:score     success:130710  fail:0  score:28238

これで28238点。

やっぱり中身もMySQLからRedis化せんとだめかな。。。

次回に続く

hiyuzawa
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away