PHP自带的Session实际是在服务器中为每个客户建立独立的文件存放各自的信息。
在不做处理的情况下,很容易被客户端伪造。并且由于采用文件形式,所以存在着IO
读写的瓶颈。一般当用户在线达到1000左右时,就会出现访问速度明显下降的问题。
Memcache是应用层级的缓存,它将数据存储内存中。内存的访问速度是可想而知的。
PHP在使用Memcache之前,需要做两件事。
1.安装PHP的memcache扩展。
2.下载Memcache文件。
以上两步很简单,去Google一下就可以了。
下面是memcache.class.php文件中MemcacheSession类
memcache.class.php
<?php define('PREFIX', 'god'); define('SESS_LEFETIME', 3600); define('ZIP_FLAG', 0); class MemcacheSession { static $Memcache; /* 构造函数 * @param string @login_user * @param int @login_type * @param string $login_sess */ public function __construct($config) { if (!class_exists('Memcache') || !function_exists('memcache_connect')) { exit("Can't load Memcache Extendstion"); } $this->Memcache = new Memcache; if (!@$this->Memcache->connect($config['host'], $config['port'])) { exit('连接失败'); } $this->setCookie(); return TRUE; } /* 增加键值 * return bool */ public function add($key, $data='empty') { if (!$this->Memcache->add($key, $data, ZIP_FLAG, SESS_LEFETIME)) { exit("此键名已经被使用"); } } /* uniqueID * return string */ public function uniqueID() { return PREFIX . md5(uniqid(rand(), true)) . $_SERVER['REMOTE_ADDR']; ; } /* 读取数据 * @param string * return string/array */ public function get($key='') { if ($key == '') exit('键名不能为空'); $wData = $this->Memcache->get($key); if (!$wData) return FALSE; return $wData; } /* 重写数据 * @param string $key * @param string $data * @return bool */ public function set($key, $data='') { $ret = $this->Memcache->set($key, $data, ZIP_FLAG, SESS_LEFETIME); if (TRUE != $ret) { exit("存储数据失败"); } } /* 注销数据 * @param string $key * return bool */ public function memDestory($key) { $this->Memcache->set($key); } /* Cookie验证,建立客户端与服务器端同步键名 * return bool */ public function setCookie() { if (empty($_COOKIE['sessionID'])) { $sessionID = md5(uniqid(rand(), true)) . $_SERVER['REMOTE_ADDR']; setcookie('sessionID', $sessionID, time() + SESS_LEFETIME); $this->set(PREFIX . $sessionID, 'empty'); } else { setcookie('sessionID', $_COOKIE['sessionID'], time() + SESS_LEFETIME); if (!$this->Memcache->get(PREFIX . $_COOKIE['sessionID'])) exit('处理异常'); //出现此错误是因为客户端伪造sessionID } } } ?>
下面是简单的测试使用
ceshi.php
<?php require_once "memcache.class.php"; $config['host'] = '127.0.0.1'; $config['port'] = 11211; try { $session = new MemcacheSession($config); } catch (Exception $e) { echo $e->getMessage(); } $sessionID = PREFIX . $_COOKIE['sessionID']; $data['userA'] = 1024; $data['pointA'] = 100; $data['introA'] = '你干嘛呢!干嘛呢!'; $session->set($sessionID, $data); print_r($session->get($sessionID)); ?>
这里仅仅是针对一台服务器的实现。
如果需要分布式存储只需在实例化类传递host时,进行一些扩展就可以实现了。
扩展方案:
1.地址轮询:假设有3台服务器A、B、C,那么当第一个用户访问时连接A,第二个访问时连接B,第三个访问时连接C,第四个访问时返回第一个重新开始计数,依次向下。
2.地址分配:设定三个段A:69.168.0.0-69.168.255.255;B:192.168.0.0-192.168.255.255;C:68.192.0.0-68.192.255.255
当用户访问时,根据IP给其分配对应的服务器。
这两种方法,各自有各自的优缺点。
地址轮询,可以很好的实现负载均衡。
地址分配,可以根据用户位置分配距离最近的服务器,从而提高访问速度。