http協(xié)議是無狀態(tài)的,即你連續(xù)訪問某個網(wǎng)頁100次和訪問1次對服務(wù)器來說是沒有區(qū)別對待的,因為它記不住你。
那么,在一些場合,確實需要服務(wù)器記住當(dāng)前用戶怎么辦?比如用戶登錄郵箱后,接下來要收郵件、寫郵件,總不能每次操作都讓用戶輸入用戶名和密碼吧,為了解決這個問題,session的方案就被提了出來,事實上它并不是什么新技術(shù),而且也不能脫離http協(xié)議以及任何現(xiàn)有的web技術(shù)。
原理很簡單,假設(shè)你訪問網(wǎng)頁時就像逛澡堂,第一次進(jìn)去你是沒有鑰匙的,這個時候你交了錢服務(wù)臺就分配一把鑰匙給你,你走到哪里都要帶上,因為這是你身份的唯一標(biāo)識,接下來你用這把鑰匙可以去打開一個專有的儲物柜存儲你的衣物,游完泳,你再用鑰匙去打開柜子拿出衣物,最后離開游泳池時,把鑰匙歸還,你的這次游泳的過程就是一次session,或者叫做會話,在這個例子中,鑰匙就是session的key,而儲物柜可以理解為存儲用戶會話信息的介質(zhì)。
那么在web server中如何實現(xiàn)session呢?想必看了上面的例子你會很容易理解,主要是解決兩個問題,一個是鑰匙的問題,一個是存儲用戶信息的問題。對于第一個問題,即什么東西可以讓你每次請求都會自動帶到服務(wù)器呢?如果你比較了解http協(xié)議,那么答案一目了然,就是cookie,如果你想為用戶建立一次會話,可以在用戶授權(quán)成功時給他一個cookie,叫做會話id,它當(dāng)然是唯一的,比如php就會為建立會話的用戶默認(rèn)set一個名為phpsessid,值看起來為一個隨機(jī)字符串的cookie,如果下次發(fā)現(xiàn)用戶帶了這個cookie,服務(wù)器就知道,哎呀,剛剛這位顧客來了。
剩下的是解決第二個問題,即如何存儲用戶的信息,服務(wù)器知道會話id為abc的用戶來了,那abc想存儲自己的私人信息,比如購物車信息,如何處理?這個時候可以用內(nèi)存、也可以用文件,也可以用數(shù)據(jù)庫了,但有個要求是,數(shù)據(jù)需要用用戶的會話id即可取到,比如php就默認(rèn)會把會話id為abc的用戶會話數(shù)據(jù)存儲到/tmp/phpsess_abc的文件里面,每次讀取都要反序列化程序可以理解的數(shù)據(jù),寫的時候又需要序列化為持久的數(shù)據(jù)格式。
較好理解的描述:
session被用于表示一個持續(xù)的連接狀態(tài),在網(wǎng)站訪問中一般指代客戶端瀏覽器的進(jìn)程從開啟到結(jié)束的過程。session其實就是網(wǎng)站分析的訪問(visits)度量,表示一個訪問的過程。
session的常見實現(xiàn)形式是會話cookie(session cookie),即未設(shè)置過期時間的cookie,這個cookie的默認(rèn)生命周期為瀏覽器會話期間,只要關(guān)閉瀏覽器窗口,cookie就消失了。實現(xiàn)機(jī)制是當(dāng)用戶發(fā)起一個請求的時候,服務(wù)器會檢查該請求中是否包含sessionid,如果未包含,則系統(tǒng)會創(chuàng)造一個名為JSESSIONID的輸出 cookie返回給瀏覽器(只放入內(nèi)存,并不存在硬盤中),并將其以HashTable的形式寫到服務(wù)器的內(nèi)存里面;當(dāng)已經(jīng)包含sessionid是,服務(wù)端會檢查找到與該session相匹配的信息,如果存在則直接使用該sessionid,若不存在則重新生成新的 session。這里需要注意的是session始終是有服務(wù)端創(chuàng)建的,并非瀏覽器自己生成的?!〉菫g覽器的cookie被禁止后session就需要用get方法的URL重寫的機(jī)制或使用POST方法提交隱藏表單的形式來實現(xiàn)。
二、如何實現(xiàn)session的共享?
首先我們應(yīng)該明白,為什么要實現(xiàn)共享,如果你的網(wǎng)站是存放在一個機(jī)器上,那么是不存在這個問題的,因為會話數(shù)據(jù)就在這臺機(jī)器,但是如果你使用了負(fù)載均衡把請求分發(fā)到不同的機(jī)器呢?這個時候會話id在客戶端是沒有問題的,但是如果用戶的兩次請求到了兩臺不同的機(jī)器,而它的session數(shù)據(jù)可能存在其中一臺機(jī)器,這個時候就會出現(xiàn)取不到session數(shù)據(jù)的情況,于是session的共享就成了一個問題。
1.各種web框架早已考慮到這個問題,比如asp.net,是支持通過配置文件修改session的存儲介質(zhì)為sql server的,所有機(jī)器的會話數(shù)據(jù)都從同一個數(shù)據(jù)庫讀,就不會存在不一致的問題;
2.以cookie加密的方式保存在客戶端.優(yōu)點(diǎn)是減輕服務(wù)器端的壓力,缺點(diǎn)是受到cookie的大小限制,可能占用一定帶寬,因為每次請求會在頭部附帶一定大小的cookie信息,另外這種方式在用戶禁止使用cookie的情況下無效.
3.服務(wù)器間同步。定時同步各個服務(wù)器的session信息,此方法可能有一定延時,用戶體驗也不是很好。
4.php支持把會話數(shù)據(jù)存儲到某臺memcache服務(wù)器,你也可以手工把session文件存放的目錄改為nfs網(wǎng)絡(luò)文件系統(tǒng),從而實現(xiàn)文件的跨機(jī)器共享。
還有一個簡單的辦法可以用于會話信息不會頻繁變更的情況,在機(jī)器a設(shè)置用戶會話的時候,把會話數(shù)據(jù)post到機(jī)器b的一個cgi,機(jī)器b的cgi把會話數(shù)據(jù)存下來,這樣機(jī)器a和b都會有同一份session數(shù)據(jù)的拷貝。
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
伴隨網(wǎng)站業(yè)務(wù)規(guī)模和訪問量的逐步發(fā)展,原本由單臺服務(wù)器、單個域名的迷你網(wǎng)站架構(gòu)已經(jīng)無法滿足發(fā)展需要。
此時我們可能會購買更多服務(wù)器,并且啟用多個二級子域名以頻道化的方式,根據(jù)業(yè)務(wù)功能將網(wǎng)站分布部署在獨(dú)立的服務(wù)器上;或通過負(fù)載均衡技術(shù)(如:DNS輪詢、Radware、F5、LVS等)讓多個頻道共享一組服務(wù)器。
OK,頭腦中我們已經(jīng)構(gòu)思了這樣的解決方案,不過進(jìn)入深入開發(fā)后新的技術(shù)問題又隨之而來:
我們把網(wǎng)站程序分布部署到多臺服務(wù)器上,而且獨(dú)立為幾個二級域名,由于Session受實現(xiàn)原理的局限(PHP中Session默認(rèn)以文件的形式保存在本地服務(wù)器的硬盤),使得我們的網(wǎng)站用戶不得不經(jīng)常在幾個頻道間來回輸入用戶名、密碼登入,導(dǎo)致用戶體驗大打折扣;另外,原本程序可以直接從用戶Session變量中讀取的資料(如:昵稱、積分、登入時間等),因為無法跨服務(wù)器同步更新Session 變量,迫使開發(fā)人員必須實時讀寫數(shù)據(jù)庫,從而增加了數(shù)據(jù)庫的負(fù)擔(dān)。
于是,解決網(wǎng)站跨服務(wù)器之間的Session共享方案需求變得迫切起來,最終催生了多種解決方案,下面列舉4種較為可行的方案進(jìn)行對比探討:
建網(wǎng)站原本是網(wǎng)站策劃師、網(wǎng)絡(luò)程序員、網(wǎng)頁設(shè)計師等,應(yīng)用各種網(wǎng)絡(luò)程序開發(fā)技術(shù)和網(wǎng)頁設(shè)計技術(shù)配合操作的協(xié)同工作。成都創(chuàng)新互聯(lián)公司專業(yè)提供做網(wǎng)站、網(wǎng)站設(shè)計,網(wǎng)頁設(shè)計,網(wǎng)站制作(企業(yè)站、響應(yīng)式網(wǎng)站、電商門戶網(wǎng)站)等服務(wù),從網(wǎng)站深度策劃、搜索引擎友好度優(yōu)化到用戶體驗的提升,我們力求做到極致!
基于NFS的Session共享:
NFS是Net FileSystem的簡稱,最早由Sun公司為解決Unix網(wǎng)絡(luò)主機(jī)間的目錄共享而研發(fā)。
這個方案實現(xiàn)最為簡單,無需做過多的二次開發(fā),僅需將共享目錄服務(wù)器mount到各頻道服務(wù)器的本地session目錄即可,缺點(diǎn)是NFS依托于復(fù)雜的安全機(jī)制和文件系統(tǒng),因此并發(fā)效率不高,尤其對于session這類高并發(fā)讀寫的小文件,會由于共享目錄服務(wù)器的io-wait過高,最終拖累前端WEB應(yīng)用程序的執(zhí)行效率。