PHPsession的實現原理
PHP SESSION原理
我們知道,session是在伺服器端保持使用者會話資料的一種方法,對應的cookie是在客戶端保持使用者資料。HTTP協議是一種無狀態協議,伺服器響應完之後就失去了與瀏覽器的聯絡,最早,Netscape將cookie引入瀏覽器,使得資料可以客戶端跨頁面交換,那麼伺服器是如何記住眾多使用者的會話資料呢?
首先要將客戶端和伺服器端建立一一聯絡,每個客戶端都得有一個唯一標識,這樣伺服器才能識別出來。建議唯一標識的方法有兩種:cookie或者通過GET方式指定。預設配置的PHP使用session的時會建立一個名叫”PHPSESSID”的cookie(可以通過php.ini修改session.name值指定),如果客戶端禁用cookie,你也可以指定通過GET方式把session id傳到伺服器(修改php.ini中session.use_trans_sid等引數)。
我們檢視伺服器端session.save_path目錄會發現很多類似sess_vv9lpgf0nmkurgvkba1vbvj915這樣的檔案,這個其實就是session id “vv9lpgf0nmkurgvkba1vbvj915″對應的資料。真相就在這裡,客戶端將session id傳遞到伺服器,伺服器根據session id找到對應的檔案,讀取的時候對檔案內容進行反序列化就得到session的值,儲存的時候先序列化再寫入。
事實就是這樣,所以如果伺服器不支援session或者你想自定義session,完全可以DIY,通過PHP的uniqid生成永不重複的session id,然後找個地方儲存session的內容即可,你也可以學flickr把session儲存在MySQL資料庫中。
使用session之前為什麼必須先執行session_start()?
瞭解的原理之後,所謂的session其實就是客戶端一個session id伺服器端一個session file,新建session之前執行session_start()是告訴伺服器要種一個cookie以及準備好session檔案,要不然你的session內容怎麼存;讀取session之前執行session_start()是告訴伺服器,趕緊根據session id把session檔案反序列化。
只有一個session函式可以在session_start()之前執行,session_name():讀取或指定session名稱(比如預設的就是”PHPSESSID”),這個當然要在session_start之前執行。
session影響系統效能
session在大訪問量網站上確實影響系統效能,影響效能的原因之一由檔案系統設計造成,在同一個目錄下超過10000個檔案時,檔案的定位將非常耗時,PHP支援session目錄hash,我們可以通過修改php.ini中session.save_path = “2;/path/to/session/dir”,那麼session將儲存在兩級子目錄中,每個目錄有16個子目錄[0~f],不過好像PHP session不支援建立目錄,你需要事先把那麼些目錄建立好 。
還有一個問題就是小檔案的效率問題,一般我們的session資料都不會太大(1~2K),如果有大量這樣1~2K的檔案在磁碟上,IO效率肯定會很差,PHP手冊上建議使用Reiserfs檔案系統,不過Reiserfs的前景堪憂,Reiserfs的作者把媳婦給殺了,SuSE也拋棄了Reiserfs。
其實還有很多中儲存session的方式,可以通過php -i|grep “Registered save handlers”檢視,比如Registered save handlers => files user sqlite eaccelerator可以通過檔案、使用者、sqlite、eaccelerator來存,如果伺服器裝了memcached,還有會mmcache的選項。當然還有很多,比如MySQL、PostgreSQL等等。都是不錯的選擇。
session的同步
我們前端可能有很多臺伺服器,使用者在A伺服器上登入了,種下了session資訊,然後訪問網站的某些頁面沒準跳到B伺服器上去了,如果這個時候B伺服器上沒有session資訊又沒有做特殊處理,可能就會出問題了。
session同步有很多種,如果你是儲存在memcached或者MySQL中,那就很容易了,指定到同樣的位置即可,如果是檔案形式的,你可以用NFS統一儲存。
還有一種方式是通過加密的cookie來實現,使用者在A伺服器上登入成功,在使用者的瀏覽器上種上一個加密的cookie,當使用者訪問B伺服器時,檢查有無session,如果有當然沒問題,如果沒有,就去檢驗cookie是否有效,cookie有效的話就在B伺服器上重建session。這種方法其實很有用,如果網站有很多個子頻道,伺服器也不在一個機房,session沒辦法同步又想做統一登入那就太有用了。
當然還有一種方法就是在負載均衡那一層保持會話,把訪問者繫結在某個伺服器上,他的所有訪問都在那個伺服器上就不需要session同步了,這些都是運維層面的東西。就說這麼多吧,根據自己的應用來選擇使用session,不要因為大家都說session影響系統效能就畏首畏尾,知道問題,解決問題才是關鍵,惹不起躲得起不適合這裡。
相關文章
- Vitepress 的實現原理Vite
- ACID的實現原理
- synchronized 的實現原理synchronized
- LinkedList 的實現原理
- Category的實現原理Go
- React Router 的實現原理React
- Docker的核心實現原理Docker
- 堆的原理與實現
- 前端路由的實現原理前端路由
- Spring AOP的實現原理Spring
- AQS實現原理AQS
- Condition實現原理
- Synchronized 實現原理synchronized
- LinkedList實現原理
- block實現原理BloC
- ReentrantLock實現原理ReentrantLock
- synchronized實現原理synchronized
- AsyncTask實現原理
- jQuery實現原理jQuery
- 分散式鎖的實現原理分散式
- [SentencePiece]Tokenizer的原理與實現
- ArrayList底層的實現原理
- 富集分析的原理與實現
- http 框架的路由實現原理HTTP框架路由
- async 函式的實現原理函式
- Springboot Starter的核心實現原理Spring Boot
- 前端路由的原理和實現前端路由
- GO 中 string 的實現原理Go
- GO 中 slice 的實現原理Go
- GO 中 map 的實現原理Go
- GO 中 defer的實現原理Go
- base64的實現原理
- CPU實現原子操作的原理
- flutter_redux 的實現原理FlutterRedux
- v-model的實現原理
- 簡單的實現vue原理Vue
- 簡單的實現React原理React
- 原始碼|ThreadLocal的實現原理原始碼thread
- spring-jdbc 的實現原理SpringJDBC