对 PHP SESSION 的深刻认识(四)---- 缓存(memcache和redis)存储session
来源:互联网 发布:虚拟主机控制面板源码 编辑:程序博客网 时间:2024/05/22 10:42
本篇博客将带着大家实现使用缓存系统来存储 session 数据,其中会介绍两个缓存系统 :memcache 和 redis。
一、使用 memcache:
如果大家有看过我之前的这篇博客 《memcache 和 memcached 的区别分析》,就会发现,PHP两个扩展中的 memcached 工作的更好,因此这篇博客在使用 memcache 服务时我选择的是 memcached 扩展。
1、使用 memcached 提供的 session 支持实现(最简单的方法)
memcached 提供了一个自定义的 session 处理器可以被用于存储用户session 数据到 memcached 服务端。 一个完全独立的 memcached 实例将会在内部使用,因此如果需要您可以设置一个不同的服务器池。
session 的 key 被存储在前缀 memc.sess.key. 之下,因此, 如果你对session 和通常的缓存使用了同样的服务器池,请注意这一点。 译注:另外一个 session 和通常缓存分离的原因是当通常的缓存占满了memcached 服务端后,可能会导致你的 session 被从缓存中踢除,导致用户莫名的掉线。
上面的话都是引用自 PHP 官方手册:http://php.net/manual/zh/memcached.sessions.php
下面我们通过实例来实现将 session 数据存储到 memcache。
第一步,设置session用memcache来存储:
打开配置文件 php.ini ,修改以下两项:
session.save_handler = memcachedsession.save_path = "127.0.0.1:11211"
重启服务器。
关于修改配置的话,如果你没有修改 php.ini 的权限,或者你只想在当前应用中使用 memcache 来存储 session 的话,可以使用局部的设置:
#在某个php文件中ini_set('session.save_handler','memcached');ini_set('session.save_path','127.0.0.1:11211');
配置好之后我们就可以使用了,非常简单:
第二步,在代码中使用会话:
#test1.php 文件<?php//如果你没有修改配置文件 php.ini,则用下面两行代码ini_set('session.save_handler','memcached');ini_set('session.save_path','127.0.0.1:11211');//开启会话session_start();if(!isset($_SESSION['name'])){ $_SESSION['name'] = 'default';}else{ $_SESSION['name'] = 'lsgogroup';}$_SESSION['age'] = 20;echo session_id(); //获取客户端的sessionId,即 PHPSESSID,后面会用到
在浏览器中打开 test1.php,然后我们在 test2.php 中验证是否操作成功。
#test2.php 文件<?php//如果你没有修改配置文件 php.ini,则用下面两行代码ini_set('session.save_handler','memcached');ini_set('session.save_path','127.0.0.1:11211');//开启会话session_start();var_dump($_SESSION);
在浏览器中打开 test2.php ,返回:
array(2) { ["name"]=> string(7) "default" ["age"]=> int(20) }
我们在 test3.php 中验证 session 是否是存储到了 memcached 中,由于前面说了session 的 key 被存储在前缀 memc.sess.key. 之下,因此当我们要从 memcached 中读取 session数据,我们指定的 key 是 memc.sess.key.sessionId,其中 sessionId 我们在 test1.php 中输出了,直接复制,或者从浏览器中的 cookie 中复制(我这里输出的是 g5ef37mnb7dstkf1kesegbajb7)。
#test3.php 文件#这里假设大家知道 memcached 的一些操作<?php$mem = new memcached();$mem->addServer("127.0.0.1",11211);echo $mem->get('memc.sess.key.g5ef37mnb7dstkf1kesegbajb7');
返回:
name|s:7:"default";age|i:20;
如果刷新 test1.php 页面,test2.php 和 test3.php 的输出如下:
#test2.phparray(2) { ["name"]=> string(9) "lsgogroup" ["age"]=> int(20) }#test3.phpname|s:9:"lsgogroup";age|i:20;
由上面的 test2.php 和 test3.php 的输出中我们成功的将 session 数据存储到 memcached 中。
memcached 对于 session 的支持还有好几个设置,可能大家都会用到,你如说前面的 key 的前缀设置默认是 memc.sess.key.,我们可以通过修改配置文件 php.ini,将配置项改成
memcached.sess_prefix = "zhongjin."
或这样:
ini_set("memcached.sess_prefix","zhongjin.");
那么你在 test3.php 中就可以这样读取 session 数据了:
echo $mem->get('zhongjin.g5ef37mnb7dstkf1kesegbajb7');
更多有用的配置项大家可以参考官方手册 :http://php.net/manual/zh/memcached.configuration.php
第三步,必要了解过期 session 数据的清理
首先,使用 memcached,将 session 数据都存储在内存中,一旦宕机,数据都会丢失,但对于 session 数据来说这其实并不是什么严重的问题。
其次,前面官方手册说道, session 和通常缓存分离的原因是当通常的缓存占满了memcached 服务端后,可能会导致你的 session 被从缓存中踢除,导致用户莫名的掉线。怎么理解?我们要从 memcache 淘汰数据的机制说起。
Memcached主要的cache机制是LRU(最近最少用)算法+超时失效(学过操作系统的同学应该会记忆幽深)。当您存数据到memcached中,可以指定该数据在缓存中可以呆多久。如果memcached的内存不够用了,过期的slabs会优先被替换,接着就轮到最老的未被使用的slabs。
怎样判断session失效了呢?在php.ini中有个Session.cookie_lifetime的选项,这个代表SessionID在客户端Cookie储存的时间,默认值是“0”,代表浏览器一关闭,SessionID就作废,这样不管保存在Memcached中的Session是否还有效(保存在Memcached中的session会利用Memcached的内部机制进行处理,即使session数据没有失效,而由于客户端的SessionID已经失效,所以这个key基本上不会有机会使用了,利用Memcached的LRU原则,如果Memcached的内存不够用了,新的数据就会取代过期以及最老的未被使用的数据),因为SessionID已经失效了,所以在客户端会重新生成一个新的SessionID。
我们再来解释官方手册的问题,通常的缓存是指我们在php中使用memcache来存储数据库查询结果等数据,导致占用大量的分配给 memcache 的内存,这样可能有某个用户的session数据会因此被淘汰掉,而此时用户还在线,就会导致用户意外掉线。所以官方手册上建议将 session 和通常的缓存分离。
2、通过php提供的接口,自己改写 session 的处理函数
通过自定义 session 的处理函数,我们能够更加自如的控制 session 的存取。更加多的细节和思想大家参考我的上一篇博客 《对 PHP SESSION 的深刻认识(三)—- 数据库存储session》,在这里我直接给出实现:
第一步,修改配置,告诉 php 引擎使用我们自己的session处理函数
打开配置文件 php.ini,修改配置项:
session.save_handler = user
同时注释 session.save_path 项(在前面添加 ;).
或者:
#在某个php文件中 ini_set('sesion.save_handler','user');
第二步,编写会话函数
新建 session.inc.php(结构跟session存储在数据库中的代码结构一样),代码如下:
#session.inc.php 文件<?php/** * Created by PhpStorm. * User: lsgozj * File: session.inc.php * Desc: 处理 session 的自定义类 * Date: 16-12-13 * Time: 下午2:45 */class memcachedSession implements SessionHandlerInterface{ private $_mem = null; //memcached链接句柄 //这些信息应该放在配置文件中。。。。 private $_configs = array( 'host' => '127.0.0.1', //主机域 'port' => 11211, //端口 'prefix' => '', //key前缀 'expire' => 0 //有效时间 ); public function __construct() { //默认获取配置文件中的配置 $this->_configs['prefix'] = ini_get('memcached.sess_prefix'); $this->_configs['expire'] = ini_get('session.gc_maxlifetime'); } //自定义session_start()函数 public static function my_session_start() { $sess = new self; session_set_save_handler($sess); //注册自定义函数,在php5.4之后,session_set_save_handler()参数直接传SessionHandlerInterface类型的对象即可。 session_start(); } /** * session_start() 开始会话后第一个调用的函数,类似于构造函数的作用 * @param string $save_path 默认的保存路径 * @param string $session_name 默认的参数名(PHPSESSID) * @return bool */ public function open($save_path, $session_name) { $mem = new memcached(); $mem->addServer($this->_configs['host'], $this->_configs['port']); $this->_mem = $mem; return true; } /** * 类似于析构函数,在write()之后调用或者session_write_close()函数之调用 * @return bool */ public function close() { $this->_mem = null; return true; } /** * 读取session信息 * @param string $sessionId 通过该ID(客户端的PHPSESSID)唯一确定对应的session数据 * @return session信息或者空串(没有存储session信息) */ public function read($sessionId) { //根据配置文件获取前缀(当然也可以自定义) return $this->_mem->get($this->_configs['prefix'] . $sessionId); } /** * 写入或修改session数据 * @param string $sessionId 要写入数据的session对应的id(PHPSESSID) * @param string $sessionData 要写入的是数据,已经序列化过的 * @return bool */ public function write($sessionId, $sessionData) { return $this->_mem->set($this->_configs['prefix'] . $sessionId, $sessionData, $this->_configs['expire']); } /** * 主动销毁session会话 * @param string $sessionId 要销毁的会话的唯一ID * @return bool */ public function destroy($sessionId) { return $this->_mem->delete($this->_configs['prefix'] . $sessionId); } /** * 清理会话中的过期数据 * @param int $maxlifetime 有效期(自动读取配置文件 php.ini 中的 session.gc_maxlifetime 配置项) * @return bool */ public function gc($maxlifetime) { return true; }}
对以上代码的必要解释:
1、存储时使用的 key 前缀和存储的生命周期读取的是配置文件 php.ini 的设置,如果需要自定义,在构造函数中修改或者直接在 _configs 数组中定义,然后删除构造函数。
2、由于我们在write()函数中设置缓存的时候已经指定生命周期,过期的数据会由 memcache 自动清理,所以后面的 gc() 函数已经没什么意义了,直接 return true 即可。
3、在使用 memcached 存储session数据的时候,有效时间不能超过30天。
我们在 test.php 文件中测试一下是否可用:
#test.php 文件<?phprequire_once('./session.inc.php');memcachedSession::my_session_start(); //开启会话$_SESSION['name'] = 'LSGOZJ';$_SESSION['age'] = 22;var_dump($_SESSION);echo '<br>'.session_id(); //获取SESSIONID,我们后面测试会用到,我现在测试得到的是 g5ef37mnb7dstkf1kesegbajb7
在浏览器中访问 test.php,然后我们在 test1.php 中看看memcached 中是否已经存储了 session 数据:
#test1.php 文件<?php$mem = new memcached();$mem->addServer('127.0.0.1',11211);$prefix = ini_get("memcached.sess_prefix");echo $mem->get($prefix."g5ef37mnb7dstkf1kesegbajb7");
在浏览器打开 test1.php 返回:
name|s:6:"LSGOZJ";age|i:22;
这个结果也能证明,我们已经成功的将 session 数据存储到 memcached 中了。
第三步、简单谈谈session的清理
在上面我们为我们的每一条 session 设置了生命周期,如果到达这个时间该条session还没有被访问的话,那么 memcached 视之为垃圾数据,但是,并不是到期了就把该条 session 数据删除,而是在下一次访问该条 session 数据的时候,检测是否到了有效期,过了有效期才把它从内存中删除。(如果用轮询的办法每时每刻的检测是否到期,那得多耗内存。。。。)
二、使用 redis:
由于使用 redis 和使用 memcache 是差不多的,因此这部分就快速的带过了。
1、使用 redis 提供的 session 支持实现(最简单的方法)
修改配置文件 php.ini:
session.save_handler = redissession.save_path = 'tcp://127.0.0.1:6379'
或是:
#某个php文件ini_set('session.save_handler','redis');ini_set('session.save_path','tcp://127.0.0.1:6379');
2、通过php提供的接口,自己改写 session 的处理函数
关于这一部分,跟上面 memcached 的内容非常像,就只有个别函数比如设置有效时间,redis使用setex()函数,等等跟memcached 不一样,我就不再举例子了。
总结:
1、“对 PHP SESSION 的深刻认识”这个小系列已经算是完成了。如果大家想了解 session 的原理等内容,可以回去看看我前面的几篇文章《对 PHP SESSION 的深刻认识(一)》、《对 PHP SESSION 的深刻认识(二)》 、《对 PHP SESSION 的深刻认识(三)—- 数据库存储session》
2、在写本篇博客和上一篇博客《memcache 和 memcached 的区别分析》之前,我对 memcached、redis 仅停留在简单使用的层面上,只知道这两个东西是个很强大的工具。在查阅了很多资料之后,我对这两个东西有了更深刻的了解。
- 对 PHP SESSION 的深刻认识(四)---- 缓存(memcache和redis)存储session
- 对 PHP SESSION 的深刻认识(三)---- 数据库存储session
- 对 PHP SESSION 的深刻认识(一)
- 对 PHP SESSION 的深刻认识(二)
- PHP中使用memcache(或者redis)存储session
- php session存储到文件、memcache或redis
- php使用memcache存储session
- php使用memcache存储session
- php使用memcache存储session
- php调用memcache存储session
- php使用memcache存储session
- php使用memcache存储session
- php Redis存储Session
- php Session存储到Redis的方法
- php Session存储到Redis的方法
- redis 或者memcache session 存储 同步
- (转)session和cookie的最深刻理解
- 基于php使用memcache存储session的详解
- 更好的 SQL 模式的 10 条规则
- 常用SQL查询语句
- R语言-linux下devtools包、SparkR包安装
- Hadoop安装教程_单机/伪分布式配置_Hadoop2.7.3/Ubuntu16.04
- 一个经典例子让你彻彻底底理解java回调机制
- 对 PHP SESSION 的深刻认识(四)---- 缓存(memcache和redis)存储session
- [Paper note] Xception: Deep Learning with Depthwise Separable Convolutions
- 升级python
- 【web】输入验证标准
- 非对称密码之DH密钥交换算法
- jdk 下有jre 还需要下载jre吗
- Hdu_2018 母牛的故事(递推)
- 权限系统——2016.12.13
- Hadoop项目规划:硬件