ホームページ  >  記事  >  バックエンド開発  >  PHP は memcache を使用してセッションを保存し、データを失います

PHP は memcache を使用してセッションを保存し、データを失います

WBOY
WBOYオリジナル
2016-06-23 14:20:33685ブラウズ

まずコードをテストしましょう。
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 は不完全に記録されることがよくあります。理由が分からないので専門家に解説してもらいたいです。

以下に私の他の構成を添付します
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


ディスカッションへの返信 (解決策)

いいえあなたにテストしてもらうための質問です。
Index.php へのリクエストは合計 6 つあります。
初回は session_id Cookie が初期化されます
しかし、2 回目と 3 回目では、サーバーが応答する前にリクエストが送信される可能性が非常に高くなります。 。この時点では、session_id cookie は設定されていないため、session_id cookie は再度初期化されます。
この方法では、最初のリクエストで設定された session_id Cookie が上書きされ、データを読み取ることができなくなります

session_start() の問題ではありません。
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');?>

専門家はいますか? 。 。問題は解決され、ポイントは 2 倍になります

ここで、memcache の set メソッドを直接使用した場合でも、データの損失が発生します。

これは伝説のキャラクターの問題だと思います...

本番環境では使用されていませんが、古い memcache ではこのような状況が起こるべきではないと思います

.. ..
問題: 両方の memcache。私の会社のマシンにはこの問題があります。 。 。 。
そして、この損失は簡単に再現できます。
memcache または PHP の設定に何か問題があると思われます。 。 。

# IP パケット転送を制御します
net.ipv4.ip_forward = 0

# ソースルート検証を制御します
net.ipv4.conf.default.rp_filter = 1

# ソースルーティングを受け入れません
conf.default .accept_source_route = 0

# カーネルのシステムリクエストデバッグ機能を制御します
kernel.sysrq = 0

# コアダンプがコアファイル名に PID を追加するかどうかを制御します
# マルチスレッドアプリケーションのデバッグに役立ちます
kernel.core_uses_pid = 1

# TCP syncookies の使用を制御します
net.ipv4.tcp_syncookies = 1

# メッセージの最大サイズをバイト単位で制御します
kernel.msgmnb = 65536

# メッセージキューのデフォルトの最大サイズを制御します
kernel.msgmax = 65536

# 最大共有セグメント サイズをバイト単位で制御します
kernel.shmmax = 4294967295

# 共有メモリ セグメントの最大数をページ単位で制御します
kernel.shmall = 268435456

これは memcache です。 ctl .conf ファイル。デフォルト。手付かず。 。 。
memcache に詳しい方からアドバイスをお願いします。

付け加えますと、2 つの memcache のうち 1 つは通常のオフィスのデスクトップにインストールされている Linux で、もう 1 つは主にテスト用にラップトップ上で仮想化された Linux です。機械と何か関係があるのか​​な?

書き込みのみで読み取りはしない場合、データが正しく書き込まれていることをどのように確認できますか?
書いた後は校正し、少なくとも CRC チェックをしてください
このレベルでは、誰も信頼すべきではありません

私たちが議論しているコードはすべて理論上のコードであり、エラーは実際の使用時に判断する必要があります
memcache はあなたに与えるだけだとだけ言っておきましょう通信環境

問題を解決できるのは数行のコードだけではありません
ソフトウェア開発は、メンテナンスが必要なくなったら、すぐに寿命を迎えます

....もちろん、読んでから問題に気づきました。 。
memcache 内のデータを走査しましたが、確かにデータは書き込まれませんでした。読まなかったわけではない。

記録は不完全ですか、それとも完全に失われていますか?これには 2 つの性質の問題があります。本当に解決策がない場合は、redis を試すことができます
しかし、私はそれを使用したことがありません。それが memcache の代替品であると常に聞いていました

.... もちろん、私はそれについて読んだ後でのみ問題を発見しました。 。
memcache 内のデータを走査しましたが、確かにデータは書き込まれませんでした。読まなかったわけではない。 じゃあ、あなたは私が何を言っているのか理解できませんでした
つまり、書いたらすぐに読んでください。それが書かれているということは良いことです
どう思いますか?

1 2 つの memcache を使用したテストが失敗したとのことですが、確率は同じではないようです。テストしているデータが同じであるか、中国語か英語かを確認してください。
2 両方のユニットに問題がある場合は、コードを確認できます。最初に memcache を使用するのではなく、mysql を使用して実装してください。変更前に、セッションを実装する関数内でデータをファイルに書き込んで確認してください。
3 tcpdump を使用して、リクエストが送信されたかどうかを確認します。それでもうまくいかない場合は。変数も追跡する memcache を変更します。 (ありがたいことに、当面はその必要がありません)。

私が使用した方法は比較的愚かですが、それがあなたにインスピレーションを与えることを願っています。

1 2 台の memcache マシンを使用するとテストが失敗したとのことですが、確率は同じではないようです。テストしているデータが同じであるか、中国語か英語かを確認してください。
2 両方のユニットに問題がある場合は、コードを確認できます。最初に memcache を使用するのではなく、mysql を使用して実装してください。変更前に、セッションを実装する関数内でデータをファイルに書き込んで確認してください。
3 tcpdump を使用して、リクエストが送信されたかどうかを確認します。それでもうまくいかない場合は。変数も追跡する memcache を変更します。 (ありがたいことに、当面はその必要がありません)。

テスト 7 のデータ ビンは同じです。上に投稿したコードを参照してください。そして、リクエストを受け取るたびに、それを書き留めます

携帯電話で送られてくる言葉を入力するのは本当に難しいです。リクエストを受け取るたびに、リクエストされた値をライブラリに書き込みます。ライブラリ内のレコードは正常ですが、セッションがまだ保存されているか、カスタム変数が保存されているかにかかわらず、memcache への書き込みが不完全であることがわかります。構成のバージョンとファイルを投稿しましたが、構成に問題があるかどうかはわかりません。設定に問題があるかどうかを確認してください。

また、手元に memcache 環境はありますか? 問題がなければ、使用しているバージョンを送っていただけますか?私のバージョンに問題がありますか? 3q

考慮すべき点は、ブラウザがほぼ同時に同時リクエストを行うということです。新しい値は、数ミリ秒前に読み取られた値に基づいて設定されます。ただし、この間に新しい値が正常に挿入される可能性は十分にあります。再度挿入すると、以前に書き込まれた新しい値は読み出されず、すぐに上書きされます。したがって、データが失われるのは正常なことです。
クライアントまたはサーバー上でテストを作成して、毎回 1 秒間一時停止した場合の影響を同時並行性と比較できます。

テスト ページからどのような値が返されるかについてまだ述べていませんか?
プログラムによっては、結果 123456 が必要です。
js はスムーズにロードされます。同時実行性の問題は発生しないはずです。データをチェックするときは、主にセッション ID をチェックします

どこで更新され解放されるかを確認する必要はありません

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


有効期限は 60 秒です

60 の値をより大きくすることができます。

テスト ページからどのような値が返されるかについてまだ述べていませんか?
プログラムによっては、結果 123456 が必要です。
js はスムーズにロードされます。同時実行性の問題は発生しないはずです。データを確認するときは、主にセッションIDを確認してください
はい、論理的には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值。

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

我也出现这个问题

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。