首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

PHP 多伺服器共享 Session:將 Session 寫入 MySQL 實現統一登入

     編輯:MySQL 資料庫相關知識

問題背景

多子域/多伺服器架構下,用戶在 A 系統登入後跳轉到 B 系統需重新登入。核心原因:各伺服器獨立產生 Session ID、Session 檔案分散在本地檔案系統。

解決思路:雙重共享

  1. Client 端共享 Session ID:設定 Cookie domain 為主域 (如 .example.com),所有子域自動攜帶同一 PHPSESSID。
  2. Server 端共享 Session 資料:將 Session 存入中央 MySQL,所有 Web 節點讀寫同一張表。

資料庫表結構


CREATE TABLE `sess` (
  `sesskey` VARCHAR(32) NOT NULL DEFAULT '',
  `expiry`  BIGINT(20) NOT NULL DEFAULT '0',
  `data`    LONGTEXT NOT NULL,
  PRIMARY KEY (`sesskey`),
  KEY `expiry` (`expiry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

PHP 實作核心:自定義 Session Handler

使用 session_set_save_handler() 覆寫六個回調:open, close, read, write, destroy, gc。


close();
        return true;
    }

    static function read($sesskey) {
        $sql = "SELECT `data` FROM `sess` WHERE `sesskey`=" . self::$db->qstr($sesskey) . " AND `expiry`>=" . time();
        $rs = self::$db->execute($sql);
        if ($rs && !$rs->EOF) {
            $v = $rs->fields[0];
            $rs->close();
            return $v;
        }
        return '';
    }

    static function write($sesskey, $data) {
        $arr = array(
            'sesskey' => $sesskey,
            'expiry'  => time() + MY_SESS_TIME,
            'data'    => $data
        );
        self::$db->replace('sess', $arr, 'sesskey', true); // ADODB REPLACE
        return true;
    }

    static function destroy($sesskey) {
        $sql = "DELETE FROM `sess` WHERE `sesskey`=" . self::$db->qstr($sesskey);
        self::$db->execute($sql);
        return true;
    }

    static function gc($maxlifetime = null) {
        $sql = "DELETE FROM `sess` WHERE `expiry`<" . time();
        self::$db->execute($sql);
        // 定期整理碎片
        self::$db->execute("OPTIMIZE TABLE `sess`");
        return true;
    }
}

// 使用範例 (需 ADODB)
require_once('adodb/adodb.inc.php');
$db = ADONewConnection('mysqli');
$db->connect('127.0.0.1', 'root', 'pass', 'sess_db');

$sess = new My_Sess($db);
$sess->init();

$_SESSION['user'] = 'admin';
print_r($_SESSION);
?>

效能考量與進階方案

  • 高併發下頻繁讀寫 MySQL 會成瓶頸。
  • 進階方案:Memory-based Session Server (C/Java 寫多線程 Hash Map + Socket 協議),Session 駐留記憶體,微秒級讀寫。
  • 配合 負載均衡器 Sticky Session 或 Redis Cluster 做分散式 Session 存儲。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved