使用SQL Server In-Memory存儲ASP.NET的會話狀態(tài)
從以前的 “classic” ASP 到目前的 ASP.NET 4.5 Web Forms,很多開發(fā)者依賴ASP.NET 會話狀態(tài)作為重要的臨時保存每個用戶的數(shù)據(jù)的主要手段。 它的特征是在用戶訪問web應(yīng)用程序的過程中,允許開發(fā)者存儲和讀取用戶的數(shù)據(jù)。 會話數(shù)據(jù)是自動從存儲中持續(xù)保存和恢復(fù),并且自動過期刪除。
問題
使用Session State的替代方案這些內(nèi)容超出了本文的范圍。 對于依賴Session State的應(yīng)用程序也有陷阱,最常見的是訪問每個用戶,每個請求的Session基礎(chǔ)數(shù)據(jù)。這種獨特的訪問是維持Session State的一致性的一種方式,并且是通過設(shè)計實現(xiàn)了這種方式。 如果你對這樣殘暴細(xì)節(jié)的設(shè)計感興趣, 他們在題名為“鎖定會話狀態(tài)數(shù)據(jù)”章節(jié)這里解釋了。會話狀態(tài)常見于ASP.NET Web窗體應(yīng)用程序,而ASP.NET MVC在較小程度上使用了TempData(POST數(shù)據(jù)到GET作為例子) 。
Web應(yīng)用程序主要利用Session狀態(tài)來協(xié)調(diào)彼此間的工作。作為對比,客戶端腳本較多的重量級web應(yīng)用通常擁有更高的并發(fā)請求,這種情況下使用Session狀態(tài)訪問資源需要對Session加鎖和解鎖,從而成為了Web應(yīng)用的瓶頸。不限制類型的Web應(yīng)用將會成為另外一個瓶頸因為需要足夠的存儲空間維持它們的會話的狀態(tài)。有三種途徑優(yōu)化Session狀態(tài)的訪問,使得一些請求可以不需要session或者使用只讀的,但是如果加載后應(yīng)用規(guī)模持續(xù)增大,最終仍然會有瓶頸。
目前的狀況
基于這些考慮目前的ASP.NET的會話狀態(tài)仍然使用的非常普遍。在許多領(lǐng)域我不斷看到許多消費者在有大量擴(kuò)展的Web應(yīng)用中使用會話狀態(tài)。對大量企業(yè)級用戶而言,內(nèi)部使用ASP.NET窗體應(yīng)用更為普遍。對于這些消費者而言,如何選擇Session State存儲提供商是相當(dāng)關(guān)鍵的。這些提供商必須將Session字典的內(nèi)容序列化存儲在耐用的設(shè)備上并反序列化從中提取數(shù)據(jù)(通常使用BLOB應(yīng)用程序)。這里有許多提供商可供選擇,包括Microsoft和第三方開發(fā)者提供的工具。目前Microsoft提供了下面的Session存儲工具,假定ASP.NET應(yīng)用部署在企業(yè)內(nèi)部:
Session Provider |
Can be Highly Available? |
Can be Geo Redundant? |
Can be used in Web Farms? |
Performance? |
In-Proc |
No |
No |
No |
Excellent |
State Server |
No |
No |
Yes |
Good |
SQL Server (Traditional) |
Yes |
Yes |
Yes |
Fair |
AppFabric Caching |
Yes |
No |
Yes |
Good |
SQL Server (In-Memory) |
Yes* |
Yes |
Yes |
Excellent |
*需要在 in-memory表中將模式和數(shù)據(jù)標(biāo)記為持久的
如果你的應(yīng)用程序需要Session State高可用,同時支持跨web farm的部署,你可以從Microsoft提供的選項,僅限于SQL Server或者AppFabric Caching.SQL Server有一個增加的優(yōu)勢,它可以跨越數(shù)據(jù)中心來提供地理冗余(geo-redundancy).而AppFabric則受限于單一數(shù)據(jù)中心.實際應(yīng)用中,這兩種解決方案都工作良好.但是,傳統(tǒng)的SQL Server實現(xiàn)常常遇到瓶頸,產(chǎn)生的原因是基于單一磁盤的表存在競爭.競爭導(dǎo)致阻塞,死鎖,或者其它不友好的變化.這影響了它存儲和恢復(fù)會話的時間.另外,在刪除操作過程中,當(dāng)先前的會話數(shù)據(jù)由于鎖的擴(kuò)大和競爭的延續(xù)而清除了,這也會存在問題.
SQL Server 2014的新選項
為了解決老版本SQL Server安裝包的性能問題,SQL Server團(tuán)隊最近發(fā)布了新的安裝包“Microsoft ASP.NET Session State provider for SQL Sever In-Memory”作為NugGet包.在this case study中有這個安裝包不可思議的性能提升的證明.它在ASP.NET應(yīng)用程序中使用Session State,每秒處理250,000個請求!這個新實現(xiàn)使用了SQL Server 2014稱為"Hekaton"的內(nèi)存優(yōu)化表特性.這需要這個產(chǎn)品的2014版本.這個安裝包如何在老版本SQL Server會話狀態(tài)安裝包上有所提升的呢?
-
會話存儲的持續(xù)性是通過內(nèi)存優(yōu)化表而不是磁盤表.對于繁重的訪問模型,如存儲會話狀態(tài)等,內(nèi)存優(yōu)化表是全事務(wù)的,可持續(xù)性和理想的.這類表使用無鎖數(shù)據(jù)結(jié)構(gòu)和優(yōu)化的,多版本的并發(fā)控制.
-
為了更進(jìn)一步提升性能,可用本地編譯存儲過程來恢復(fù)和存儲會話數(shù)據(jù). 本質(zhì)上,這是一種新型的存儲過程,它被編譯為本地機器代碼.
這兩個SQL 2014產(chǎn)品特性,解決了主要的性能和競爭問題,這些問題存在于基于磁盤實現(xiàn)的舊的傳統(tǒng)的SQL Server安裝包.安裝和配置這個程序是相當(dāng)直接的.通過NuGet包管理控制臺,可以按照下面的方式安裝:
Install-Package Microsoft.Web.SessionState.SqlInMemory.
在你的應(yīng)用程序中,NuGet包將增加一個到Microsoft.Web.SessionState.SqlInMemory的引用,同時也會增加一個名為ASPStateInMemory.sql的腳本文件來安裝SQL Server 2014 Session State數(shù)據(jù)庫.這個文件包含了必須的DDL來安裝數(shù)據(jù)庫.在SQL腳本中有一些項,你想要審查或者最可能審查或修改的:
-
這個數(shù)據(jù)庫的名字默認(rèn)是ASPStateInMemory.
-
數(shù)據(jù)庫的主文件組路徑.
-
數(shù)據(jù)庫的MEMORY_OPTIMIZED_DATA文件組路徑.
-
BUCKET_COUNT的大小信息,它基于會話中的項的預(yù)期大小.
-
讓會話中的表可持久或非可持久的決定(涉及到是否需要會話高可用)
以上的第五個部分,需要對已經(jīng)存在的SQL Server會話數(shù)據(jù)庫作一些分析,它可能像計算傳統(tǒng)ASP.NET SQL Server會話模式里BLOB列的DATALENGTH()一樣簡單.對于InProc或者StateServer來說,決定會話項的平均大小會更加困難,但可以通過捕獲w3wp.exe或者StateServer進(jìn)程的內(nèi)存dump來實現(xiàn),其間檢查在會話字典中的項的數(shù)目和大小.對于InProc或者StateServer,關(guān)于會話中的項的數(shù)目,有性能計數(shù).***的建議總是測試和調(diào)整.
讓基于內(nèi)存的會話高可用
默認(rèn),SQL Server 2014基于內(nèi)存會話的內(nèi)存優(yōu)化表是標(biāo)記為非持久的.這意味著,這些表里的數(shù)據(jù)變化是過渡性的一致.這些變化沒有記錄在日志中,這意味著如果SQL Server重啟了,服務(wù)器重啟了或者任何形式的故障恢復(fù)發(fā)生(FCI或者AlwaysOn),所有的會話數(shù)據(jù)將丟失.設(shè)置這個默認(rèn)值是因為性能.為了讓這些內(nèi)存優(yōu)化表可持續(xù),需要在ASPStateInMemory.sql腳本中做三點改變.在腳本中有一些注釋解釋了為何需要做這些改變.
-
按下面的方式修改SessionItems表.
-
修改WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY)
-
為WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_AND_DATA)
-
取消語句的注釋(注意***的逗號): Id bigint IDENTITY,
-
取消語句的注釋(注意***的逗號,根據(jù)需要修改1000000 * 2為real值,在這個語句前讀T-SQL注釋以選擇一個起始值): CONSTRAINT [PK_SessionItems_Id] PRIMARY KEY NONCLUSTERED HASH (Id) WITH (BUCKET_COUNT = 2000000),
-
-
修改會話表
-
修改WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY
-
為WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_AND_DATA)
-
只要做了這些修改,我們可以讓數(shù)據(jù)庫成為部分SQL Server AlwaysOn可用性組.當(dāng)故障恢復(fù)時,會話數(shù)據(jù)將會保留.由于增加的重試邏輯,所以,當(dāng)一個自動的或者人為的故障恢復(fù)發(fā)生時,連接池中的過期連接不會產(chǎn)生異常拋出給終端用戶.
請注意,即使我們設(shè)置表為非可持續(xù)的,將會話數(shù)據(jù)庫放入SQL Server AlwaysOn可用性組,但會話表中的數(shù)據(jù)在復(fù)制(只有schema可用)時不可用.對于客戶負(fù)荷,這個"schema only"復(fù)制模型,通過使用非可持續(xù)內(nèi)存優(yōu)化表,已足夠來保證性能提升.
這個最簡單的高可用的拓?fù)鋵QL Server In-Memory來說是最合適的,它與下面的類似:
-
位于子網(wǎng)(數(shù)據(jù)中心)A的SQL Server 2014 Node 1
-
位于子網(wǎng)(數(shù)據(jù)中心)B的SQL Server 2014 Node 2
-
位于子網(wǎng)(數(shù)據(jù)中心)C的文件共享
這個拓?fù)涮峁┝说乩砣哂?自動故障恢復(fù)和維持了1/3的數(shù)據(jù)中心完整的丟失連接.Windows Server 2012 R2的動態(tài)特性,使得自動維持2個數(shù)據(jù)中心的丟失連接成為可能.(***的男人的場景[last man standing scenario]).
ASP.NET 配置文件
在 ASP.NET web 應(yīng)用程序的配置文件web.config中,配置一個新的provider,并且按照下面編輯它。
<sessionState mode="Custom" customProvider="SqlInMemoryProvider">
<providers>
<add name="SqlInMemoryProvider"
type="Microsoft.Web.SessionState.SqlInMemoryProvider"
connectionString="Data Source=AGAspNet; Initial Catalog=ASPStateInMemory;Integrated Security=True;" />
</providers>
</sessionState>
在上面的代碼片段中, ‘AGAspNet’ 是SQL Server 2014 中永遠(yuǎn)可用的監(jiān)聽者名字。
一個快速的例子
使用ASP.NET網(wǎng)頁表單4.5應(yīng)用,并在會話中編寫簡單的帶有時間戳的字符串,SQL Server 2014中便生成如下的數(shù)據(jù):
注意在SQLNode1-2014中,AspStateInMemory數(shù)據(jù)庫的位置.接下來,我們手動進(jìn)行故障恢復(fù)可用性組.
在SQLNode2-2014上,會話現(xiàn)在可用了,而且不會干擾ASP.NET應(yīng)用程序.簡單的敲擊web應(yīng)用程序的F5,以獲取來自會話的數(shù)據(jù),而不會向客戶端拋出異常.
過期會話會怎么樣呢?
在舊的SQL Server會話中,一個SQL Agent作業(yè)創(chuàng)建后用來刪除過期會話.在新版本中,提供了一個必須被作業(yè)調(diào)用的存儲過程[dbo].[DeleteExpiredSessions].默認(rèn),會話超時時間為20分鐘.每次一個會話項被訪問,超時被重置以保持用戶會話“存活”.
概述
在新的會話狀態(tài)中,有許多有意思的細(xì)節(jié).我鼓勵你為自己而深入研究代碼.你將會發(fā)現(xiàn)它是一段奇妙的學(xué)習(xí)旅程,其間是關(guān)于SQL Server 2014 基于內(nèi)存的OLTP "Hekaton"特性的性能和限制.一個特別的屬性包含在代碼中,以模擬內(nèi)存中存儲BLOB類型的數(shù)據(jù).內(nèi)存優(yōu)化表現(xiàn)在不支持BLOB類型.序列化的會話字典和可能的大BLOB數(shù)據(jù)類型有什么不同呢?其中使用的預(yù)處理程序(sprocs)將序列化的會話分拆為7000字節(jié)的數(shù)據(jù)塊,以增強大的會話項數(shù)據(jù)的存儲.
精明的讀者可能已經(jīng)發(fā)現(xiàn),在我的屏幕截圖中, [SessionItems]表中并沒有數(shù)據(jù)行,但在[Sessions]表中有一行數(shù)據(jù).如果我的會話內(nèi)容超過了7000字節(jié),你應(yīng)該會在[SessionItems]表中看到"溢出"(spill over)行.關(guān)于這方面,在ASP.NET會話存儲之外,有許多其它潛在的應(yīng)用程序,我很可能在下一篇文章中深入挖掘這點.
本地編譯存儲過程也值得一看.有一些技巧來處理本地編譯存儲過程的限制,如缺少CASE語句的支持.這個限制是因為,只要預(yù)處理程序(sproc)編譯為本地代碼,是不允許進(jìn)行分支的!
如果你在考慮使用這個新特性,有如下關(guān)鍵點和問題需要考慮:
-
內(nèi)存優(yōu)化表由內(nèi)存來支撐!你的SQL Server在峰值負(fù)載時,有足夠的內(nèi)存來包含所有的會話數(shù)據(jù)嗎?
-
默認(rèn)表是非可持久的.請仔細(xì)考慮你的高可用性的需求.不管是可持久還是非可持久,性能將超出你現(xiàn)在使用的傳統(tǒng)SQL Server數(shù)據(jù)庫的會話和模式.
-
閱讀SQL文件中的注釋,調(diào)整BUCKET_COUNT為非簇集HASH索引.以下是SessionItems表DDL語句的代碼片段.
祝你好運!請在評論中分享你使用新版本的經(jīng)驗!
英文原文:ASP.NET Session State using SQL Server In-Memory
譯文出自:http://www.oschina.net/translate/asp-net-session-state-using-sql-sever-in-memory