PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

分布式存储Memcache替代Session方案

分布式存储Memcache替代Session方案

来源:phperz.com  作者:phperz.com  发布时间:2012-03-09
PHP自带的Session实际是在服务器中为每个客户建立独立的文件存放各自的信息。 在不做处理的情况下,很容易被客户端伪造。并且由于采用文件形式,所以存在着IO 读写的瓶颈。一般当用户在线达到1000左右时,就会出现访问速度明显下降的问题。 Memcache是应用层级的缓存,

PHP自带的Session实际是在服务器中为每个客户建立独立的文件存放各自的信息。

在不做处理的情况下,很容易被客户端伪造。并且由于采用文件形式,所以存在着IO

读写的瓶颈。一般当用户在线达到1000左右时,就会出现访问速度明显下降的问题。

Memcache是应用层级的缓存,它将数据存储内存中。内存的访问速度是可想而知的。

PHP在使用Memcache之前,需要做两件事。

1.安装PHP的memcache扩展。

2.下载Memcache文件。

以上两步很简单,去Google一下就可以了。

下面是memcache.class.php文件中MemcacheSession类

memcache.class.php
 
[php] view plaincopyprint?
<?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 (emptyempty($_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  
        } 
    } 
 

?> 
<?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] view plaincopyprint?
<?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)); 
?> 
<?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给其分配对应的服务器。

这两种方法,各自有各自的优缺点。

地址轮询,可以很好的实现负载均衡。

地址分配,可以根据用户位置分配距离最近的服务器,从而提高访问速度。


延伸阅读:
查看session内容的函数
PHP中常见的session问题
php用session做客户验证时的注意事项
Session常见问题解决办法
如何把Session放入MySql数据库中
php教程之session的应用 一
php教程之session的应用 二
php教程之session的应用 三
PHP SESSION过期时间问题
php 中session和cookie的区别
php 中session过期问题


PHP中Session会话的使用和分析
关于PHP编程中session的问题集锦及解决方法
session错误Cannot send session cache limiter - headers already sent 的解决方法
PHP基础:Session与Cookie
php中session和cookie的一些资料整理
利用Memcached在php下实现session机制
PHP 会话(session 时间设定)使用入门
PHP Notice: Undefined variable: _SESSION
php SESSION错误:session_start() [function.session-start]: open_basedir restriction
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号