全部Web程序都會使用Session保存數據. 使用獨立的Session服務器能夠解決負載均衡場景中的Session共享問題.本文介紹.NET平臺下創建Session服務器的幾種辦法, 並介紹在使用Session時的各類經驗和技巧.html
Session數據保存在服務器端, 可是每個客戶端都須要保存一個SessionID, SessionID保存在Cookies中, 關閉瀏覽器時過時.web
在向服務器發送的HTTP請求中會包含SessionID, 服務器端根據SessionID獲取獲取此用戶的Session信息.sql
不少初級開發人員不知道SessionID和Cookies的關係, 因此經常認爲二者沒有聯繫. 這是不正確的. 正是由於SessionID保存在Cookies中, 因此在咱們保存Cookies的時候,必定要注意不要由於Cookies的大小和個數問題而致使SessionID對象. 在咱們的程序中, 對SessionID的Cookies有特殊的處理:數據庫
SetCookie( day) { CookieName = GetType().ToString(); HttpCookie SessionCookie = ; (HttpContext.Current.Request.Cookies[] != ) { SesssionId = HttpContext.Current.Request.Cookies[].Value.ToString(); SessionCookie = HttpCookie(); SessionCookie.Value = SesssionId; }
//省略掉中間的代碼部分.只保留備份SessionID和找回SessionID的邏輯
(HttpContext.Current.Request.Cookies.Count > 20 && SessionCookie != ) { (SessionCookie.Value != .Empty) { HttpContext.Current.Response.Cookies.Remove(); HttpContext.Current.Response.Cookies.Add(SessionCookie); } } ; }
將Session保存在獨立的服務器中能夠實如今多臺Web服務器之間共享Session.雖然咱們也能夠本身開發Session存儲系統, 可是使用ASP.NET自帶的存儲機制將更加便捷.windows
.NET提供了5種保存Seission的方式:瀏覽器
方式名稱安全 |
存儲方式 | 性能 |
Off服務器 |
設置爲不使用Session功能cookie |
無 |
InProcsession |
設置爲將Session存儲在進程內,就是ASP中的存儲方式,這是默認值。 |
性能最高 |
StateServer |
設置爲將Session存儲在獨立的狀態服務中。一般是aspnet_state.exe進程. |
性能損失10-15% |
SQLServer |
設置將Session存儲在SQL Server中。 |
性能損失10-20% |
Customer |
自定製的存儲方案 |
由實現方式肯定 |
咱們能夠在Web.Config中配置程序使用的Session存儲方式.默認狀況下是InProc, 即保存在IIS進程中. 關於Off, InProc和Customer本文不作講解. 相關文章你們均可以在網上搜索到.
下面主要講解 StateServer 和 SQLServer 的應用.
1.啓動 Asp.net State service服務.(這個服務默認的狀態爲手動.修改成自動並啓動.)
2.修改註冊表: [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\aspnet_state\Parameters]
設置 AllowRemoteConnection = 1 , 設置 Port = 42424 (十進制,默認即爲42424)
Port是服務的端口號
AllowRemoteConnection 表示是否容許其餘機器鏈接,0爲僅能本機使用,1爲能夠供其餘機器使用.
在Web應用程序的Web.Config中, 咱們須要修改 <configuration> / <system.web> 的<sessionState>節點.若是沒有
沒有則添加(默認使用的是InProc方式)
<sessionState mode="StateServer" stateConnectionString="tcpip=服務器ip:42424" cookieless="false" timeout="60"/>
上面的參數咱們能夠根據須要修改.
使用SqlServer模式搭建Session服務器端有兩種方式. ASP.NET 1.0和1.1版本請使用方式a, 2.0即以上版本請使用方式b.
在ASP.NET 1.0和1.1 版本中, 只能使用這種方式.對於2.0及其以上版本,請使用aspnet_regsql.exe工具.(固然此方法也通用2.0版本)
.net提供了數據庫安裝腳本,能夠在機器的windows文件夾中找到:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ InstallSqlState.sql
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ InstallSqlStateTemplate.sql
根據ASP.NET的版本不一樣, 須要使用不一樣的SQL腳本. ASP.NET主要有1.1和2.0兩個版本,能夠在不一樣的版本文件夾找到這兩個SQL.
InstallSqlState.sql 是建立默認名稱的數據庫"[ASPState]".此SQL能夠直接運行.
InstallSqlStateTemplate.sql 可使用本身指定的數據庫保存數據.此SQL須要本身修改後運行, 打開SQL文件將其中 [DatabaseNamePlaceHolder] 替換爲本身指定的數據庫名稱.
執行installsqlstate.sql時不須要指定數據庫,能夠在任意數據庫上執行.此SQL會本身建立新的數據庫
ASP.NET 2.0版本後微軟提供了aspnet_regsql.exe工具能夠方便的配置Session數據庫.該工具位於 Web 服務器上的"系統根目錄\Microsoft.NET\Framework\版本號"文件夾中.
使用舉例:
aspnet_regsql.exe -S . -U sa -P 123456 -ssadd -sstype p
-S參數:
表示數據庫實例名稱. 能夠用"."表示本機.
-U和-P參數:
表示用戶名和密碼.
-E參數:
能夠再-U –P 與 -E中選擇一組. –E表示以當前系統用戶經過windows身份驗證登陸數據庫, -U -P則是使用SqlServer用戶登陸數據庫.
-ssadd / –ssremove 參數:
-ssadd表示是添加Session數據庫, -ssremove表示移除Session數據庫.
sstype 參數:
選項 |
說明 |
t |
將會話數據存儲到 SQL Server tempdb 數據庫中。這是默認設置。若是將會話數據存儲到 tempdb 數據庫中,則在從新啓動 SQL Server 時將丟失會話數據。 |
p |
將會話數據存儲到 ASPState 數據庫中,而不是存儲到 tempdb 數據庫中。 |
c |
將會話數據存儲到自定義數據庫中。若是指定 c 選項,則還必須使用 -d 選項包括自定義數據庫的名稱。 |
此房是一樣須要Web應用程序修改Web.Config中的<sessionState>節點.若是使用默認的數據庫(ASPState庫), 則配置以下:
<sessionState mode="SQLServer" sqlConnectionString="server=192.168.9.151; uid=sa; pwd=123456;" />
若是使用了自定義的數據庫名稱,則還須要制定allowCustomSqlDatabase屬性並在數據庫鏈接串中指定數據庫:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="server=192.168.9.151; DataBase=MyAspState;uid=sa; pwd=123456;" />
下面是SessionID, Session_End時間, StatServer模式 和 SqlServer模式的各類經驗和技巧總結.
1.在web farm中,請確認在全部的web服務器上有相同的<machineKey>
2. 要保存在Session中的對象是可序列化的。
3.爲了在web farm中的不一樣web服務器上維護session state,IIS Metabase中的網站應用程序路徑(如\LM\W3SVC\2)應該在全部的服務器上保持一致(大小寫敏感).
4. ASP.NET處理Session是在Machine.Config中配置的HttpModuel模塊, 在.NET的安裝目錄下的Config文件夾中, 查看Web.Config(1.1版本是在Machine.Config):
<httpModules> ...
<add name="Session" type="System.Web.SessionState.SessionStateModule"/> ...
</httpModules>
確認此模塊是否存在.
5.StateServer不支持負載均衡, 因此若是大併發推薦使用SqlServer模式, 能夠享受到SqlServer的高性能和安全性.雖然存儲效率會有降低.
6.須要讓全部機器的MachineKey相同.在Machine.Config中配置:
<machineKey validationKey="1234567890123456789012345678901234567890AAAAAAAAAA" decryptionKey="123456789012345678901234567890123456789012345678" validation="SHA1" decryption="Auto" />
1. 要保存在Session中的對象是可序列化的。
2. 若是使用了默認是數據庫, 則在客戶端配置文件中的數據庫連接字符串的用戶,須要擁有ASPState和tempdb兩個庫的dbowner權限.
3. 在SQLServer模式下,session過時是由SQL Agent使用一個註冊任務完成的,要確認SQL Agent已經運行。不然沒法清理過時的Session數據, 會致使數據庫數據一直增長.
4. 若是使用SqlServer模式時, 對於Web場中的各服務器的 ASP.NET 應用程序路徑必須是相同的。請在 IIS 配置數據庫中對 Web 場中的全部 Web 服務器進行 Web 站點的應用程序路徑同步。大小寫必定要相同,由於 Web 站點的應用程序路徑是區分大小寫的。
5.須要讓全部機器的MachineKey相同.在Machine.Config中配置:
<machineKey validationKey="1234567890123456789012345678901234567890AAAAAAAAAA" decryptionKey="123456789012345678901234567890123456789012345678" validation="SHA1" decryption="Auto" />
1. 不能直接經過Session服務器在ASP.NET和ASP之間共享Session. 請使用微軟提供的解決方案:
http://msdn.microsoft.com/zh-cn/library/aa479313.aspx
2. 在不一樣的應用程序或一個網站的不一樣虛擬目錄之間沒法共享Session
3. Session的過時時間是滑動時間.
4. Session存儲.NET自帶的值類型性能最優. 存儲對象會下降性能.
1.SessionID 還能夠保存在URL上, 設置Web.Config文件中的System.Web/sessionState節點的Cookiesless屬性便可:
<sessionState cookieless="UseUri" />
2. 通常在Session超時或刪除以後,SessionID保持不變. 由於Session過時後會在服務器端清除數據, 可是SessionID保存在用戶瀏覽器上, 因此只要瀏覽器不關閉則HTTP頭中的SessionID保持不變.
3.關閉瀏覽器後再訪問, SessionID會不一樣.
4.每打開一個IE6窗口, SessionID都不一樣, 在IE6中兩個窗口的Session不能共享.
5.FireFox的標籤頁和新的FireFox窗口, SessionID都相同, 在FF的窗口和標籤頁上Session能共享.
6.對於包含FrameSet的頁面,好比:
<frameset cols="25%,50%,25%"> <frame src="SessionID.aspx"> <frame src="SessionID.aspx"> <frame src="SessionID.aspx"></frameset>
若是後綴名是.htm而且.htm文件沒有交給ASP.NET的ISAPI處理, 那麼根據服務器速度在每一個Frame頁面生成不一樣的SessionID, 再刷新後相同都等於最後一個SessionID.
解決辦法是將.htm後綴改爲.aspx, 或者將.htm文件交給ASP.NET的ISAPI處理.
1. Session_End僅在InProc模式中可用
2. 關閉瀏覽器,Session_End是不會觸發的。HTTP是一種無狀態協議,服務器沒有辦法知道你的瀏覽器是否已經關閉。
3. 當Session由於時間過時或調用Session.Abandon時,Session_End纔會觸發.Session.Clear()僅僅是清除數據,但沒有刪除session。
4. Session_End由一個後臺線程觸發,使用工做者進程帳號運行. 因此程序不會通知發生的錯誤.
5. 在Session_End訪問數據庫要考慮權限問題. Session_End是用運行工做者進程(aspnet_wp.exe)的賬號運行的,這個帳號能夠在machine.config中指定。所以,在Session_End中,若是使用integrity security鏈接SQL,它將使用工做者進程帳號身份鏈接,這可能會引發登陸失敗.
6.由於Session_End是有獨立線程出發的, 因此在Session_End中沒法使用HttpContext對象(Request,Response,Server等對象都在HttpContext中), 即沒法使用 Response.Redirect 和Server.Transfer等方法.
我已經使用SqlServer模式對公司的多臺服務器實現了Session共享, 服務器重啓也不會致使用戶預約過程從新開始(預約過程須要的Session不會丟失). 但願本文對具體的Session服務器搭建人員有所幫助.
參考文獻:
使用一個 SQL 數據庫 SQL Server 會話狀態的全部應用程序可能致使瓶頸
http://support.microsoft.com/kb/836680/zh-cn
ASP.NET 中 Session 實現原理淺析 [1] /[2]
http://www.cnblogs.com/flier/archive/2004/08/04/30226.html
http://www.cnblogs.com/flier/archive/2004/08/07/30902.html
理解Session State模式+ASP.NET SESSION丟失FAQ [翻譯]
http://www.cnblogs.com/tonyqus/archive/2006/10/24/522618.html