热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入Memcache的Session数据的多服务器共享详解_php技巧

一相关介绍1.memcache+memcache的多服务器数据共享的介绍,请参见http://www.guigui8.

一相关介绍
1.memcache + memcache的多服务器数据共享的介绍
,请参见http://www.guigui8.com/index.php/archives/206.html
2.session机制:
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识- 称为sessionid,如果已包含一个sessionid则说明以前已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含sessionid,则为此客户端创建一个session并且生成一个与此session相关联的sessionid,sessionid的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionid将被在本次响应中返回给客户端保存。

保存这个sessionid的方式可以采用COOKIE,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。

一般这个COOKIE的名字都是类似于SEEESIONID,而。比如weblogic对于web应用程序生成的COOKIE,PHPSESSID=ByOK3vjFD75aPnrF3K2HmdnV6QZcEbzWoWiBYEnLerj,它的名字就是PHPSESSID。

二动机
在实际web生产环境中,一个应用系统,往往将不同的业务应用分布到不同服务器上进行处理。
当跟踪当前在线用户信息时,如果是同一个主域名时,可以用全域COOKIE处理相关数据的共享问题;如果是在不同主域下,则可以通过观察者模式的中心话概念解决相应问题,通过这种概念延伸出的解决方案有很多,而今天我所要讲的,是前一种,通过memcache的多服务器数据共享技术来模拟session,以进行对当前在线用户数据的多服务器共享。
关于多服务器统一session信息,要求如下:
1.能够在memcached规定的几台服务器上,保存session信息(通过前面介绍的memcache的多服务器数据共享);
2.能够象zend定义的session_start()前,通过session_id($sessid)那样,自定义session_id的值。
3.能方便的在系统运行时,切换memcached存储的session信息和 用文件存储的session信息的操作。

三代码
实现方式很简单,通过memcache来模拟session机制,只是利用memcache将存储媒介换成共享服务器的内存,以达到多台分布式部署的服务器共享session信息的目的。而调用的接口,与zend提供的session操作函数相区别,所以可以方便的在memcache和文件的session信息操作建切换。
以下代码,已经过多次实际测试,能达到以上功能需求。先贴下面了:

/**
*=---------------------------------------------------------------------------=
* MemcacheSession.class.php
*=---------------------------------------------------------------------------=
*
* 实现基于Memcache存储的 Session 功能
* (模拟session机制,只是利用memcache将存储媒介换成共享服务器的内存)
*
* 缺点:暂时没有引入不同主域的session共享机制的实现策略。即只支持同主域下的实现。
*
* Copyright(c) 2008 by guigui. All rights reserved.
* @author guigui
* @version $Id: MemcacheSession.class.php, v 1.0 2008/12/22 $
* @package systen
* @link http://www.guigui8.com
*/


/**
* class MemcacheSession
*
* 1. 设置客户端的COOKIE来保存SessionID
* 2. 把用户的数据保存在服务器端,通过COOKIE中的Session Id来确定一个数据是否是用户的
*/
class MemcacheSession
{
// {{{ 类成员属性定义
public $memObject = null; //memcache操作对象句柄
private $_sessId = '';
private $_sessKeyPrefix = 'sess_';
private $_sessExpireTime = 86400;
private $_COOKIEDomain = '.guigui8.com'; //全域COOKIE域名
private $_COOKIEName = '_PROJECT_MEMCACHE_SESS';
private $_COOKIEExpireTime = '';

private $_memServers = array('192.168.0.3' => 11211, '192.168.0.4' => 11211);
private $_sessCOntainer= array(); //当前用户的session信息
private static $_instance = null; //本类单例对象
// }}}


/**
* 单例对象获取的静态方法。
* (可以顺便提供memcache信息存储的服务器参数)
*
* @param string $host - memcache数据存储的服务器ip
* @param integer $port - memcache数据存储的服务器端口号
* @param bool $isInit - 是否实例化对象的时候启动Session
*/
public static function getInstance($host='', $port=11211, $isInit = true) {
if (null === self::$_instance) {
self::$_instance = new self($host, $port, $isInit);
}
return self::$_instance;
}

/**
* 构造函数
*
* @param bool $isInit - 是否实例化对象的时候启动Session
*/
private function __construct($host='', $port=11211, $isInit = false){
!empty($host) && $this->_memServers = array(trim($host) => $port);
$isInit && $this->start();
}

/**
*=-----------------------------------------------------------------------=
*=-----------------------------------------------------------------------=
* Public Methods
*=-----------------------------------------------------------------------=
*=-----------------------------------------------------------------------=
*/

/**
* 启动Session操作
*
* @param int $expireTime - Session失效时间,缺省是0,当浏览器关闭的时候失效, 该值单位是秒
*/
public function start($expireTime = 0){
$_sessId = $_COOKIE[$this->_COOKIEName];
if (!$_sessId){
$this->_sessId = $this->_getId();
$this->_COOKIEExpireTime = ($expireTime > 0) ? time() + $expireTime : 0;
setCOOKIE($this->_COOKIEName, $this->_sessId, $this->_COOKIEExpireTime, "/", $this->_COOKIEDomain);
$this->_initMemcacheObj();

$this->_sessCOntainer= array();
$this->_saveSession();
} else {
$this->_sessId = $_sessId;
$this->_sessCOntainer= $this->_getSession($_sessId);
}
}

/**
* setSessId
*
* 自定义的session id,通常没有必要经过COOKIE操作处理的(所以省略了COOKIE记录session_id)
*
* @param string $sess_id
* @return boolean
*/
public function setSessId($sess_id){
$_sessId = trim($sess_id);
if (!$_sessId){
return false;
} else {
$this->_sessId = $_sessId;
$this->_sessCOntainer= $this->_getSession($_sessId);
}
}

/**
* 判断某个Session变量是否注册
*
* @param string $varName -
* @return bool 存在返回true, 不存在返回false
*/
public function isRegistered($varName){
if (!isset($this->_sessContainer[$varName])){
return false;
}
return true;
}

/**
* 注册一个Session变量
*
* @param string $varName - 需要注册成Session的变量名
* @param mixed $varValue - 注册成Session变量的值
* @return bool - 该变量名已经存在返回false, 注册成功返回true
*/
public function set($varName, $varValue){
$this->_sessContainer[$varName] = $varValue;
$this->_saveSession();
return true;
}

/**
* 获取一个已注册的Session变量值
*
* @param string $varName - Session变量的名称
* @return mixed - 不存在的变量返回false, 存在变量返回变量值
*/
public function get($varName){
if (!isset($this->_sessContainer[$varName])){
return false;
}
return $this->_sessContainer[$varName];
}

/**
* 销毁一个已注册的Session变量
*
* @param string $varName - 需要销毁的Session变量名
* @return bool 销毁成功返回true
*/
public function delete($varName){
unset($this->_sessContainer[$varName]);
$this->_saveSession();
return true;
}

/**
* 销毁所有已经注册的Session变量
*
* @return 销毁成功返回true
*/
public function destroy(){
$this->_sessCOntainer= array();
$this->_saveSession();
return true;
}


/**
* 获取所有Session变量
*
* @return array - 返回所有已注册的Session变量值
*/
public function getAll(){
return $this->_sessContainer;
}

/**
* 获取当前的Session ID
*
* @return string 获取的SessionID
*/
public function getSid(){
return $this->_sessId;
}

/**
* 获取Memcache的服务器信息
*
* @return array Memcache配置数组信息
*/
public function getMemServers(){
return $this->_memServers;
}

/**
* 设置Memcache的服务器信息
*
* @param string $host - Memcache服务器的IP
* @param int $port - Memcache服务器的端口
*/
public function setMemServers($arr){
$this->_memServers = $arr;
}

/**
* 添加Memcache服务器
*
* @param string $host - Memcache服务器的IP
* @param int $port - Memcache服务器的端口
*/
public function addMemServer($host, $port){
$this->_memServers[trim($host)] = trim($port);
$this->memObject->addServer($host, $port);
}

/**
* 移除Memcache服务器(注意,这个只是移除配置,并不能实际从memcached的连接池移除)
*
* @param string $host - Memcache服务器的IP
* @param int $port - Memcache服务器的端口
*/
public function removeMemServer($host){
unset($this->_memServers[trim($host)]);
}

/**
*=-----------------------------------------------------------------------=
*=-----------------------------------------------------------------------=
* Private Methods
*=-----------------------------------------------------------------------=
*=-----------------------------------------------------------------------=
*/

/**
* 生成一个Session ID
*
* @return string 返回一个32位的Session ID
*/
private function _getId(){
return md5(uniqid(microtime()));
}

/**
* 获取一个保存在Memcache的Session Key
*
* @param string $_sessId - 是否指定Session ID
* @return string 获取到的Session Key
*/
private function _getSessKey($_sessId = ''){
$sessKey = ($_sessId == '') ? $this->_sessKeyPrefix.$this->_sessId : $this->_sessKeyPrefix.$_sessId;
return $sessKey;
}
/**
* 检查保存Session数据的路径是否存在
*
* @return bool 成功返回true
*/
private function _initMemcacheObj(){
if (!class_exists('Memcache') || !function_exists('memcache_connect')){
$this->_showMessage('Failed: Memcache extension not install, please from http://pecl.php.net download and install');
}
if ($this->memObject && is_object($this->memObject)){
return true;
}
$this->memObject = new Memcache;
if (!empty($this->_memServers)) {
foreach ($this->_memServers as $_host => $_port) {
$this->memObject->addServer($_host, $_port);
}
}

return true;
}

/**
* 获取Session文件中的数据
*
* @param string $_sessId - 需要获取Session数据的SessionId
* @return unknown
*/
private function _getSession($_sessId = ''){
$this->_initMemcacheObj();
$sessKey = $this->_getSessKey($_sessId);
$sessData = $this->memObject->get($sessKey);
if (!is_array($sessData) || empty($sessData)){
//this must be $_COOKIE['__SessHandler'] error!
return array();
}
return $sessData;
}

/**
* 把当前的Session数据保存到Memcache
*
* @param string $_sessId - Session ID
* @return 成功返回true
*/
private function _saveSession($_sessId = ''){
$this->_initMemcacheObj();
$sessKey = $this->_getSessKey($_sessId);

if (empty($this->_sessContainer)){
$ret = @$this->memObject->set($sessKey, $this->_sessContainer, false, $this->_sessExpireTime);
}else{
$ret = @$this->memObject->replace($sessKey, $this->_sessContainer, false, $this->_sessExpireTime);
}

if (!$ret){
$this->_showMessage('Failed: Save sessiont data failed, please check memcache server');
}
return true;
}

/**
* 显示提示信息
*
* @param string $strMessage - 需要显示的信息内容
* @param bool $isFailed - 是否是失败信息, 缺省是true
*/
private function _showMessage($strMessage, $isFailed = true){
return;
if ($isFailed){
echo ($strMessage);
}
echo $strMessage;
}


四应用
1.本地session存储,与原始session操作方式一样,没有任何改变。如:

session_start();
$_SESSION['file_session_info']= '本地文件保存的session信息'; //本地文件保存的session


2.memcache共享服务器的session存储

$mem= MemcacheSession::getInstance('192.168.0.4', 11211);
$mem->addMemServer('192.168.0.4',11211);
$mem->addMemServer('192.168.0.5',11211);
//如果COOKIE功能不可用,则根据其他参数传递的唯一信息,设置映射为session_id
if(1) {
$sn= '838ece1033bf7c7468e873e79ba2a3ec';
$mem->setSessId($sn);
}
$mem->set('name','guigui'); //多台memcache服务器共享的session
$mem->set('addr','wuhan'); //多台memcache服务器共享的session
//$mem->destr6来源gaodaimacom搞#^代%!码网搞gaodaima代码oy();


3.分别获取本地和memcache存储的session信息

$addr= $mem->get('addr');
$_MEM_SESSION= $mem->getAll();
echo"
localhost file session:";
var_dump($_SESSION);
echo"
memcache session:";
var_dump($_MEM_SESSION);
//$res= $mem->delete('name');


推荐阅读
  • 本文讨论了在使用Git进行版本控制时,如何提供类似CVS中自动增加版本号的功能。作者介绍了Git中的其他版本表示方式,如git describe命令,并提供了使用这些表示方式来确定文件更新情况的示例。此外,文章还介绍了启用$Id:$功能的方法,并讨论了一些开发者在使用Git时的需求和使用场景。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • .NetCoreWebApi生成Swagger接口文档的使用方法
    本文介绍了使用.NetCoreWebApi生成Swagger接口文档的方法,并详细说明了Swagger的定义和功能。通过使用Swagger,可以实现接口和服务的可视化,方便测试人员进行接口测试。同时,还提供了Github链接和具体的步骤,包括创建WebApi工程、引入swagger的包、配置XML文档文件和跨域处理。通过本文,读者可以了解到如何使用Swagger生成接口文档,并加深对Swagger的理解。 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • Hadoop2.6.0 + 云centos +伪分布式只谈部署
    3.0.3玩不好,现将2.6.0tar.gz上传到usr,chmod-Rhadoop:hadophadoop-2.6.0,rm掉3.0.32.在etcp ... [详细]
  • 像跟踪分布式服务调用那样跟踪Go函数调用链 | Gopher Daily (2020.12.07) ʕ◔ϖ◔ʔ
    每日一谚:“Acacheisjustamemoryleakyouhaven’tmetyet.”—Mr.RogersGo技术专栏“改善Go语⾔编程质量的50个有效实践” ... [详细]
  • springboot基于redis配置session共享项目环境配置pom.xml引入依赖application.properties配置Cookie序列化(高版本不需要)测试启 ... [详细]
  • IamgettingaUnicodeerror:UnicodeEncodeError:charmapcodeccantencodecharacteru\xa9in ... [详细]
  • 一,织梦后台后台设置进入系统后台,在[系统基本参数]下面的性能选项卡当中,关于memcache进行如下配置:cfg_memcache_enable:是否启用memcache缓存,如果为否(N) ... [详细]
  • 相对于内存来说,磁盘的容量是非常大的,所以Linux内核实现了一个叫 内存交换 的功能--把某些进程的一些暂时用不到的内存页保存到磁盘中,然后把物理内存页分配给更紧急的用户使用,当 ... [详细]
author-avatar
栋逼逼丶
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有