PHPのセッション管理に使う箱選び 2
前回からの続き
MySQL
DBにはMySQL-5.0.27を採用。
MyISAMとInnoDBで比較してみる。MEMORY(HEAP)は試していない。MySQLサーバへはUNIXドメインソケットを使って接続し、毎回接続/切断を行うようにしてみた。GCは1/100のまま。
設定の問題もあるかもしれないけど、リクエスト数が増えるとMyISAMの場合は順調に遅くなってしまう。一方のInnoDBはかなり安定した性能。
MyISAMの場合、DELETEを実行する際にテーブルをロックしてしまうため、レコード数が多い状態で全件走査するDELETEが実行されると、長い時間他のクエリが待たされてしまうのが遅くなる原因ではないかと思う。
最長待ち時間もリクエスト/秒と同じ傾向になっている。ひとつのGCの処理が終わる前に別のGCが起動するという状態が繰り返され、どんどん待ち時間が長くなっているみたい。
設定など
適当に設定したmy.cnf
skip-locking key_buffer = 64M max_allowed_packet = 1M table_cache = 64 sort_buffer_size = 512K net_buffer_length = 8K read_buffer_size = 1M read_rnd_buffer_size = 512K myisam_sort_buffer_size = 1M innodb_data_file_path = ibdata1:10M:autoextend innodb_buffer_pool_size = 64M innodb_additional_mem_pool_size = 8M innodb_log_file_size = 32M innodb_log_buffer_size = 8M innodb_flush_log_at_trx_commit = 1 innodb_lock_wait_timeout = 50
テーブルのCREATE文
CREATE TABLE `sess_inno` ( `id` varbinary(48) NOT NULL, `data` blob NOT NULL, `mtime` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=binary CREATE TABLE `sess_myisam` ( `id` varbinary(48) NOT NULL, `data` blob NOT NULL, `mtime` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=binary
セッションハンドラ
<?php define('DB_HOST', 'localhost'); define('DB_NAME', 'session'); define('DB_USER', 'httpd'); define('DB_PASSWORD', 'password'); $GLOBALS['sess_con'] = null; function open($save_path, $session_name) { $con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD); if ($con !== false) { mysql_select_db(DB_NAME, $con); mysql_query('SET NAMES binary', $con); $GLOBALS['sess_con'] = $con; return true; } else { return false; } } function close() { return mysql_close($GLOBALS['sess_con']); } function read($sess_id) { $con = $GLOBALS['sess_con']; $sql = sprintf("SELECT data FROM sess_myisam WHERE id = '%s'", mysql_real_escape_string($sess_id, $con)); $result = mysql_query($sql, $con); if ($result !== false && mysql_num_rows($result) === 1) { $row = mysql_fetch_row($result); return $row[0]; } else { return ''; } } function write($sess_id, $sess_data) { $con = $GLOBALS['sess_con']; $sql = sprintf("REPLACE INTO sess_myisam (id, data) VALUES('%s', '%s')", mysql_real_escape_string($sess_id, $con), mysql_real_escape_string($sess_data, $con)); $result = mysql_query($sql, $con); if ($result !== false) { return true; } else { return false; } } function destroy($sess_id) { $con = $GLOBALS['sess_con']; $sql = sprintf("DELETE FROM sess_myisam WHERE id = '%s'", mysql_real_escape_string($sess_id, $con)); $result = mysql_query($sql, $con); if ($result !== false) { return true; } else { return false; } } function gc($maxlifetime) { $con = $GLOBALS['sess_con']; $sql = sprintf("DELETE FROM sess_myisam WHERE mtime < FROM_UNIXTIME(%d)", time() - $maxlifetime); $result = mysql_query($sql, $con); if ($result !== false) { return true; } else { return false; } } session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc'); ?>
destroy関数で使っているmysql_real_escape_string()の前に$が付いていたので削除