1. 程式人生 > >session共享原理以及PHP 實現多網站共享用戶SESSION 數據解決方案

session共享原理以及PHP 實現多網站共享用戶SESSION 數據解決方案

偽造 分布式應用 use 應用服務 php配置 登錄系統 文章 mem 火墻

參考自:

http://www.cnblogs.com/qulinke/articles/6003049.html

https://segmentfault.com/q/1010000005788476

總而言之:session共享的關鍵技術點在於兩點:

1. 讓客戶端訪問同一個sessionId,
2. 讓所有域名對應的服務器訪問的Session的數據的位置必須一致

下面重點講講實現,Session共享相對於Cookie共享來說較為復雜,因為情況相對於比較多,大概有四種情況

同服務器同域名,同服務器不同域名,不同服務器同域名,不同服務器不同域名。

同服務器同域名(不同子域名)的實現:

實現比較簡單,直接找一份網上的demo(圖侵刪),直接按照以下的代碼實現即可。

技術分享圖片

同服務器不同域名的實現:

這種情況下,我們再次明確實現session共享的關鍵技術點,同一個sessionId同樣的數據源
不同域名的話就要先將cookie(‘PHPSESSID‘)跨域,然後通過這個sessionid值從MySQL數據庫或者Nosql中取得對應數據,這樣就實現了同服務器不同域名的session共享。
首先是cookie跨域:

然後是Redis數據共享,key就是session_id,值就是需要共享的數據,使用到的就是Redis的集群技術,實例過於復雜,感興趣的可以直接去文章查看:redis cluster 集群 安裝 配置 詳解

不同服務器同域名的實現:

此種情況與<同服務器不同域名的實現>差不多,但在此種情況下不需要考慮cookie跨域的問題了,那麽著重實現數據共享即可,同上,key為sessio_id,值為具體的數據值,參考文章同上redis cluster 集群 安裝 配置 詳解。

不同服務器名不同域名的實現:

此種情況和<同服務器不同域名的實現>圖探訪,也是要實現兩個目標,同一個sessionId同樣的數據源。不同域名的話就要先將cookie(‘PHPSESSID‘)跨域,然後通過這個sessionid值從MySQL數據庫或者Nosql中取得對應數據,這樣就實現了同服務器不同域名的session共享。

首先是cookie跨域:

技術分享圖片

此方法有一個關鍵也即php如何利用P3P頭實現跨域設置cookie

具體可參考 http://blog.csdn.net/lhorse003/article/details/72614845

然後是Redis數據共享,key就是session_id,值就是需要共享的數據,使用到的就是Redis的集群技術,實例過於復雜,感興趣的可以直接去文章查看:redis cluster 集群 安裝 配置 詳解。

我們發現四種情況下的解決方式都差不多,第2種情況<同服務器不同域名的實現>和第四種情況<不同域名不同服務器的實現>更是基本一樣,其中的核心思想無非就是解決兩個根源問題,session_id大家需要獲取同一個,有一個共享的數據源需要給大家獲取。

搞明白了這兩點,Session共享的SSO也就水到渠成了。

以下看PHP 實現多網站共享用戶SESSION 數據解決方案

PHP服務器有多臺,用nginx做負載均衡,這樣同一個IP訪問同一個頁面會被分配到不同的服務器上,如果session不同步的話,就會出現很多問題,比如說最常見的登錄狀態,下面提供了幾種方式來解決session共享的問題:

1、不使用session,換用cookie

session是存放在服務器端的,cookie是存放在客戶端的,我們可以把用戶訪問頁面產生的session放到cookie裏面,就是以cookie為中轉站。你訪問web服務器A,產生了session然後把它放到cookie裏面,當你的請求被分配到B服務器時,服務器B先判斷服務器有沒有這個session,如果沒有,再去看看客戶端的cookie裏面有沒有這個session,如果也沒有,說明session真的不存,如果cookie裏面有,就把cookie裏面的sessoin同步到服務器B,這樣就可以實現session的同步了。

說明:這種方法實現起來簡單,方便,也不會加大數據庫的負擔,但是如果客戶端把cookie禁掉了的話,那麽session就無從同步了,這樣會給網站帶來損失;cookie的安全性不高,雖然它已經加了密,但是還是可以偽造的。

2、session存在數據庫(MySQL等)中

PHP可以配置將session保存在數據庫中,這種方法是把存放session的表和其他數據庫表放在一起,如果mysql也做了集群了話,每個mysql節點都要有這張表,並且這張session表的數據表要實時同步。

說明:用數據庫來同步session,會加大數據庫的IO,增加數據庫的負擔。而且數據庫讀寫速度較慢,不利於session的適時同步。

3、session存在memcache或者Redis中

memcache可以做分布式,php配置文件中設置存儲方式為memcache,這樣php自己會建立一個session集群,將session數據存儲在memcache中。

說明:以這種方式來同步session,不會加大數據庫的負擔,並且安全性比用cookie大大的提高,把session放到內存裏面,比從文件中讀取要快很多。但是memcache把內存分成很多種規格的存儲塊,有塊就有大小,這種方式也就決定了,memcache不能完全利用內存,會產生內存碎片,如果存儲塊不足,還會產生內存溢出。

4、nginx中的ip_hash技術能夠將某個ip的請求定向到同一臺後端,這樣一來這個ip下的某個客戶端和某個後端就能建立起穩固的session,ip_hash是在upstream配置中定義的:

技術分享圖片
   upstream nginx.example.com
       { 
                server 192.168.74.235:80; 
                server 192.168.74.236:80;
                ip_hash;
       }
       server
       {
                listen 80;
                location /
                {
                        proxy_pass
                       http://nginx.example.com;
                }
    }
技術分享圖片

ip_hash是容易理解的,但是因為僅僅能用ip這個因子來分配後端,因此ip_hash是有缺陷的,不能在一些情況下使用:
1.nginx不是最前端的服務器。

ip_hash要求nginx一定是最前端的服務器,否則nginx得不到正確ip,就不能根據ip作hash。譬如使用的是squid為最前端,那麽nginx取ip時只能得到squid的服務器ip地址,用這個地址來作分流是肯定錯亂的。
2.nginx的後端還有其它方式的負載均衡。

假如nginx後端又有其它負載均衡,將請求又通過另外的方式分流了,那麽某個客戶端的請求肯定不能定位到同一臺session應用服務器上。這麽算起來,nginx後端只能直接指向應用服務器,或者再搭一個squid,然後指向應用服務器。最好的辦法是用 location作一次分流,將需要session的部分請求通過ip_hash分流,剩下的走其它後端去。

5、upstream_hash
為了解決ip_hash的一些問題,可以使用upstream_hash這個第三方模塊,這個模塊多數情況下是用作url_hash的,但是並不妨礙將它用來做session共享。沒試過真心的不明白

補充:memcached簡單的介紹

一、概念

Memcached是danga.com(運營LiveJournal的技術團隊)開發的一套分布式內存對象緩存系統,用於在動態系統中減少數據庫負載,提升性能。

二、適用場合

1. 分布式應用。由於memcached本身基於分布式的系統,所以尤其適合大型的分布式系統。

2. 數據庫前段緩存。數據庫常常是網站系統的瓶頸。數據庫的大並發量訪問,常常造成網站內存溢出。當然我們也可以使用hibernate的緩存機制。但memcached是基於分布式的,並可獨立於網站應用本身,所以更適合大型網站進行應用的拆分。

3. 服務器間數據共享。舉例來講,我們將網站的登錄系統、查詢系統拆分為兩個應用,放在不同的服務器上,並進行集群,那這個時候用戶登錄後,登錄信息如何從登錄系統服務器同步到查詢系統服務器呢?這時候,我們便可以使用memcached,登錄系統將登錄信息緩存起來,查詢系統便可以獲得登錄信息,就像獲取本地信息一樣。

三、不適用場合

那些不需要“分布”的,不需要共享的,或者幹脆規模小到只有一臺服務器的應用,memcached不會帶來任何好處,相反還會拖慢系統效率,因為網絡連接同樣需要資源

解決方案,使用memcached做為session的存儲,memcached服務器設置在和nginx同一臺Linux主機上。

解決過程,

兩臺apache的主機IP分別是 192.168.74.235192.168.74.236

Nginx主機IP是192.168.74.131

Memcached主機的IP是192.168.74.131

在192.168.74.131 安裝memcached,並且啟動

以一臺為例192.168.74.236,安裝php及php對memcached的依賴庫yuminstall memcached-devel.i686 libmemcached-devel.i686 php-pecl-memcache.i686

配置php.ini

session.save_handler= memcache

session.save_path= "tcp://192.168.74.131:11211"

或者(以下兩個沒有嘗試)

1.某個目錄下的 .htaccess :

php_value session.save_handler "memcache"
php_value session.save_path "tcp://IP:11211"

2.在某個一個應用中:

ini_set("session.save_handler", "memcache");
ini_set("session.save_path", "tcp://IP:11211");

同時一定要把下面的;session.save_path= "/var/lib/php/session" 註釋掉

同時把extension=memcache.so 打開

重啟一下 apache,查看 phpinfo 中的 "Registered save handlers" 會有 "files usermemcache" 這3個可用,如果有就證明裝好了

Memcached服務器執行及結果

[[email protected]Git ~]# memcached-tool127.0.0.1:11211

# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM

在236機器上添加下面的php文件

<?php

session_start();

if (!isset($_SESSION[‘TEST‘])) {

$_SESSION[‘TEST‘] = time();

}

$_SESSION[‘TEST3‘] = time();

print $_SESSION[‘TEST‘];

print "<br><br>";

print $_SESSION[‘TEST3‘];

print "<br><br>";

print session_id();

?>

然後去memcached服務器上執行

[[email protected] ~]# memcached-tool127.0.0.1:11211

# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM

1 80B 0s 1 0 no 0 0 0

這樣應該就算可以把session寫到memcached服務器上了。

總結下:

1. 防火墻問題,很多連接局域網服務器失敗都是防火墻引起的

2. 依賴沒有安裝完畢,一開始使用memcached總失敗,因為我沒有安裝php-memcached這樣的擴展庫

session共享原理以及PHP 實現多網站共享用戶SESSION 數據解決方案