session工作原理、存儲目錄、垃圾回收、存儲優化等研究

一、Session工作原理

    http協議是WEB服務器與客戶端(瀏覽器)相互通信的協議,它是一種無狀態協議,服務器響應完之後就失去了與瀏覽器的聯繫。所謂無狀態,指的是不會維護http請求數據,http請求是獨立的,不持久的。而越來越複雜的WEB應用,需要保存一些用戶狀態信息。這時候,Session這種方案應需而生。PHP從4.1開始支持Session管理。

    session的工作原理:用戶在客戶端登陸網站時,被訪問的PHP頁面使用session_start()函數啓動session,產生客戶端唯一標識session_id(使用函數session_id()設置),當請求下一個頁面時,PHP程序通過兩種方式來獲取客戶端的session_id:一種是將session_id自動加入到GET或POST的URL中,默認情況下,變量名爲PHPSESSD(在php.ini中的設置session name=PHPSESSD);另一種方式是通過cookie,將session_id 保存在cookie中,如下圖所示的紅色框,客戶端的PHPSESSID的值與服務端的sess_後綴的值是相等的。由此可以看出,服務端產生客戶端唯一標誌的sessionid。

 

客戶端:

服務端:



      保存在服務器端的session數據,不是保存在服務器端的內存中,而是保存在文件或數據庫中。默認情況下配置服務器端的php設置(php.ini),通過文件的方式保存(session save_hander=files),使用讀寫文件的方式保存session數據,session文件保存的目錄由session save_path指定,如:文件名爲 sess_c72665af28a8b14c0fc61afeb59b51b,文件中的數據即是序列化之後的session數據,如果訪問量大,還可能產生多個session文件,這時可以設置分級目錄保存session文件

session save_path="N;/save_path"(N爲分級的級數,save_path爲開始目錄)。對session數據寫入時,PHP獲得客戶端的session d,然後跟隨session d到指定的session文件保存目錄中找到相應的session文件,不存在則創建,最後將數據序列化之後寫入文件。讀取session數據是類似的流程,對讀出來的數據需要進行解序列化,生成相應的session變量

      用戶在瀏覽網頁時,用戶的session會話開始,如果客戶端的瀏覽器支持cookie,將會建立一個session的id到cookie,這個唯一的id由PHP隨機生成,並且使用md5加密。客戶端的cookie應該叫做session cookie,因爲這個cookie是不會寫入客戶端的硬盤中,當一個session期結束的時候,該cookie也自動刪除,如果客戶端的瀏覽器禁用cookie,session的id將會放入URL中進行傳遞.
session id內存放着用戶的相關信息,如:用戶認證、認證時間、用戶權限和其他信息。session文件的結構爲: 變量名|類型:長度:值,多個變量用逗號分割

二、Session的存儲目錄

session是以文本文件形式保存在一個文件中sess_*,linux下默認存儲在/tmp文件夾下,window默認存儲在c:\windows\Temp下或C:\Documents and Settings\kuco\Local Settings\Temp\下。

PHP配置文件中session.save_path負責session文件的存放位置。如果沒有配置則不會生成session文件,如果配置的目錄session.save_path = "E:/ttt"不存在,則會報錯:

Warning: session_start() [function.session-start]: open(E:/ttt\sess_e0b64760c92422d81c1d6202b66884f6, O_RDWR) failed: No such file or directory (2) in E:\APMServ5.2.6\www\htdocs\session\index.php on line 13
 Warning: Unknown: open(E:/ttt\sess_e0b64760c92422d81c1d6202b66884f6, O_RDWR) failed: No such file or directory (2) in Unknown on line 0
 Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (E:/ttt) in Unknown on line 0

 

所以,如果需要生成session文件,需要檢查配置文件.如果沒有配置目錄,則請將php.ini中的“;session.save_path = "/tmp"” 改爲“session.save_path = "E:/yourdir"”,並切記在E盤根目錄下新建,名爲yourdir的文件夾。設置完成後需要重啓服務,然後設置生效。可以再php文件中測試,是否設置成功。

 

    $sessionpath = session_save_path();
    if (strpos ($sessionpath, ";") !== FALSE)
      $sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);

    //獲取當前session的保存路徑
    echo $sessionpath;


如果服務器是遠程連接的,不在本地,不方便更改php配置文件,可以再程序中重置session目錄,要想改變SESSION存儲路徑,必須在SESSION啓動之前使用改變SESSION路徑函數。。

   session_save_path("D:/www/session/rrr");
   session_start();


附:通過phpinfo()資料的獲取也可以得到session文件的位置如:

session.cache_expire爲session緩存在客戶端的過期時間(適用於那種更新較少的網站使用)

session.gc_maxlifetime爲session的有效期(默認爲1440秒即24分鐘,也就是說,客戶端超過24分鐘沒有刷新,當前session就會失效。)

session.save_path爲session在服務端的存儲路徑

三、Session的垃圾回收機制

    本節原本打算講session的有效時間(或生命週期session lifetime),但是,如果理解了session的垃圾回收機制,那麼對session的生命週期自然就明白了。

    1、session“回收”何時發生?

    由於PHP的工作機制,她並沒有一個daemon線程,來定時的掃描session信息並判斷其是否失效。當一個有效請求發生時,PHP會根據全局變量 session.gc_probability/session.gc_divisor(同樣可以通過php.ini或者ini_set()函數來修改) 的值,來決定是否啓動一個GC(Garbage Collector 中文意思是:垃圾收集工,即垃圾回收)。默認情況下,session.gc_probability = 1,session.gc_divisor =1000,也就是說有0.1%的可能性會啓動GC,也就是說是否啓動GC是由一個概率計算得來的,每1000個用戶調用session_start()的時候,就有一個會執行一次垃圾回收機制將磁盤上的session文件刪除。 

    注意:一般對於一些大型的門戶網站,建議將session.gc_divisor調大一點,減少開銷,接下來,我通過一個例子演示下,如何配置才能讓調用gc(垃圾回收)進程呢!

通過配置php.ini文件,修改以下幾個信息:

■ session.gc_maxlifetime = 60//當session文件在60s後還沒有被訪問的話,則該session文件將會被視爲“垃圾文件”,並且等待gc(垃圾回收)進程的調用的時候被清理掉

■ session.gc_probability = 1000

因爲gc進程被調用的概率是通過gc_probability/gc_divisor 計算得來的,這裏我將session.gc_probability改成1000,而session.gc_divisor 默認情況下也是1000。則gc進程在每次執行session_start()函數的時候都會被調用到。

以下我通過截圖簡單的說明下:

 

 

      我開啓三個會話,則創建三個對應的session文件,當每個文件在30秒內都沒被調用的話,就會被當成是“垃圾文件”,等到gc進程調用的時候,“垃圾文件”就會被unlink,因爲之前我已經通過修改php.ini配置文件,將gc被調用的概率改成百分百,所以接下來,如果我重新使用任何一個瀏覽器刷新下頁面的時候,三個session文件,應該只剩下一個了

     2、session過期,但session文件未被刪除

    這種情況是經常存在的,尤其是對於PHP技術開發人員,如下面的陳述:

    某網站的會員登錄網站後,24分鐘內都沒有刷新,但是24分鐘後仍然可以訪問,而不要求輸入賬號、密碼重新登錄。

這個現象就是session過期,但session文件未被刪除,即session過期,GC未啓動刪除session文件,此時session文本文件將被重新修改,即session文件的“最後修改時間”變化了,但session文件內容仍然沒變化,在PHP環境中我們可以通過$_SESSION全局變量獲取到

四、Session的存儲優化

    session的存儲機制,默認的是保存在files中,即以文件的方式保存session數據,在php中主要根據php.ini的配置session.save_handler來選擇保存session的方式。如果併發訪問很大,或者說session建立太多,目錄下存在大量session文件,同一目錄下文件數過多導致I/O性能下降,並且可能導致受到攻擊最終出現文件系統錯誤。所以必須對其優化

    1、多級目錄保存session文件

php.ini裏面Session設置部分中有這樣一項:

session.save_path = "N;MODE;/path"

    這項設置提供給我們可以給session存放目錄進行多級散列,其中“N”表示要設置的目錄級數,“MODE”表示目錄的權限屬性,默認爲600,在WINDOWS上基本是不用設置的,*NIX上也可以不用設置,後面的“/path”表示session文件存放的根目錄路徑,比如我們設置爲下面的格式

session.save_path = "2;/tmp/phpsession"


       上面的設置表示我們把/tmp/phpsession目錄作爲php的session文件存放根目錄,在該目錄下進行兩級目錄散列,每一級目錄分別是0-9和a-z共36個字母數字爲目錄名,這樣存放session的目錄可以達到36*36個,相信作爲單臺服務器來說,這是完全夠用了,如果說您的系統架構設計爲多臺服務器共享session數據,可以把目錄級增加到3級或者更多。
  需要注意的是,php自己並不會自動創建子目錄,需要您自己動手去創建,網上找到這樣的自動創建目錄的代碼,大家可以做個參考。下面的代碼自動創建3級子目錄,可以自己動手根據需要進行修改。或者使用ext/session目錄下的mod_files.sh腳本創建。

<?php
set_time_limit(0);
$string = '0123456789abcdefghijklmnopqrstuvwxyz';
$length = strlen($string);
function makeDir($param)
{
    if(!file_exists($param)) {
        makeDir(dirname($param));
        mkdir($param);
    }
} 
for($i = 0; $i < $length; $i++) {
    for($j = 0; $j < $length; $j++) {
        for($k = 0; $k < $length; $k++) {
            makeDir($string[$i].'/'.$string[$j].'/'.$string[$k]);
        }
    }
}
?>

值得注意的是:當N>0時自動垃圾回收將會失效,這個事後要建立一個自動回收機制,本文不做講述了。
 

   2、保存到數據庫

        見 session存儲優化之基於mysql的存取

(未完,待續)

 

參考文檔:

1、PHP session詳解

2、深入理解session過期機制

PHP視頻教程

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