点击数:14052015-07-29 15:35:50 来源: 外贸网站建设,深圳外贸网站建设,深圳网站建设,外贸商城网站制作-亿恩科技
所谓两层,简单描述如下:
保存到Memcached中的同时也保存到数据库中,写入时监控共享内存利用率,如果超过伐值,从共享内存中删除这个会话,这时可能释放了共享内存,只保存到了数据库,而取数据时,先到共享内存取,如果没有命中则到数据库取。
经过研究,在Magento中只要重写Mage_Core_Model_Resource_Session类就能实现。
首先在自定义模块的配置文件中重写这个类:
1
2
3
4
5
6
7
8
9
10
11
12
|
<global>
<models>
<mysession>
<class>Vfeelit_Mysession_Model</class>
</mysession>
<core_resource>
<rewrite>
<session>Vfeelit_Mysession_Model_Resource_Session</session>
</rewrite>
</core_resource>
</models>
</global>
|
然后我们的Vfeelit_Mysession_Model_Resource_Session继承自Mage_Core_Model_Resource_Session。在构造函数中引入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public function __construct()
{
$mySession = Mage::getConfig()->getNode(self::XML_NODE_MYSESSION)->asArray();
$prefix = $mySession['session_prefix'];
if(!empty($prefix)){
$this->_prefix = $prefix;
}
$options = $mySession['session_servers'];
$this->_backend = new Zend_Cache_Backend_Libmemcached($options);
parent::__construct();
}
|
我这里实例化一个Zend_Cache_Backend_Libmemcached对象(PHP必须安装了Memcached扩展),用它来链接Memcached服务器,把数据保存到共享内存中。我这里还设置了一个key的前缀(因为我自己控制数据存入,所以key就可以自定义了),后面就是调用父类的构造函数,它负责数据库初始化。
要自定义会话的处理,需要使用session_set_save_handler()绑定6个方法,这个已经在Mage_Core_Model_Resource_Session中实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public function setSaveHandler()
{
if ($this->hasConnection()) {
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
} else {
session_save_path(Mage::getBaseDir('session'));
}
return $this;
}
|
看起来,我们不需要动这个方法。我们需要重载的方法是read和write和destory(gc方法直接使用继承过来的即可)。
首先看read重载方法的实现:
1
2
3
4
5
6
7
8
9
10
11
12
|
public function read($sessId)
{
if($this->_backend){
$id = $this->_prefix.$sessId;
$data = $this->_backend->load($id);
}
if(!$data){
return parent::read($sessId);
}else{
return $data;
}
}
|
实际上非常简单,从共享内存中取数据,如果没有取到(可能是共享服务器down了或被存满了),就去数据库里取,从数据库取数据的逻辑Magento本身已经实现。
然后看write方法:
1
2
3
4
5
6
7
8
|
public function write($sessId, $sessData)
{
if($this->_backend){
$id = $this->_prefix.$sessId;
$this->_save($sessData, $id, array(), $this->getLifeTime());
}
return parent::write($sessId, $sessData);
}
|
这个方法同时保存到共享内存和数据库,这个是read方法无法读取到数据时可以从数据库里读取到的保证。这里我实现了一个_save方法抽象了保存的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
private function _save($data, $id, $tags = array(), $specificLifetime = false)
{
$usage = $this->_getFastFillingPercentage('saving');
$boolFast = true;
if($specificLifetime){
$lifetime = $specificLifetime;
}else{
$lifetime = $this->getLifetime();
}
//$preparedData = $this->_prepareData($data, $lifetime);
if ( 85 >= $usage) {
$boolFast = $this->_backend->save($data, $id, array(), time()+$lifetime);
} else {
$boolFast = $this->_backend->remove($id);
if (!$boolFast && !$this->_backend->test($id)) {
// some backends return false on remove() even if the key never existed. (and it won't if fast is full)
// all we care about is that the key doesn't exist now
$boolFast = true;
}
}
return $boolFast;
}
|
通过_getFastFillingPercentage方法获取共享内存的利用率,当利用率没有超过85,直接保存到共享内存中。如果超过了,就把这个KEY从数据库中踢掉,最后确保已经成功删除。这样,到达伐值后,就释放空间,内容从数据库获取,释放的空间和内存过期的会话释放的空间如果低于了伐值,新的会话数据库继续写入共享内存,从而实现了快慢存储。
从测试来看,完成没有问题。另外一个需要主要的是,会话的共享内存空间最好不要和其它的缓存内存混用,因为会话内容共享内存一定要设置过期时间,方便垃圾数据及时退出,而缓存共享内存就不一定了,可以设置它保存很长时间,甚至直到手动刷新或重启Memcached服务时才被清理,所有缓存空间可能会被快速占用而不释放,那么会话内容可能无法存入,加速会话读取(或共享内存)的美梦就会泡汤。这里的自己写的代码不多,但是要非常清楚的内容就非常多,比如会话机制的原理,共享内存Memcached工作原理,Magento的类重写,Magento对会话的封装过程等。