[转]MySQL内存表、MyISAM表、MemCache实现Session效率比较
admin | 技术教程 | 一月 13th, 2009 | No Comments »
早先问过BleakWind,他认为,给别人做的话MySQL内存表做会话比较好一些,因为MySQL内存表做Session更容易维护(可以制作 安装脚本)。这个周末,我进行了一些测试,测试MySQL MyISAM表做会话(对时间给不给索引)、内存表做会话、MemCache做会话的效率比较。
定义会话Session类:
<?php
/**
* @author: wps2000
* file Session.php
* Email:[email protected]
* Data:
*/
class Seesion {
const SESSION_ID_NAME = ‘PHPSESSID’;
/**
* 会话生成时间
*
* @var int
*/
private $_session_left_time;
/**
* 会话GC概率
*
* @var int
*/
private $_gc_probility;
/**
* 会话处理器
*
* @var Session_Handler_Interface
*/
private $_session_handler;
/**
* 存储的会话数据
*
* @var Array
*/
private $_data;
/**
* 会话ID
*
* @var String
*/
private $_session_id;
public function __construct(Seesion_Handler_Interface $handler) {
$this->_session_handler = $handler;
$this->_gc_probility = ( int ) (get_cfg_var ( ‘session.gc_divisor’ ) / get_cfg_var ( ‘session.gc_probability’ ));
$this->_sessin_left_time = ( int ) get_cfg_var ( ‘session.gc_maxlifetime’ );
$this->_session_handler->open ( $this->_session_left_time );
if (isset ( $_COOKIE [self::SESSION_ID_NAME] )) {
$this->_session_id = $_COOKIE [self::SESSION_ID_NAME];
$this->_data = $this->_session_handler->read ( $this->_session_id );
} else {
$this->_session_id = $this->_generate_session_id ();
setcookie ( self::SESSION_ID_NAME, $this->_session_id, null, ‘/’ );
}
}
private function _generate_session_id() {
return uniqid ( mt_rand (), true );
}
public function __set($k, $v) {
$this->_data [$k] = $v;
}
public function __get($k) {
if (isset ( $this->_data [$k] ))
return $this->_data [$k];
return null;
}
public function destroy() {
$this->_sessin_handler->destroy ( $this->_session_id );
}
public function __destruct() {
$this->_session_handler->write ( $this->_session_id, $this->_data );
$this->_session_handler->close ();
if (mt_rand ( 1, $this->_gc_probility ) == 1) {
$this->_session_handler->gc ( $this->_session_left_time );
}
}
}
?>
定义会话处理器接口(Session_Handler_Interface):
<?php
/**
* @package default
* @author wps2000
* file Session_Handler_Interface.php
* Email:[email protected]
* Date: 16/12/2007
*/
interface Sessin_Handler_Interface {
function open($life_time);
function read($id);
function write($id, Array $data = null);
function destroy($id);
function close();
function gc($time = 0);
}
?>
实现MySQL内存表Session处理器:
<?php
/**
* @author wps2000
* file MySQL_Memory_Session.php
* Email: [email protected]
* Date: 16/12/2007
*/
class MySQL_Memory_Session implements Sessin_Handler_Interface {
/**
* 存储的数据库链接
*
* @var PDO
*/
private $_db;
private $_life_time;
public function open($life_time) {
$this->_db = new PDO ( ‘mysql:host=localhost;dbname=session’, ‘root’, ‘root’, array (PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_DIRECT_QUERY => true ) );
$this->_db = query ( ‘set names utf8’ );
$this->_life_time = $life_time;
}
public function read($id) {
/**
* 本处未做任何过滤
*/
$result = $this->_db->query ( ‘select * from `session` where `id`=\” . $id . ‘\’ and `time`>’ . (time () – $this->_life_time) )->fetchAll ( PDO::FETCH_ASSOC );
if ($result)
return $result [0];
return array ();
}
public function write($id, Array $data = null) {
/**
* 本处未做任何过滤
*/
$this->_db->query ( ‘replace into `session`(`id`,`name`,`ip`,`time`) values (\” . $id . ‘\’,\” . $data [‘name’] . ‘\’,\” . $data [‘ip’] . ‘\’,’ . time () . ‘)’ );
}
public function destroy($id) {
if (! $time)
$time = $this->_life_time;
$this->_db->query ( ‘delete from `session` where `time`<‘ . (time () – $time) );
}
public function close() {
return true;
}
}
?>
实现MemCache会话处理器:
<?php
/**
* @author: wps2000
* file MemCache_Session.php
* Email:[email protected]
* Date: 16/12/2007
* Test via MemCache 1.21 Server,PHP 5.25 with PHP_memcache.dll for PHP5.21
*/
class MemCache_Session implements Sessin_Handler_Interface {
private $_host;
private $_life_time;
public function open($life_time) {
$this->_host = new MemCache ( );
$this->_host->pconnect ( ‘localhost’ );
$this->_life_time = $life_time;
}
public function read($id) {
if ($result = $this->_host->get ( $id ))
return $result;
return array ();
}
public function write($id, Array $data = null) {
$this->_host->set ( $id, $data, MEMCACHE_COMPRESSED, $this->_life_time );
}
public function destroy($id) {
$this->_host->delete ( $id );
}
public function close() {
return true;
}
public function gc($lift_time = 0) {
return true;
}
}
?>
MySQL内存表测试程序:
<?php
/**
* 测试写入Session
*/
error_reporting ( E_ALL );
require ‘./Session_Handler_Interface.php’;
require ‘./MySQL_Memory_Session.php’;
require ‘./Session.php’;
$session = new Seesion ( new MySQL_Memory_Session ( ) );
$session->name = ‘wps2000’;
$session->ip = $_SERVER [‘REMOTE_ADDR’];
echo ‘Yeah!’;
?>
MemCache会话测试代码:
<?php
/**
* 测试MemCache Session实现
*/
require ‘./Session_Handler_Interface.php’;
require ‘./Session.php’;
require ‘./MemCache_Session.php’;
$sess = new Seesion ( new MemCache_Session ( ) );
$sess->name = ‘张心灵‘;
$sess->age = 23;
echo ‘Yeah’;
?>
MySQL会话表如下:
CREATE TABLE `session` (
`id` char(32) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`ip` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
`time` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
测试结果:
MemCache:
======================================================================================
Concurrency Level: 30
Time taken for tests: 18.234375 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 2774781 bytes
HTML transferred: 280000 bytes
Requests per second: 548.41 [#/sec] (mean)
Time per request: 54.703 [ms] (mean)
Time per request: 1.823 [ms] (mean, across all concurrent requests)
Transfer rate: 148.57 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.9 0 31
Processing: 0 53 12.1 46 328
Waiting: 0 52 11.9 46 328
Total: 0 53 12.1 46 328
Percentage of the requests served within a certain time (ms)
50% 46
66% 62
75% 62
80% 62
90% 62
95% 62
98% 62
99% 78
100% 328 (longest request)
MySQL内存表:
=================================================================================
Concurrency Level: 30
Time taken for tests: 20.375000 seconds
Complete requests: 10000
Failed requests: 4694
(Connect: 0, Length: 4694, Exceptions: 0)
Write errors: 0
Total transferred: 3118440 bytes
HTML transferred: 623048 bytes
Requests per second: 490.80 [#/sec] (mean)
Time per request: 61.125 [ms] (mean)
Time per request: 2.038 [ms] (mean, across all concurrent requests)
Transfer rate: 149.45 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.9 0 31
Processing: 0 60 7.6 62 125
Waiting: 0 59 7.6 62 125
Total: 0 60 7.5 62 125
Percentage of the requests served within a certain time (ms)
50% 62
66% 62
75% 62
80% 62
90% 62
95% 62
98% 78
99% 78
100% 125 (longest request)
其他测试:
将MySQL实现的数据库引擎改为 MyISAM(依然为 并发 30 测试 10000 次) 结果为:
Requests per second: 440.17 [#/sec] (mean)
Percentage of the requests served within a certain time (ms)
50% 62
66% 62
75% 78
80% 78
90% 78
95% 78
98% 78
99% 78
100% 640 (longest request)
为MyISAM表的 time 列增加索引(因为 会话表 读写次数几乎相等,因此应该效果不明显),结果为:
Requests per second: 441.08 [#/sec] (mean)
Percentage of the requests served within a certain time (ms)
50% 62
66% 62
75% 78
80% 78
90% 78
95% 78
98% 109
99% 109
100% 156 (longest request)
=================================================================================
结论:
MemCache做会话效率最高,也最灵活,但目前尝不支持查看谁在线等功能,附加的,只能自己增加一个数组记录在线用户、以及最后活跃时间并实现gc等。
MySQL内存表做会话效率也相当的高,另外一个有点是,MySQL内存表似乎更稳定,longest request (125ms)明显的短于 MemCache的(328ms)。不过缺点是,存储的字段数以及字段长度受限。
MySQL MyISAM表做会话在这里居然也达到了440的rps,真不简单。不过您要是等半个小时在测试一次,您就会明白MyISAM表的缺点了,页面几乎崩溃。MyISAM表的缺点是,一旦其中有较多的碎片,这个数据库几乎都不可用了,您注释掉 gc 的代码在这里貌似可以获得更好的效率表现(^_^、当然也可以定时的Optimizer,概率触发或者Cron定时启动也不错)
MyISAM表对time列增加索引对每秒完成的请求数没什么影响,不过有一点需要注意的是,增加索引后,每次完成 request的时间更均匀了,longest request从640ms跌到了156ms。为time列增加索引有助于让完成请求的时间变均匀。
测试平台:
Acer Aspire 4520G:
CPU:AMD Athlon 64 * 2 TK-55
RAM: IG
OS: Windows XP sp2
Web Server: Apache 2.26
PHP: PHP5.25
发表评论
你必须 登录 才能发表评论.