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

一相关介绍
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 <evan_gui@163.com>
 * @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->destroy();

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


代码如下:

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

(0)

相关推荐

  • PHP 实现多服务器共享 SESSION 数据

    一.问题起源 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名.密码在整个网站的各个模块中都是可以登录使用的.各个服务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可.但还存在一个问题,就是用户在这个服务器登录之后,进入另一个服务器的别的模块时,仍然需要重新登录,这就是一次登录,全部通行的问题,映射到技术上,其实就是各个服务器之间如何实现共享

  • Session服务器配置指南与使用经验的深入解析

    一.摘要所有Web程序都会使用Session保存数据. 使用独立的Session服务器可以解决负载均衡场景中的Session共享问题.本文介绍.NET平台下建立Session服务器的几种办法, 并介绍在使用Session时的各种经验和技巧. 二.关于Session,SessionID和CookiesSession数据保存在服务器端, 但是每一个客户端都需要保存一个SessionID, SessionID保存在Cookies中, 关闭浏览器时过期. 在向服务器发送的HTTP请求中会包含Sessio

  • IIS服务器中 ASP.NET State Service 开启后 Session 仍容易丢失的问题终极解决办法

    解决方法一: 1. 开启ASP.NET State Service服务: 选择管理工具->服务,找到ASP.NET State Service,点开后选择启动,并将启动类型设为自动. 2. 设置程序配置文件: 将web.config打开,会看到有一行是<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" timeout="20"/>,如

  • asp.net页面状态管理cookie和服务器状态管理Session

    Cookie:是存储在客户端文件系统的文本文件中或客户端浏览器对话的客户端浏览器对话的内存中的少量的数据.当我们在访问一个网站网页,当用户请求该网页时,应用程序会首先检查用户在此前是否已经登录过,我们可以通过读取Cookie获取用户信息来判断是否让它继续访问 记录Cookie信息 创建一个名称是user的Cookie对象:HttpCookie cookie=new HttpCookie("user"); 给Cookie赋值,只能使用字符串赋值:cookie.Value="ch

  • PHP实现多服务器session共享之NFS共享的方法

    PHP实现多服务器session共享之NFS共享  前言,Nio大侠提出了session多服务器共享的问题,原文请见PHP 实现多服务器共享 SESSION 数据. 其中,有一种方法就是利用NFS来共享session,如果session量比较大并且所有的session文件都在同一个子目录下的话,那么可能会由此带来很严重的负载问题,甚至导致网站无法使用.本文就是对这个方案做一下详细的解说. 首先,修改 php.ini的 session.save_path 选项,大致如下: session.save

  • 用PHP实现多服务器共享SESSION数据的方法

    PHP 实现多服务器共享 SESSION 数据 /google 的广告条--> 一.问题起源 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名.密码在整个网站的各个模块中都是可以登录使用的.各个服务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可.但还存在一个问题,就是用户在这个服务器登录之后,进入另一个服务器的别的模块时,仍然需要重新登录,这

  • 多php服务器实现多session并发运行

    首先介绍一下session的概念: 所谓session是微软首先提出的,在asp中最先集成.由于session的采用,大大方便了web开发员的工作.一时间asp风靡全球.现在php4也加入session的支持,再度显示出open source 的强大力量.和Cookie类似,设计Session的目的也是为了在一个访问期间在不同的页面间传输数据以解决http协议无状态的问题,但Session更加简单.更加安全.Session 中文没有一个统一的译法,我习惯上译为会话.关于session的意义大家都

  • 深入Memcache的Session数据的多服务器共享详解

    一相关介绍1.memcache + memcache的多服务器数据共享的介绍,请参见http://www.guigui8.com/index.php/archives/206.html2.session机制:session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息.当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识- 称为sessionid,如果已包含一个sessionid

  • Redis数据过期策略的实现详解

    目录 一.设置过期时间 1.常用方式 2.字符串独有方式 二.3种过期策略 三.Redis采用的过期策略 四.RDB对过期key的处理 五.AOF对过期key的处理 本文对Redis的过期机制简单的讲解一下 讲解之前我们先抛出一个问题,我们知道很多时候服务器经常会用到redis作为缓存,有很多数据都是临时缓存一下,可能用过之后很久都不会再用到了(比如暂存session,又或者只存放日行情股票数据)那么就会出现一下几个问题了 Redis会自己回收清理不用的数据吗?如果能,那如何配置?如果不能,如何

  • C语言数据输入与输出实例详解

    C语言数据输入与输出实例详解 1 概论 C语言提供了跨平台的数据输入输出函数scanf()和printf()函数,它们可以按照指定的格式来解析常见的数据类型,例如整数,浮点数,字符和字符串等等.数据输入的来源可以是文件,控制台以及网络,而输出的终端可以是控制台,文件甚至是网页. 2 数据输出 从第一个c语言程序中,就使用了跨平台的库函数printf实现将一段文字输出到控制台,而实际上,printf()不仅可以将数据按照指定的格式输出到控制台,还可以是网页或者是指定的文件中,printf()函数执

  • Java编程Post数据请求和接收代码详解

    这两天在做http服务端请求操作,客户端post数据到服务端后,服务端通过request.getParameter()进行请求,无法读取到数据,搜索了一下发现是因为设置为text/plain模式才导致读取不到数据 urlConn.setRequestProperty("Content-Type","text/plain; charset=utf-8"); 若设置为以下方式,则通过request.getParameter()可以读取到数据 urlConn.setReq

  • Hibernate中Session增删改查操作代码详解

    把三状态转换图放在这,方便分析方法的作用: 1.Session的save()方法 Session是Hibernate所有接口中最重要的接口,提供了对数据保存,更新,查询和删除的方法. Session的save()方法可以使临时态或游离态转换为持久态.例如,保存一个Customer对象: SessionFactory sessionFactory; Configuration configuration = new Configuration().configure(); sessionFacto

  • 微信小程序数据存储与取值详解

    在小程序开发的过程,经常要需要这个页面输入的数据,在下一个页面中进行取值赋值. 比如: 在A页面input输入框,输入电话号码,点击添加.需要在B页面电话区域中,显示刚刚输入的电话号码. 因为这是两个页面,就需要先存储,再取值.微信小程序提供了数据存储的API,wx.setStorage(OBJECT) 可以将数据存储在本地缓存中指定的 key 中,如果重复会覆盖掉原来该 key 对应的内容. 思路是,在A页面,使用bindinput获取input输入的值,赋值给一个变量(自定义),点击添加按钮

  • MySQL数据归档小工具mysql_archiver详解

    一.主要概述 MySQL数据库归档历史数据主要可以分为三种方式:一.创建编写SP.设置Event:二.通过dump导入导出:三.通过pt-archiver工具进行归档.第一种方式往往受限于同实例要求,往往被大家舍弃.第二种,性能相对较好,但是归档表较多时运维也是比较头疼的事.所以很多DBA往往采用第三种方式--pt-archiver. pt-archiver是Percona-Toolkit工具集中的一个组件,是一个主要用于对MySQL表数据进行归档和清除的工具.它可以将数据归档到另一张表或者是一

  • 基于MyBatis的数据持久化框架的使用详解

    目录 一.MyBatis是什么 1.1.概述 1.2.什么是持久化 1.3.什么是ORM 1.4.MyBatis主要内容 1.5.优点 1.6.缺点 二.MyBatis架构 2.1.mybatis所依赖的jar包 2.2.MyBatis准备工作 三.MyBatis 核心对象 一.MyBatis是什么 1.1.概述 Mybatis是一个优秀的开源.轻量级持久层框架,它对JDBC操作数据库的过程进行封装,简化了加载驱动.创建连接.创建 statement 等繁杂的过程,使开发者只需要关注sql本身.

  • kubernetes数据持久化PV PVC深入分析详解

    目录 1. 什么是PV,PVC? 1.1 什么是PV 1.2 什么是PVC? 2. PV资源实践 2.1 PV配置字段详解 2.2 HostPath PV示例 2.3 NFS PV示例 3. PVC资源实践 3.1 PVC配置清单详解 3.2 hostPath-PVC示例 3.3 NFS-PV-PVC实践之准备NFS共享存储 3.4 准备NFS-PVC 3.4.1准备Pod并使用PVC 3.4.2 测试数据持久性 1. 什么是PV,PVC? 1.1 什么是PV 官方文档地址: https://k

  • NodeJs Express框架实现服务器接口详解

    目录 CORS 跨域资源共享 1. 接口的跨域问题 2. 使用 cors 中间件解决跨域问题 创建基本的服务器 创建 API 路由模块 编写 GET 接口 编写 POST 接口 注意:如果要获取 URL-encoded 格式的请求体数据,必须配置中间件 app.use(express.urlencoded({ extended: false })) CORS 跨域资源共享 1. 接口的跨域问题 <body> <button id="btnGET">GET<

随机推荐