為什么有session?
首先大家知道,http協議是無狀態的,即你連續訪問某個網頁100次和訪問1次對服務器來說是沒有區別對待的,因為它記不住你。
那么,在一些場合,確實需要服務器記住當前用戶怎么辦?比如用戶登錄郵箱后,接下來要收郵件、寫郵件,總不能每次操作都讓用戶輸入用戶名和密碼吧,為了解決這個問題,session的方案就被提了出來,事實上它並不是什么新技術,而且也不能脫離http協議以及任何現有的web技術。
原理很簡單,假設你訪問網頁時就像逛澡堂,第一次進去你是沒有鑰匙的,這個時候你交了錢服務台就分配一把鑰匙給你,你走到哪里都要帶上,因為這是你身份的唯一標識,接下來你用這把鑰匙可以去打開一個專有的儲物櫃存儲你的衣物,游完泳,你再用鑰匙去打開櫃子拿出衣物,最后離開游泳池時,把鑰匙歸還,你的這次游泳的過程就是一次session,或者叫做會話,在這個例子中,鑰匙就是session的key,而儲物櫃可以理解為存儲用戶會話信息的介質。
那么在web server中如何實現session呢?想必看了上面的例子你會很容易理解,主要是解決兩個問題,一個是鑰匙的問題,一個是存儲用戶信息的問題。對於第一個問題,即什么東西可以讓你每次請求都會自動帶到服務器呢?如果你比較了解http協議,那么答案一目了然,就是cookie,如果你想為用戶建立一次會話,可以在用戶授權成功時給他一個cookie,叫做會話id,它當然是唯一的,比如php就會為建立會話的用戶默認set一個名為phpsessid,值看起來為一個隨機字符串的cookie,如果下次發現用戶帶了這個cookie,服務器就知道,哎呀,剛剛這位顧客來了。
剩下的是解決第二個問題,即如何存儲用戶的信息,服務器知道會話id為abc的用戶來了,那abc想存儲自己的私人信息,比如購物車信息,如何處理?這個時候可以用內存、也可以用文件,也可以用數據庫了,但有個要求是,數據需要用用戶的會話id即可取到,比如php就默認會把會話id為abc的用戶會話數據存儲到/tmp/phpsess_abc的文件里面,每次讀取都要反序列化程序可以理解的數據,寫的時候又需要序列化為持久的數據格式。
如何實現session的共享?
首先我們應該明白,為什么要實現共享,如果你的網站是存放在一個機器上,那么是不存在這個問題的,因為會話數據就在這台機器,但是如果你使用了負載均衡把請求分發到不同的機器呢?這個時候會話id在客戶端是沒有問題的,但是如果用戶的兩次請求到了兩台不同的機器,而它的session數據可能存在其中一台機器,這個時候就會出現取不到session數據的情況,於是session的共享就成了一個問題。
事實上,各種web框架早已考慮到這個問題,比如asp.net,是支持通過配置文件修改session的存儲介質為sql server的,所有機器的會話數據都從同一個數據庫讀,就不會存在不一致的問題;php支持把會話數據存儲到某台memcache服務器,你也可以手工把session文件存放的目錄改為nfs網絡文件系統,從而實現文件的跨機器共享。
還有一個簡單的辦法可以用於會話信息不會頻繁變更的情況,在機器a設置用戶會話的時候,把會話數據post到機器b的一個cgi,機器b的cgi把會話數據存下來,這樣機器a和b都會有同一份session數據的拷貝。