session多服务器共享的方案梳理
默認情況下,php的session文件是保存在磁盤文件中。在php.ini配置文件中的配置項如下:
session.save_handler = files
session.save_path = "N;/path"
第一個配置項是指定使用files(文件形式)存儲session數據。
第二個參數指定保存的路徑。N表示生成多少級目錄(不放到一個目錄下,分散到多個磁盤目錄中去)
我的配置項是:session.save_path = "/tmp/session"。那么就會去這個目錄下面看到很多session數據的文件。當我們使用php的內置函數session_start()的時候,就是去上面指定的磁盤目錄把session數據載入,實際上就是拿類似sess_74dd7807n2mfml49a1i12hkc45的文件74dd7807n2mfml49a1i12hkc45就是大家經常說的什么session的id號。
php.ini中還有一個關鍵配置項,如下:
session.name = PHPSESSID
PHPSESSID就是cookie的名稱,其實上面一串"74dd7807n2mfml49a1i12hkc45"會保存在一個名為PHPSESSID的cookie中。根據http的請求機制,當瀏覽器請求的時候,頭部信息會把瀏覽器中的cookie一起發給服務器。PHPSESSID這個cookie也是在其中發給了服務器,php引擎通過讀取PHPSESSID的值來確定要載入哪個session文件。比如值為74dd7807n2mfml49a1i12hkc45,載入的就是"sess_74dd7807n2mfml49a1i12hkc45"。
根據如上原理。session的數據默認是保存在磁盤文件中。假設這種情況:多臺php服務器進行負載均衡的時候,比如有三臺php服務器,為了實現負載均衡,那么三臺服務器上面的php代碼都是一樣。
生成session數據文件都是在本地了(a,b,c各自的服務器磁盤上)。負載均衡的目的本來就是要為了平均分配請求,所以沒有固定第一次訪問和第二次訪問是同一臺服務器,實際上無法確定的。第一秒訪問可能是a服務器,第二秒訪問的可能是c服務器。所以同一個登錄會員,實際上就會出現:第一秒訪問第一臺php服務器,第二秒訪問的是第二臺服務器。登錄的信息一般是保存在session中的。這樣子登錄保存的session數據就需要進行共享了。不然的話會出現,訪問第一臺服務器生成了一個session數據。第二秒負載請求到第三臺服務器,結果獲取不到剛才生成的session數據。在php環境中,只有多臺php服務器(php服務器而非web服務器,session文件是php引擎生成的)的情況下,才會涉及session共享的問題。單臺php服務器,存儲都在一臺主機上。不涉及到共享問題。因為session直接存儲在這臺服務器磁盤上是能夠被本機讀取到的。
目前業界解決session共享的幾種思路,總結如下:
第一種辦法:把原來存儲在服務器磁盤上的session數據存儲到客戶端的cookie中去。這樣子,就不需要涉及到數據共享了。a客戶端請求的時候,原來生成在服務器的數據生成到瀏覽器的cookie中,根據cookie中的數據識別用戶。php由原來的”從本地(也就是服務器)磁盤上讀取session數據”轉變為”瀏覽器的cookie中讀取數據”,這樣子,在多臺php服務器負載均衡的情況下,即便第一秒請求是a服務器,第二秒請求是b服務器,都不需要管哪臺服務器了。反正都是讀取客戶端上的cookie數據。
一般是把session數據按照自己定義的加密規則,加密后后存在cookie中。數據保存在cookie中這種做法有好處,也有壞處。好處是服務器的壓力減小了,因為session數據不存在服務器磁盤上。根本就不會出現session讀取不到的問題。
帶來的弊端是:
網絡請求占用很多。每次請求時,客戶端都要通過cookie發送session數據給服務器。
另外,瀏覽器對cookie的大小存在限制。每個瀏覽器限制是不同的。
Firefox和Safari允許cookie多達4097個字節,包括名(name)、值(value)和等號。Opera允許cookie多達4096個字節,包括:名(name)、值(value)和等號。Internet Explorer允許cookie多達4095個字節,包括:名(name)、值(value)和等號。
所以第一種方案不適合高訪問量的情況下,因為高訪問量的情況下,每次請求瀏覽器都要發送session數據給服務器。一般一個cookie大小2k的樣子。占用很多帶寬了,成本增高。歸納為帶寬性能,速度問題。存儲到cookie中去,第二方面是安全問題:把session數據放到客戶端,一般session中存的都是重要性數據,會存在安全問題。了解到,淘寶以前用過這種方式,把session數據存儲到cookie中,根據cookie來識別用戶。
第二種思路:用一種算法(簡單理解為規則),什么機制下session是保存在哪臺服務器下,那么讀取的時候就按照這種規則去讀取,就能定位到原來的服務器。叫做分發請求,分發到特定的服務器上去,我理解其原理是存session和讀session數據保證都在一臺服務器操作,就不會需要涉及到共享,具體實現方式是通過約定一種分發機制來實現。也叫做sticky模式(粘性會話模式),同一個用戶的訪問請求都被派送到同一個服務器上。假設是同一個用戶user1,每次訪問都路由到同一臺服務器上,這樣即便是在負載均衡的情況下,也能保證每次訪問都能讀取到session,不需要做session數據共享了。
關鍵多臺server的原因是為負載均衡而做的,那么就得把原來負載均衡的規則假設是—a,現在改為按照session來均衡分發請求的規則—b。如果這臺機子掛掉了,那么后續的請求按照session的規則還是會分發到這臺服務器上去,但是現在不可用了。因為某種規則的session都是保存在一臺服務器上,比如用戶編號是1-200涉及到的session數據保存到a服務器上去。所以只要一臺出問題,1-200的用戶就無法實現登錄了。后面就不可用了(可能想到1-200用戶的session服務器用多臺進行復制,這感覺很蹩腳,仍然需要用到復制的話,還不如用其他簡便的方法)
第三種思路:做一個中間層,專門來存儲所有訪問涉及到的session。也就是所有的session都存儲在這里。服務器端統一從這里讀取session數據。
具體實現方式很多種。我的理解是,這里只是一種思想層面上的。我不知道淘寶的tbsession框架的具體實現。但是大致思想差不多,由這個session框架來維護所有網站的session數據。
使用這種中間層的思想來實現共享,具體的技術方案,我歸納為以下幾種:
1、 通過NFS文件共享的方式,多臺php服務器共享保存session文件的磁盤。通過nfs的方式,各個php服務器操作session數據的時候,是讀取本地磁盤目錄,但實際上是一個共享網絡文件。各個php服務器實際上操作的都是同一個目錄的文件。
2、保存在數據庫中,這種方式的擴展性很強,可以隨意增加WEB而不受影響。放在數據庫里面安全方面好。把以前存儲在文件中的session數據存儲到數據庫中去,那么這樣做,其實就不用到php內置的session機制了(像session_start()之類的函數都不需要去用了)。寫程序要模擬的是,從數據庫拿session數據,約定什么情況下數據過期了然后自動清理,這里是指刪除數據庫中的行。保存在文件中的時候,php有垃圾回收機制會去自動清理過期的session文件。弊端是放在數據庫里面,訪問量小沒有問題。大流量網站這么做,只會拖慢速度。因為得查詢數據庫,造成數據庫壓力大。高并發訪問的情況下,會出現很大的性能問題。放到數據庫存儲后,就可以實現:多臺web服務器統一操作數據庫,因為數據都在數據庫,web服務器都能從數據庫進行讀取,那么session數據就能實現共享。存儲在數據庫的做法,在線人數決定了其瓶頸,主要問題是影響性能。在線人數,因為登錄的session數據存儲在數據庫中,只要是登錄的用戶就會涉及到頻繁操作數據庫。對于大訪問量的網站,數據庫存儲session方法可行性有待商榷。
3、可以將session數據保存在memcached,redis之類內存數據庫中,memcached是基于內存存儲數據的,性能很高,用戶并發量很大的時候尤其合適。主要是利用內存的數據讀取速度是很快的,與磁盤讀取的速度不是一個數量級的。使用內存存儲:方便統計在線人數,內存的速度比磁盤訪問快、內存數據庫系統能夠控制內存中的過期數據自動失效(剛好符合session過期需要)。存儲在redis比較理想的選擇,存儲在數據庫中方便存儲統計在線人數,那么存儲在redis中也實現了這個要求。也可以存儲在memcache中,redis支持的數據類型多。
關于使用技術工具復制session數據同步到多臺服務器的方案權衡:
這種方案是,使用一些文件同步工具(linux下的rsync),當a服務器中的session數據有更改的時候,就會把這些更改也同步到b,c服務器上去。通過復制的方式,最終a,b,c各個服務器上都拷貝了一份session數據。這種方式的弊端是,速度慢。復制數據會出現延遲。比如第一秒訪問是a服務器,修改了session數據,負載均衡,可能下一秒訪問是b服務器,session數據如果沒有被復制到b服務器,則是讀取不到session數據的,出現時間上的延遲。這種復制數據要消耗很多網絡帶寬的。在實際中業界用得比較少。機器的數量越多,復制數據的性能損耗越大。不具備高度擴展性。
復制session的方式,無論是網絡帶寬成本還是硬件開銷上都很大的。
轉載于:https://blog.51cto.com/mrcelite/1350353
總結
以上是生活随笔為你收集整理的session多服务器共享的方案梳理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python很简单。。。。
- 下一篇: Devexpress之dxErrorPr