PHP SESSION機制原理和CodeIgniter3.0 Session併發衝突問題

 

一、機制原理

Session(英文翻譯爲“會話”),可以在瀏覽器和服務器之間建立持續的會話訪問。在會話管理期間,Session會在服務器上維護一張登記表,記錄(session_id, ip_address, user_agent, timestamp, data)等信息,除了data用於服務器端編程記錄信息外,其他都是Session自動維護的。使用Session,依據session id和會話表,在服務器端進行編程,可以實現一次登錄身份,短期持續可靠的訪問。

1、當用戶User登錄身份時,通過在瀏覽器中輸入用戶名和密碼進行登錄,服務器編程通過session_start();啓用會話,自動調用session_regenerate_id(false);產生並記錄下session id和timestamp等信息。這個session id就像一個臨時身份證(通常會設置過期時間),通過cookie(COOKIE就是)返回給瀏覽器,並在瀏覽器下次訪問時自動攜帶。如果之前帶有session id,Session會檢查是否過期,如果過期將爲訪問用戶重新生成一個session id,如果沒有過期,將更新其它自動維護的信息。

2、當用戶User登錄身份後,服務器編程可使用Session寫入該登錄用戶的user_id等常用信息,這些信息會被存入data。這樣下次用戶訪問時,可以編程通過$_SESSION[]獲取這些信息,獲取信息時Session會自動查詢會話表。

3、當用戶User註銷身份時,服務器編程使用session_destroy();終止會話,自動調用session_regenerate_id(true),重新一個session_id,並刪除編程保存的data信息。如果用戶非正常退出,session會話信息仍然會保存在服務器端,當用戶再次訪問時,如果身份信息沒有過期,將自動登錄。如果身份信息已經過期,編程要求用戶重新登錄。

其它:也可以在登錄時,使用session_regenerate_id(true);重新產生一個session id。

二、併發衝突       

在 CodeIgniter 之前的版本中,Session 類並沒有實現鎖機制,請求是非阻塞的。(requests were non-blocking)。而在CodeIgniter3.0中,Session實現的'files','datebase','memcached'和'redis'驅動中,使用了鎖機制,並且在關閉Session時才進行釋放。而在通常情況下,程序沒有設計主動來關閉SESSION,默認會在php文件執行完畢後關閉Session,進行鎖的釋放,大大加劇了衝突的程度。所以,在使用session時要解決(準確的說是緩和)衝突,只有在使用完Session後,調用session_destroy();和session_write_close();纔會主動關閉Session,緩和併發衝突。

在處理 session 時使用非阻塞的請求同樣意味着不安全,因爲在一個請求中修改 session 數據(或重新生成 Session ID)會對併發的第二個請求造成影響。這是導致很多問題的根源, 同時也是爲什麼 CodeIgniter 3.0 對 Session 類完全重寫的原因。

主要存在的兩種場景:

(1)WEB頁面中使用了大量AJAX請求。當網站大量使用了ajax請求時,在多個請求中都使用了session的情況下,由於讀取SESSION時會加鎖,從而發生衝突。

(2)大量API請求中,啓用了Session,並且在APP中保持了COOKIE。公司開發的系統中,使用了nginx分佈式部署,爲了解決SESSION同步,有采用了數據庫持久化的方式。後來,客戶反映數據庫中的SESSION持久化表數據量太大,系統響應變慢。通過查看log發現:由於訪問API的Android終端,支持持久化SESSION的COOKIE數據,造成類似場景(1)中的情景。

 

三、解決辦法

1、使用session的情況

如場景一,可以在使用session完畢後,調用session_write_close();關閉會話,釋放加鎖

2、不使用session的情況

如場景二,只有在API的任何地方都不使用SESSION,才能最徹底地杜絕session併發衝突。(通過研究CI框架Session實現機制發發現,只要SESSION類實例化,就會造成會話數據的寫入。)

(1)從application/config/autoload.php中,去除session類和間接加載session類的庫類的自動加載。

(2)在使用的任何類庫中,都不要加載session類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章