狀態(tài)管理本來是一件很美好的事情,嘿嘿,只可惜總是有些廠商在實現(xiàn)的時候考慮得不那么周全。例如MS在ASP中的狀態(tài)管理實現(xiàn)就比較爛,因為只實現(xiàn)了一個進程內(nèi)的基于內(nèi)存的狀態(tài)管理,故而存在很多問題:
1.所有的Session數(shù)據(jù)都保存在Web服務的進程中,會造成服務器支持會話數(shù)量受到服務器內(nèi)存資源的限制問題,同時也因為大量非活動會話導致內(nèi)存被無效占用。
2.服務器進程崩潰會導致所有的會話數(shù)據(jù)丟失。
3.會話無法跨進程或在負載均衡情況下使用,除非負載均衡技術保障同一用戶每次都能被路由到同一機器上。就算這樣也無法保障服務器崩潰造成的會話數(shù)據(jù)丟失。
4.需要Cookie的支持,而現(xiàn)在因為安全性問題,很多人在瀏覽器中關閉了Cookie和js的支持。
為此ASP的使用者不得不自己手工將會話信息以會話ID為主鍵同步到外部數(shù)據(jù)庫中,以緩解類似問題。
而在ASP.NET中,因為設計時就考慮了這些問題,能夠避免這些限制:
1.支持進程外的狀態(tài)管理,通過獨立狀態(tài)管理服務或SQLServer狀態(tài)服務器管理會話狀態(tài)
2.支持不使用Cookie的狀態(tài)維護,通過在URL中自動增加會話ID來避免使用Cookie
3.通過獨立的狀態(tài)管理服務或SQLServer狀態(tài)服務器支持負載均衡時同步使用會話信息
實現(xiàn)這些特性的正是上節(jié)提到的 SessionStateModule .InitModuleFromConfig函數(shù)中,根據(jù) sessionState 標記的mode屬性選擇的四種不同的狀態(tài)管理器實現(xiàn)。
|
Off模式禁止會話管理,同時ASP.NET還允許通過在頁面中以EnableSessionState屬性細粒度管理頁面的會話支持狀態(tài)
|
InProc模式兼容以前ASP的策略,在ASP.NET同一進程空間內(nèi)實現(xiàn)基于內(nèi)存的會話狀態(tài)管理,速度最快但受到與ASP相同的限制;
StateServer模式通過ASP.NET獨立安裝的ASP.NETStateService服務(aspnet_state.exe),以stateConnectionString指定的IP和端口響應會話狀態(tài)服務;
SQLServer模式則通過sqlConnectionString指定的SQLServer服務器,以內(nèi)存臨時表(以InstallSqlState.sql建庫,使用tempdb內(nèi)存數(shù)據(jù)庫)或獨立表(以InstallPersistSqlState.sql監(jiān)控,使用獨立的ASPState庫)維護會話狀態(tài)。
這四種不同的狀態(tài)管理器,在性能上據(jù)《PerformanceTuningandOptimizingASP.NETAppliation》一書的測試,相對值如下:
以下為引用:
Table4-1:NormalizedTTLB(TimetoLastByte)bySessionStateMode(inMillisecondsper100Requests)
CONCURRENTBROWSERSMODE=OFFMODE=INPROCMODE=STATESERVERMODE=SQLSERVER
17.814.548.278.47
528.2820.2527.2529.29
1089.3846.0877.2985.11
Table4-2:AverageRequestsperSecondbySessionStateMode
CONCURRENTBROWSERSMODE=OFFMODE=INPROCMODE=STATESERVERMODE=SQLSERVER
118.8624.1718.3118.11
521.6625.7421.5421.34
1017.2323.818.1117.6
可以看到,無論是從TTLB還是每秒平均請求數(shù)來說,進程外狀態(tài)管理器的性能都是可以令人接受的,當然還需要針對狀態(tài)管理情況在編寫代碼時做相關優(yōu)化。不過要使用進程外狀態(tài)管理器,則保存在會話中的對象受到必須提高二進制序列化支持的限制。
從使用角度來看,狀態(tài)管理器實際上都是由上節(jié)提到的HttpSessionModule建立管理,并通過HttpSessionState接口提供訪問的,結構如下圖:
MSDN上的 UnderpinningsoftheSessionStateImplementationinASP.NET 一文非常詳細的解釋了幾種不同狀態(tài)管理器的原理和使用,這兒就不羅嗦了。
從實現(xiàn)角度來看,上節(jié)中提到的 SessionStateModule .InitModuleFromConfig函數(shù),根據(jù)配置文件中狀態(tài)管理器的模式,分別建立System.Web.SessionState.InProcStateClientManager,System.Web.SessionState.OutOfProcStateClientManager和System.Web.SessionState.SqlStateClientManager三類狀態(tài)管理器的實例。他們都繼承自System.Web.SessionState.StateClientManager抽象基類,并通過System.Web.SessionState.IStateClientManager接口向HttpApplication提高狀態(tài)管理服務。
IStateClientManager接口是狀態(tài)管理器的統(tǒng)一管理接口,主要提供以下功能:
|
ConfigInit方法主要在初始化狀態(tài)管理器時通知其根據(jù)配置進行初始化工作,并將負責會話狀態(tài)清除的SessionOnEndTarget對象實例綁定到會話管理器(我們后面討論會話狀態(tài)管理實現(xiàn)時詳細討論)。對OutOfProcStateClientManager和SqlStateClientManager來說,在此階段還會初始化與外部服務器的連接,并通過一個System.Web.Util.ResourcePool實例,提供基于時間策略的資源池來維護連接;
ResetTimeout方法重置指定Session的超時時間;對InProcStateClientManager來說,這個超時時間是通過System.Web.Caching.CacheInternal類型實現(xiàn)的緩存對象來使用的;OutOfProcStateClientManager直接通過MakeRequest函數(shù)構造請求發(fā)給外部獨立的狀態(tài)管理器執(zhí)行;SqlStateClientManager則調(diào)用存儲過程TempResetTimeout更新ASPStateTempSessions表的過期時間Expires字段;
Dispose方法是否狀態(tài)管理器的資源,落實到代碼就是對OutOfProcStateClientManager和SqlStateClientManager中資源池的釋放;
Set方法則將指定的SessionStateItem存儲到id相關的會話數(shù)據(jù)中,并根據(jù)inStorage指定的對象狀態(tài),決定在發(fā)生異常的情況下是否釋放對此會話的鎖。與ResetTimeout的實現(xiàn)類似,OutOfProcStateClientManager發(fā)送請求給外部獨立的狀態(tài)管理器;SqlStateClientManager調(diào)用存儲過程TempUpdateStateItemXXX更新會話狀態(tài)表ASPStateTempSessions中的過期時間Expires字段、鎖定狀態(tài)Lock字段、以及狀態(tài)信息SessionItemShort/SessionItemLong(分別保存7000字節(jié)以下或之上的數(shù)據(jù))。如發(fā)生異常并設置inStorage標記,則先調(diào)用TempReleaseStateItemExclusive釋放會話鎖。
對狀態(tài)管理器中數(shù)據(jù)的獲取較為復雜,IStateClientManager接口使用的是異步調(diào)用的模式,并為提高效率將獨占的獲取數(shù)據(jù)單獨拿出來。狀態(tài)管理器實現(xiàn)類通過通用基類System.Web.SessionState.StateClientManager實現(xiàn)的幾個工具方法,將數(shù)據(jù)獲取操作異步化。再最終由實現(xiàn)類通過Get和GetExclusive方法完成操作。獲取數(shù)據(jù)的方法InProcStateClientManager通過緩存;OutOfProcStateClientManager通過請求;SqlStateClientManager通過TempGetStateItemXXX存儲過程完成。
在了解了 SessionStateModule 控制的狀態(tài)服務器的實現(xiàn)和使用方法后,我們來看看上層的HttpSessionState是如何使用的。
MandeepSBhatia的 ASP.NETSessionManagementInternals 介紹了HttpSessionState內(nèi)部完成狀態(tài)信息管理的原理。HttpSessionState的Item屬性實際上是通過SessionDictionary實例實現(xiàn)的。
|
而此SessionDictionary實例與HttpSessionState實例的構造,都是在前面提到的完成會話構造的 SessionStateModule .CompleteAcquireState方法中完成的:
|
這兒涉及到的幾個字段,基本上都能跟HttpSessionState提供的公共屬性對應起來。需要注意的是HttpSessionState.StaticObjects是通過ASP.NET頁面上的<objectRunat="Server"Scope="Session"/>類似標記靜態(tài)定義的;_rqReadonly則是前面提到的<%@PageEnableSessionState="ReadOnly"%>標記設置的。
至此,狀態(tài)管理器的使用與實現(xiàn)方法基本上分析完成,下面整理一下其使用流程:
1.構造:HttpApplication在初始化過程中調(diào)用InitModules初始化配置文件Machine.config中注冊的實現(xiàn)了IHttpModule接口的HTTP模塊;其中 SessionStateModule 作為模塊之一被構造并初始化;其InitModuleFromConfig方法根據(jù)配置文件中狀態(tài)管理器的相關配置,構造并初始化相應的狀態(tài)管理器;并根據(jù)各種條件調(diào)用CompleteAcquireState方法完成HttpSessionState的構造工作。
2.使用:HttpSessionState通過SessionDictionary實現(xiàn)其Item屬性的狀態(tài)數(shù)據(jù)管理;SessionDictionary本身由 SessionStateModule .OnReleaseState在適當?shù)臅r候寫回狀態(tài)管理器;其他維護操作也是通過 SessionStateModule 調(diào)用狀態(tài)管理器的IStateClientManager接口完成的。
3.實現(xiàn):狀態(tài)管理器從抽象基類StateClientManager獲得異步調(diào)用的封裝;通過IStateClientManager接口提供給 SessionStateModule 管理其初始化、釋放和管理的接口。
雖然ASP.NET做了很多工作,但個人感覺還遠遠不夠。例如InProc/OutOfProc實際上都是在內(nèi)存中,只是解決了一個可靠性和數(shù)據(jù)集中同步的問題;SQLServer雖然能夠解決容量、可靠性和數(shù)據(jù)集中同步的問題,但效率又受到影響。這方面.NET應該向Java好好學習一下,例如Java下 EHCache 和 OSCache 都提供了平滑的可配置二級(內(nèi)存/硬盤)緩存介質(zhì)切換,并且后者還提供了對負載均衡的簡單支持,此外還有JBoss等實現(xiàn)的基于IP多播等實現(xiàn)技術的負載均衡緩存實現(xiàn)等等,都遠遠超出了ASP.NET提供的緩存機制所考慮到的范圍。雖然ASP.NET也有獨立的緩存機制,MS也提出了CacheApplicationBlock的參考實現(xiàn),不過還是任重而道遠啊,呵呵
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
