PHP是如何實現多伺服器SESSION共享
點選進入“PHP開源社群”
免費獲取進階面試、文件、影片資源
為什麼要session共享
現在稍微大一點的網站基本上都有好幾個子域名,比如www.feiniu.com, search.feiniu.com, member.feiniu.com,這些網站如果需要共用使用者登入資訊,那麼就需要做到session共享,當然前提是有相同的主域。
PHP的session原理
客戶端訪問php頁面,執行session_start,生成session_id,一般我們是把session_id儲存到cookie上,session內容儲存在服務端,客戶端訪問訪問不同的頁面都會把session_id傳到服務端,通過session_id來獲取session內容。
流程是這樣,可是不同的伺服器會對同一個客戶端產生不同的session_id,這樣的話不同伺服器就不能得到相同的session內容了。而且PHP 預設的 SESSION 資料都是分別儲存在本伺服器的檔案系統中。
所以我們要解決session共享,就必須解決 兩個問題 :
1. 多臺伺服器用同一個session_id
這個比較容易解決,只要在php中設定存session_id的cookie域名
為網站主域就可以了
開啟PHP.ini, 設定session.cookie_domain = .feiniu.com,
當然也可以在php程式碼當中
設定ini_set("session.cookie_domain","feiniu.com");
2. 多臺伺服器用同一個session_id訪問到相同的session內容
要實現這點,就必須把session內容儲存到讓所有伺服器都能訪問到的地方,
php的session內容是預設儲存到本伺服器的檔案中的,
一般的解決方案是存入資料庫,memcache或者redis這種快取伺服器,
當然用預設的檔案儲存方式也可以,用NFS統一儲存。
3. 如何選擇儲存引擎
預設檔案儲存: 這種方式的session銷燬依託於php垃圾收集器,在高併發或銷燬時間較長的情況下,在SESSION目錄下產生大量檔案,當然可以設定分級目錄進行 SESSION 檔案的儲存。
這會導致兩個問題:第一、查詢檔案慢;第二,每個目錄下可容納的檔案數是有限的,可能會導致新SESSION儲存失敗。
1) 設定Session儲存的引擎,php.ini 檔案
[Session]
session.save_handler = files
session.save_path = /data/SessionLogs
2)預設情況下的Session的使用
<?php
/**
* session的使用
* 預設情況(不更改session.save_handle引數時),是儲存在檔案file中的
* 預設情況下使用session的情況(使用者24分鐘內沒有重新整理操作會過期)
* 每個使用者對應唯一session_id,每一個session_id對應伺服器中儲存的一個session檔案,這個檔案中儲存了當前session_id的資訊,比如下面,就儲存了name和age的鍵值
*/
session_start();
echo session_id();
echo "<br>";
$_SESSION['age'] = 26;
$_SESSION['name'] = 'xiaobudiu';
var_dump($_SESSION);
3)在伺服器中儲存的形式是這樣的
資料庫儲存: 把Session儲存在資料庫裡可以防止Session資料被垃圾收集器刪除,可以固化儲存session資料。但是用資料庫來同步session,會加大資料庫的IO,增加資料庫的負擔。而且資料庫讀寫速度較慢,不利於session的適時同步。
memcache儲存:
以這種方式來同步session,不會加大資料庫的負擔,並且安全性比較高,把session放到記憶體裡面,比從檔案中讀取要快很多。
但是memcache把記憶體分成很多種規格的儲存塊,有塊就有大小,這種方式也就決定了,memcache不能完全利用記憶體,會產生記憶體碎片,如果儲存塊不足,還會產生記憶體溢位
那些不需要“分佈”的,不需要共享的,或者乾脆規模小到只有一臺伺服器的應用,memcached不會帶來任何好處,相反還會拖慢系統效率,因為網路連線同樣需要資源。
Redis儲存:
與memcache相比,redis訪問稍稍慢一點點,好處是: redis支援的資料結構較多,可以儲存陣列或物件,而memcache只能儲存字串。
在session機器重啟的情況下,memcache所有使用者都必須重新獲得 session,而redis不會 在突然湧來大量使用者產生了很多資料把儲存 session 的機器記憶體佔滿了的情況下,memcache 會罷工,所有 key 都沒過期的話就不停的覆蓋最後寫入的資料,而 redis 只是會變慢 ,不會影響程式的邏輯。
1) 設定php.ini 檔案中的session.save_handle 和session.save_path
session.save_handler = Redis
session.save_path = "tcp://localhost:6379"
注1:如果連線的是遠端redis,需要將localhost換成對應的遠端ip地址。像這樣
session.save_handler = Redis
session.save_path = "tcp://47.94.203.119:6379"
注2:如果為redis已經添加了auth許可權(requirpass),session.save_path項則應該這樣寫
session.save_handler = Redis
session.save_path = "tcp://47.94.203.119:6379?persistent=1&database=10&auth=myredisG506"
2)使用redis儲存session資訊
<?php
/**
* 將session儲存在redis中
*/
session_start();
echo session_id();
echo "<br>";
$_SESSION['age'] = 26;
$_SESSION['name'] = 'xiaobudiu';
$_SESSION['sex'] = 'man';
var_dump($_SESSION);
在redis上是以這樣的形式進行儲存的
使用Redis儲存Session,並設定Session會話存活時間以及Session中某一元素存活時間
封裝session類 b.php
<?php
/**
* session控制類
*
*/
class Session
{
function __construct($lifetime = 3600)
{
//初始化設定session會話存活時間
ini_set('session.gc_maxlifetime',$lifetime);
}
/**
* 設定當前會話session的key-value
* @param String $name session name
* @param Mixed $data session data
* @param Int $expire 有效時間(秒)
*/
function set($name, $data, $expire = 600)
{
$session_data = array();
$session_data['data'] = $data;
$session_data['expire'] = time()+$expire;
$_SESSION[$name] = $session_data;
}
/**
* 讀取當前會話session中的key-value
* @param String $name session name
* @return Mixed
*/
function get($name)
{
if(isset($_SESSION[$name])) {
if($_SESSION[$name]['expire'] > time()) {
return $_SESSION[$name]['data'];
}else{
self::clear($name);
}
}
return false;
}
/**
* 清除當前session會話中的某一key-value
* @param String $name session name
*/
function clear($name)
{
unset($_SESSION[$name]);
}
/**
* 刪除當前session_id對應的session檔案(清空當前session會話儲存)
*/
function destroy()
{
session_destroy();
}
}
session類的使用:d.php
<?php
require_once 'b.php';
session_start();
$session = new Session();
$session->set('wan','kkkk',1966);
$session->set('name','xiaobudiu');
$session->set('age',26);
$session->set('sex','man');
//輸出當前會話的session儲存資料
var_dump($_SESSION);
//unset掉某一個session屬性
//$session->clear('name');
//刪除當前session_id對應session檔案
//$session->destroy();
//echo $session->get('sex');
redis中顯示:
*宣告:本文於網路整理,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜
END
PHP開源社群
掃描關注 進入”PHP資料“
免費獲取進階
面試、文件、影片資源
點選“檢視原文”獲取更多
- MySQL中 8 種常見的 SQL 錯誤用法
- 一起來用用 php的生成器 yield
- PHP 記憶體溢位 ?如何解決呢 ?
- 為速度而生:PHP 與 Golang 的合體 —— RoadRunner
- PHP是如何實現訊息佇列(RabbitMQ)的
- 現在應該開始使用的 10 個 PHP 8.1 功能
- 談下php如何縮短介面響應時間
- PHP是如何實現多伺服器SESSION共享
- MySQL間隙鎖死鎖問題
- Hook技術簡介
- 你會使用 Linux 編輯器 Vim 嗎?
- php實現圖書管理系統詳細介紹
- 面試官問:Redis 快取都有哪些異常,各自有哪些解決方案
- 面試被問到:關於php檔案包含你瞭解多少?
- 一張小圖看盡 Nginx
- php快速搭建swoole玩轉協程
- Laravel 使用Guzzle執行HTTP請求
- PHP中的異常處理機制
- 基於redis的分散式鎖詳解
- 如何通過查原始碼的方式解決程式設計中遇到的問題?