當(dāng)前位置: 首頁(yè)IT技術(shù) → PHP session回收機(jī)制

PHP session回收機(jī)制

更多

由于PHP的工作機(jī)制,它并沒(méi)有一個(gè)daemon線程,來(lái)定時(shí)地掃描session信息并判斷其是否失效。當(dāng)一個(gè)有效請(qǐng)求發(fā)生時(shí),PHP會(huì)根據(jù)全局變量 session.gc_probability/session.gc_divisor(同樣可以通過(guò)php.ini或者ini_set()函數(shù)來(lái)修改) 的值,來(lái)決定是否啟動(dòng)一個(gè)GC(Garbage Collector)。默認(rèn)情況下,session.gc_probability = 1,session.gc_divisor =100,也就是說(shuō)有1%的可能性會(huì)啟動(dòng)GC。

GC的工作,就是掃描所有的session信息, 用當(dāng)前時(shí)間減去session的最后修改時(shí)間(modified date),同session.gc_maxlifetime參數(shù)進(jìn)行比較,如果生存時(shí)間已經(jīng)超過(guò)gc_maxlifetime,就把該session刪 除。

那為什么會(huì)發(fā)生gc_maxlifetime無(wú)效的情況呢?

在默認(rèn)情況下,session信息會(huì)以文本文件的形式,被保存在系統(tǒng) 的臨時(shí)文件目錄中。在Linux下,這一路徑通常為\tmp,在Windows下通常為C:\Windows\Temp。當(dāng)服務(wù)器上有多個(gè)PHP應(yīng)用時(shí), 它們會(huì)把自己的session文件都保存在同一個(gè)目錄中。同樣地,這些PHP應(yīng)用也會(huì)按一定機(jī)率啟動(dòng)GC,掃描所有的session文件。

問(wèn) 題在于,GC在工作時(shí),并不會(huì)區(qū)分不同站點(diǎn)的session。舉例言之,站點(diǎn)A的gc_maxlifetime設(shè)置為2小時(shí),站點(diǎn)B的 gc_maxlifetime設(shè)置為默認(rèn)的24分鐘。當(dāng)站點(diǎn)B的GC啟動(dòng)時(shí),它會(huì)掃描公用的臨時(shí)文件目錄,把所有超過(guò)24分鐘的session文件全部刪 除掉,而不管它們來(lái)自于站點(diǎn)A或B。這樣,站點(diǎn)A的gc_maxlifetime設(shè)置就形同虛設(shè)了。

找到問(wèn)題所在,解決起來(lái)就很簡(jiǎn)單了。修改session.save_path參數(shù),或者使用session_save_path()函數(shù),把保存session的目錄指向一個(gè)專用的目錄,gc_maxlifetime參數(shù)工作正常了。

還有一個(gè)問(wèn)題就是,gc_maxlifetime只能保證session生存的最短時(shí)間,并不能夠保存在超過(guò)這一時(shí)間之后session信息立即會(huì)得到 刪除。因?yàn)镚C是按機(jī)率啟動(dòng)的,可能在某一個(gè)長(zhǎng)時(shí)間內(nèi)都沒(méi)有被啟動(dòng),那么大量的session在超過(guò)gc_maxlifetime以后仍然會(huì)有效。解決這 個(gè)問(wèn)題的一個(gè)方法是,把session.gc_probability/session.gc_divisor的機(jī)率提高,如果提到100%,就會(huì)徹底解 決這個(gè)問(wèn)題,但顯然會(huì)對(duì)性能造成嚴(yán)重的影響。另一個(gè)方法是自己在代碼中判斷當(dāng)前session的生存時(shí)間,如果超出了gc_maxlifetime,就清 空當(dāng)前session。

 

php session GC功能,就是Garbage Collector。這個(gè)GC啟動(dòng)的時(shí)候,會(huì)清除那些已經(jīng)“超時(shí)”的session。它的工作原理是這樣的:

用戶訪問(wèn)并登陸網(wǎng)站,這時(shí)候后臺(tái)會(huì)調(diào)用session_start來(lái)嘗試生成一個(gè)會(huì)話(如果已經(jīng)有會(huì)話,則相當(dāng)于一次有效會(huì)話請(qǐng)求)
對(duì)于這樣的每一次有效會(huì)話請(qǐng)求(Request),apache的php模塊會(huì)根據(jù)session相關(guān)的全局變量gc_probability/gc_divisor =>計(jì)算出啟動(dòng)GC的概率,并由此概率來(lái)決定在這次請(qǐng)求中是否應(yīng)該啟動(dòng)GC。舉例來(lái)說(shuō),session.gc_probability的缺省值為1,session.gc_divisor的缺省值為100,則啟動(dòng)“垃圾回收”器的概率是1%,這就意味著在每100次請(qǐng)求中,會(huì)有可能清理一次過(guò)期會(huì)話
如果GC啟動(dòng),則GC會(huì)掃描當(dāng)前會(huì)話所在路徑(session.save_path)下的所有會(huì)話文件,并根據(jù)另外一個(gè)全局變量session.gc_maxlifetime的多少來(lái)判斷哪些session已經(jīng)過(guò)期(“當(dāng)前時(shí)間”與“會(huì)話文件的atime或者mtime”之間的差大于gc_maxlifetime:過(guò)期),并刪除這些過(guò)期的session
如果你在一個(gè)session啟動(dòng)后,長(zhǎng)時(shí)間沒(méi)有任何交互操作(譬如,不停地碼字,沒(méi)有提交或者保存為草稿),那么你的保存在后臺(tái)的會(huì)話文件將得不到機(jī)會(huì)被修改或者訪問(wèn),在gc_maxlifetime(缺省值1440秒=24分鐘)時(shí)間后,它有可能因失效而被清理,這以后你再提交,就會(huì)因?yàn)闀?huì)話失效而報(bào)錯(cuò)
由此可見,gc_maxlifetime設(shè)置為24分鐘,對(duì)于寫某些文章來(lái)說(shuō)還不夠。這是一個(gè)原因,另外,session.save_path的缺省路徑在linux上是/tmp,很少有程序會(huì)修改這個(gè)設(shè)置。如果這臺(tái)服務(wù)器上有多個(gè)虛擬主機(jī),那么,/tmp目錄下會(huì)存放許多不同session_name的會(huì)話文件。糟糕的是,php的GC不區(qū)分會(huì)話歸屬,它會(huì)根據(jù)它取得的gc_maxlifetime來(lái)清理這個(gè)目錄下的所有過(guò)期session文件。

據(jù)以上分析,解決方案是:UTBLOG在.htaccess文件內(nèi)添加了一條語(yǔ)句,將session.gc_maxlifetime的local value擴(kuò)大為14400(4小時(shí)),同時(shí)在后臺(tái)將session.save_path設(shè)置為/tmp/utblog,這樣,utblog的會(huì)話文件就不受其他網(wǎng)站干擾了,而4小時(shí)的失效時(shí)間,我想,無(wú)論如何應(yīng)該夠用了。

測(cè)試下來(lái),一切如我所愿。

另,如果直接改動(dòng)/etc/php.ini當(dāng)然也可以。如果沒(méi)有權(quán)限改動(dòng)php.ini,也沒(méi)有權(quán)限改動(dòng)apache的conf文件,.htaccess被禁止,那么直接修改plog的sessionmanager.class.php文件,在session_start行前添加ini_alter("session.gc_maxlifetime", 14400)亦可。plog結(jié)構(gòu)良好,只有這一處調(diào)用session_start,所以也只有這一處需要修改。我在本地做過(guò)測(cè)試,可以工作。

--------------------------------------------------------------------------

session.gc_probability integer
session.gc_probability 與 session.gc_divisor 合起來(lái)用來(lái)管理 gc(garbage collection 垃圾回收)進(jìn)程啟動(dòng)的概率。默認(rèn)為 1。詳見 session.gc_divisor。
session.gc_divisor integer
session.gc_divisor 與 session.gc_probability 合起來(lái)定義了在每個(gè)會(huì)話初始化時(shí)啟動(dòng) gc(garbage collection 垃圾回收)進(jìn)程的概率。此概率用 gc_probability/gc_divisor 計(jì)算得來(lái)。例如 1/100 意味著在每個(gè)請(qǐng)求中有 1% 的概率啟動(dòng) gc 進(jìn)程。session.gc_divisor 默認(rèn)為 100。
session.gc_maxlifetime integer
session.gc_maxlifetime 指定過(guò)了多少秒之后數(shù)據(jù)就會(huì)被視為“垃圾”并被清除。
Note:

如果不同的腳本具有不同的 session.gc_maxlifetime 數(shù)值但是共享了同一個(gè)地方存儲(chǔ)會(huì)話數(shù)據(jù),則具有最小數(shù)值的腳本會(huì)清理數(shù)據(jù)。此情況下,與 session.save_path 一起使用本指令。

Note: 如果使用默認(rèn)的基于文件的會(huì)話處理器,則文件系統(tǒng)必須保持跟蹤訪問(wèn)時(shí)間(atime)。Windows FAT 文件系統(tǒng)不行,因此如果必須使用 FAT 文件系統(tǒng)或者其他不能跟蹤 atime 的文件系統(tǒng),那就不得不想別的辦法來(lái)處理會(huì)話數(shù)據(jù)的垃圾回收。自 PHP 4.2.3 起用 mtime(修改時(shí)間)來(lái)代替了 atime。因此對(duì)于不能跟蹤 atime 的文件系統(tǒng)也沒(méi)問(wèn)題了。

--------------------------------------------------------

熱門評(píng)論
最新評(píng)論
發(fā)表評(píng)論 查看所有評(píng)論(0)
昵稱:
表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)