Home  >  Article  >  Backend Development  >  php利用memcache 存session 丢数据的问题

php利用memcache 存session 丢数据的问题

WBOY
WBOYOriginal
2016-06-23 14:20:33729browse

先上测试代码,大家也可以测试下
index.php

<?phpsession_start();$method = $_GET['Method'];if(isset($_SESSION['Method'])){	$_SESSION['Method'] = $_SESSION['Method'].$method;}else{	$_SESSION['Method'] =$method;}?>

clent.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>无标题文档</title></head><script type="text/javascript" src="http://127.0.0.1/?Method=1" reload="1"></script><script type="text/javascript" src="http://127.0.0.1/?Method=2" reload="1"></script><script type="text/javascript" src="http://127.0.0.1/?Method=3" reload="1"></script><script type="text/javascript" src="http://127.0.0.1/?Method=4" reload="1"></script><script type="text/javascript" src="http://127.0.0.1/?Method=5" reload="1"></script><script type="text/javascript" src="http://127.0.0.1/?Method=6" reload="1"></script><body></body></html>


之后大家可以打印一下SESSION看看,结果经常会丢数据。SESSION经常就记录不全。不知道是为什么,还请高手来解释下。

下面附上我的其他配置
libevent-2.0.18-stable.tar.gz 服务器端
memcached-1.4.13.tar.gz  服务器端
memcache-2.2.6.tgz PHP客户端



PHP.ini
session.save_path="tcp://192.168.234.234:11211"
session.save_handler = memcache

PHP组件
php_memcache.dll  版本是2.2.6.0


回复讨论(解决方案)

会否是你测试的问题。
共有6次对index.php的请求:
第一次, 初始化session_id cookie.
但当第二次第三次,很可能第一次服务器还没来得及响应,请求就已经发出。而此时session_id cookie还未设置,于是再度初始化session_id cookie。
这样第一次请求设置的session_id cookie就被覆盖了,数据也就没法读出来了

不是session_start()的问题。
现在不说session,就是直接去用memcache的set方法,也有数据丢失。
代码如下

<?php$mem = new Memcache;$mem->connect("192.168.234.234",11211);$Method = $_GET['method']."|";if($mem->get('key')){	$aa = $mem->get('key');	$mem->set('key',$aa.$Method,0,60);}else{	$mem->set('key',$Method,0,60);	}$val = $mem->get('key');?>

有没有高人啊。。。问题解决了分数加倍送啊

现在不说session,就是直接去用memcache的set方法,也有数据丢失。

我觉得这个就是传说中的人品问题了...

虽然不曾在生产环境里使用,不过我觉得一个老牌的memcache 不应该存在这种丢三拉四的情况吧.

....
问题我公司里的2台memcache都存在这个问题。。。。
而且这个丢失很容易重现。
我怀疑是不是memcache或PHP配置的有问题。。。

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65536

# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 4294967295

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 268435456

这是memcache的sysctl.conf文件的内容。默认的。没动过。。。
麻烦memcache玩的熟的人给指点下。

补充一下,这2个memcache一个是普通办公台式机装的linux,一个是我笔记本虚拟出来的linux,主要是做测试用。不知道是否和机子还有关系?

你只写不读,如何能保证数据被正确写入了呢?
写后要校对,至少要有CRC校验
在这个层面上,你不应该相信任何人

我们在讨论的代码,都是原理性代码,实际使用时都是要另加判错的
就说 memcache 也只是给你一个通讯的环境

并不是简单的几行代码就能解决问题的
软件开发就是不断地发现问题和解决问题,一旦不需要维护了,那么这个软件就快要寿终正寝了

....当然是读了才发现的问题啊。。
我在memcache里遍历了数据,确实是没有写进去。并不是没读出来。

是记录不全呢,还是完全丢失呢?这个是两个性质的事情。如果实在没有解决方法,你可以试下 redis
不过我没用过,只是一直耳闻是memcache的替代品

....当然是读了才发现的问题啊。。
我在memcache里遍历了数据,确实是没有写进去。并不是没读出来。 那你就是没理解我的意思
我是说:写了马上就读,能读到并不错,这才表示写进去了
你以为如何?

1你说过用两台memcache测试都丢失,好像概率还不一样。请确定一个你测试的数据是否一样,中文还是全英的。
2两台都有问题,可以检查一下代码。先别用memcache,用mysql实现了。换之前,在实现session的函数中,都把数据写到一个文件中,检查一下。
3使用tcpdump,检查一下请求是否发过了。要是还是不行。改下memcache吧,也是跟踪变量。(感谢上天,我暂时没这需求)。

我用的方法比较笨,希望对你有点启发。

1你说过用两台memcache测试都丢失,好像概率还不一样。请确定一个你测试的数据是否一样,中文还是全英的。
2两台都有问题,可以检查一下代码。先别用memcache,用mysql实现了。换之前,在实现session的函数中,都把数据写到一个文件中,检查一下。
3使用tcpdump,检查一下请求是否发过了。要是还是不行。改下memcache吧,也是跟踪变量。(感谢上天,我暂时没这需求)。
……
测试7数据斗一样,见我上面发的代码。还有我每次接收到请求写入一比

手机发的字真难打。我次在接收到请求后都把请求的值写到库里。可以发现库里记录正常,但memcache不论是还存的session还是自定义一个变量存,都有写入不完整的情况。我不清楚是不是配置出了问题,我的配置版本和文件都贴出来了。麻烦大家帮看下是不是配置有问题。

另外各位大侠有没有手头有memcache环境的,帮忙看下上面的代码在你们的环境下是否有丢失,如果没问题可否把使用的版本发下我看是不是我这版本有问题,3q

你应该考虑到的是浏览器几乎同时并发请求的问题,你的新值是根据几毫秒前读出的值来设定的。可在这点时间里,完全有可能有新的值插入成功。如果再插入,那么将造成前面写入的新值还没被读出,反而立即被覆盖了。所以丢失数据很正常。
你完全可以在客户端或者服务器端写个测试看看,比较一下每次停顿一秒和同时并发的效果。

你还没说你测试页面返回的值是什么那?
看你程序你想要的结果123456.
js是顺利加载。应该没并发的问题吧。你检查数据的时候,主要检查一下sessionid

不用看 肯定哪个地方 刷新释放了

$mem->set('key',$aa.$Method,0,60);


失效时间为60秒

你可以把60值修改为更大。

你还没说你测试页面返回的值是什么那?
看你程序你想要的结果123456.
js是顺利加载。应该没并发的问题吧。你检查数据的时候,主要检查一下sessionid
是的,按理说应该出来是123456,但就像16楼说的一样,他的请求几乎是同时过来的,最终数据读出来的顺比并不是123456.可能会是512436这种。但是中间会丢,成了513

$mem->set('key',$aa.$Method,0,60);


失效时间为60秒

你可以把60值修改为更大。
这个我都试过了。都没用。

你应该考虑到的是浏览器几乎同时并发请求的问题,你的新值是根据几毫秒前读出的值来设定的。可在这点时间里,完全有可能有新的值插入成功。如果再插入,那么将造成前面写入的新值还没被读出,反而立即被覆盖了。所以丢失数据很正常。
你完全可以在客户端或者服务器端写个测试看看,比较一下每次停顿一秒和同时并发的效果。

应该是并发写的问题。我把每次请求后生成的SESSION都写入到数据库以后发现,SESSION存的值经常就被重写了,而不是在后面追加的。
下面这是按我贴出的测试代码进行的一次测试结果。我在上面的代码后面加了写入数据库的操作。可以看出第一个先到的请求是4,SESSION的值被写成了4,第二个是5,session本应该是45,却被直接写成了5,

请求值 请求时间 session_id 当前生成的SESSION值
"4",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","4"
"5",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","5"
"6",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","6"
"2",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","2"
"1",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","1"
"3",1334029029,"7j1jcsdkv583cb60nb3kfemnd6","43"

如果是并发的问题,那么你用mysql存储也一样有问题。并发问题解决不了,那谁还用了。

我邮箱:go123678@126.com。你发下。

使用APMserver5.2.6集成开发包,已经集成了memcache.
测试完成成功。

memcache_session.php (摘自http://imysql.cn/?q=node/215)

<?php//设定 SESSION 有效时间,单位是 秒define('SESS_LIFTTIME', 3600);//定义memcache配置信息define('MEMCACHE_HOST', 'localhost');define('MEMCACHE_PORT', '11211');if (!defined('MemcacheSession')){    define('MemcacheSession',    TRUE);class MemacheSession{    // {{{ 类成员属性定义    static  $mSessSavePath;    static  $mSessName;    static  $mMemcacheObj;    // }}}    // {{{ 初始化构造函数    /**     * 构造函数     *     * @param string $login_user    登录用户     * @param int $login_type       用户类型     * @param string $login_sess    登录Session值     * @return Esession     */    public function __construct()    {        //我的memcache是以php模块的方式编译进去的,可以直接调用        //如果没有,就请自己包含 Memcache-client.php 文件        if (!class_exists('Memcache') || !function_exists('memcache_connect'))        {            die('Fatal Error:Can not load Memcache extension!');        }        if (!empty(self::$mMemcacheObj) && is_object(self::$mMemcacheObj))        {            return false;        }        self::$mMemcacheObj = new Memcache;        if (!self::$mMemcacheObj->connect(MEMCACHE_HOST , MEMCACHE_PORT))        {            die('Fatal Error: Can not connect to memcache host '. MEMCACHE_HOST .':'. MEMCACHE_PORT);        }        return TRUE;    }    // }}}    /** {{{ sessOpen($pSavePath, $name)     *     * @param   String  $pSavePath     * @param   String  $pSessName     *     * @return  Bool    TRUE/FALSE     */    public function sessOpen($pSavePath = '', $pSessName = '')    {        self::$mSessSavePath    = $pSavePath;        self::$mSessName        = $pSessName;        return TRUE;    }    // }}}    /** {{{ sessClose()     *     * @param   NULL     *     * @return  Bool    TRUE/FALSE     */    public function sessClose()    {        return TRUE;    }    // }}}    /** {{{ sessRead($wSessId)     *     * @param   String  $wSessId     *     * @return  Bool    TRUE/FALSE     */    public function sessRead($wSessId = '')    {        $wData = self::$mMemcacheObj->get($wSessId);        //先读数据,如果没有,就初始化一个        if (!empty($wData))        {            return $wData;        }        else        {            //初始化一条空记录            $ret = self::$mMemcacheObj->set($wSessId, '', 0, SESS_LIFTTIME);            if (TRUE != $ret)            {                die("Fatal Error: Session ID $wSessId init failed!");                return FALSE;            }            return TRUE;        }    }    // }}}    /** {{{ sessWrite($wSessId, $wData)     *     * @param   String  $wSessId     * @param   String  $wData     *     * @return  Bool    TRUE/FALSE     */    public function sessWrite($wSessId = '', $wData = '')    {        $ret = self::$mMemcacheObj->replace($wSessId, $wData, 0, SESS_LIFTTIME);        if (TRUE != $ret)        {            die("Fatal Error: SessionID $wSessId Save data failed!");            return FALSE;        }        return TRUE;    }    // }}}    /** {{{ sessDestroy($wSessId)     *     * @param   String  $wSessId     *     * @return  Bool    TRUE/FALSE     */    public function sessDestroy($wSessId = '')    {        self::sessWrite($wSessId);        return FALSE;    }    // }}}    /** {{{ sessGc()     *     * @param   NULL     *     * @return  Bool    TRUE/FALSE     */    public function sessGc()    {        //无需额外回收,memcache有自己的过期回收机制        return TRUE;    }    // }}}    /** {{{ initSess()     *     * @param   NULL     *     * @return  Bool    TRUE/FALSE     */    public function initSess()    {        $domain = '.imysql.cn';        //不使用 GET/POST 变量方式        ini_set('session.use_trans_sid',    0);        //设置垃圾回收最大生存时间        ini_set('session.gc_maxlifetime',   SESS_LIFTTIME);        //使用 COOKIE 保存 SESSION ID 的方式        ini_set('session.use_cookies',      1);        ini_set('session.cookie_path',      '/');        //多主机共享保存 SESSION ID 的 COOKIE        ini_set('session.cookie_domain',    $domain);        //将 session.save_handler 设置为 user,而不是默认的 files        session_module_name('user');        //定义 SESSION 各项操作所对应的方法名:        session_set_save_handler(                array('MemacheSession', 'sessOpen'),   //对应于静态方法 My_Sess::open(),下同。                array('MemacheSession', 'sessClose'),                array('MemacheSession', 'sessRead'),                array('MemacheSession', 'sessWrite'),                array('MemacheSession', 'sessDestroy'),                array('MemacheSession', 'sessGc')                );        session_start();        return TRUE;    }}//end class}//end define$memSess    = new MemacheSession;$memSess->initSess();?>


memcache_test.php

<?phprequire 'memcache_session.php';$method = $_GET['Method'];if(isset($_SESSION['Method'])){    $_SESSION['Method'] = $_SESSION['Method'].$method;}else{    $_SESSION['Method'] =$method;}echo "var test={$_SESSION['Method']}";


index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>无标题文档</title></head><script type="text/javascript" src="http://localhost/session/session_test.php?Method=1" reload="1"></script><script type="text/javascript" src="http://localhost/session/session_test.php?Method=2" reload="1"></script><script type="text/javascript" src="http://localhost/session/session_test.php?Method=3" reload="1"></script><script type="text/javascript" src="http://localhost/session/session_test.php?Method=4" reload="1"></script><script type="text/javascript" src="http://localhost/session/session_test.php?Method=5" reload="1"></script><script type="text/javascript" src="http://localhost/session/session_test.php?Method=6" reload="1"></script><body></body></html>

另外发现你的index.php没有引入实现session的php文件。也没打印session值。

关注,我也出现了这个问题。

我也出现这个问题

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn