首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 多伺服器環境下 Session 共享與並發解決方案

     編輯:PHP 綜合知識

問題背景

預設 PHP Session 存儲於本機檔案 (session.save_handler = files),多台 Web 伺服器無法共享 Session,導致使用者在負載平衡切換伺服器時登入狀態丟失。

方案比較

方案原理優點缺點適用場景
Nginx IP Hash / Sticky Session同一 Client 固定導向同一後端零程式碼修改伺服器下線 Session 遺失、負載不均小型、可容忍短暫掉線
資料庫共享 (MySQL/PostgreSQL)自訂 Session Handler 寫入 DB持久化、可查詢、ACID寫入延遲、連線池壓力中型、需稽核追蹤
Redis / Memcached記憶體 Key-Value,TTL 自動過期高效能、原子操作、叢集擴展資料非持久、需 HA 設計高併發、大流量 (推薦)
NFS/GlusterFS 共享檔案系統掛載共享目錄存放 session 檔案相容原生 files handler單點故障、延遲高、鎖競爭舊系統快速遷移

Redis 共享 Session 實作 (推薦)

安裝擴充

apt install php-redis
# 或 pecl install redis

php.ini 設定

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=PASSWORD&database=0&prefix=PHPSESSID:"
# 叢集/哨兵
# session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=1"
session.gc_maxlifetime = 1440

驗證

";
echo "Server: " . gethostname() . "
"; $_SESSION['counter'] = ($_SESSION['counter'] ?? 0) + 1; echo "Counter: " . $_SESSION['counter'];?>

於多台伺服器瀏覽,Counter 應同步遞增。

進階:自訂 Session Handler (資料庫範例)

pdo = $pdo; }
    public function open($path, $name): bool { return true; }
    public function close(): bool { return true; }
    public function read($id): string|false {
        $stmt = $this->pdo->prepare('SELECT data FROM sessions WHERE id = ? AND expiry > ?');
        $stmt->execute([$id, time()]);
        return $stmt->fetchColumn() ?: '';
    }
    public function write($id, $data): bool {
        $expiry = time() + ini_get('session.gc_maxlifetime');
        $stmt = $this->pdo->prepare('INSERT INTO sessions (id, data, expiry) VALUES (?,?,?)
            ON DUPLICATE KEY UPDATE data=?, expiry=?');
        return $stmt->execute([$id, $data, $expiry, $data, $expiry]);
    }
    public function destroy($id): bool {
        return $this->pdo->prepare('DELETE FROM sessions WHERE id = ?')->execute([$id]);
    }
    public function gc($maxlifetime): int|false {
        return $this->pdo->prepare('DELETE FROM sessions WHERE expiry < ?')->execute([time()]);
    }
}

// 註冊
$handler = new DbSessionHandler($pdo);
session_set_save_handler($handler, true);
session_start();

Session 並發鎖問題

預設 PHP 為同一 Session ID 加鎖 (阻塞並發請求)。高併發場景可:

  • session_write_close() 盡早釋放鎖 (資料已寫入)
  • 使用 session.save_handler = redis (Redis 內建非阻塞或可配置)
  • 唯讀請求用 session_start(['read_only' => true]) (PHP 7+)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved