在ASP.NET MVC中使用分散式快取
http://www.cnblogs.com/024hi/archive/2008/08/29/1279409.html
使用快取是提高ASP.NET MVC應用程式效能的最好方式。我們知道,在ASP.NET MVC中最耗時的操作非資料庫的讀取莫數,那麼,儘量的避免讀取資料庫顯然成為了提升效能最好的辦法。快取可以將經常訪問的資料保持在記憶體中從而大幅減少資料庫的讀取。
由於ASP.NET MVC是ASP.NET框架的一部分,這使得我們在ASP.NET MVC中仍然可以使用標準的System.Web.Caching.Cache物件。標準的ASP.NET快取物件很好很強大,我們可以通過它指定某些資料在特定的時間內被快取,建立快取項與檔案系統或者資料庫表之間的依賴,甚至可以在不同的快取向之間建立複雜的依賴鏈。也就是說,我們可以通過ASP.NET快取物件作很多很多很多…的事情。
但是標準的ASP.NET快取物件的也有一些限制,比如它只能和我們的web應用程式執行在同一個程序,也就是說它並不是分散式的。不同應用程式間的快取並不能共享,我們只能為每個應用程式構造相同的快取。
在單一伺服器架構下,傳統的ASP.NET快取在web應用程式中工作得非常好。但是當我們想使用伺服器組等叢集架構時,問題就出現了。比如我們有一個需要處理成十億上百億使用者訪問的web應用程式(譯者按:這有點誇張吧…),或者當我們的伺服器出現故障時我們並不想重新從快取載入資料。當我們欲在多組web伺服器上共享快取是,分散式快取應運而生。
在這篇文章中我將向您解釋如何在ASP.NET MVC應用程式中使用代號為Velocity的微軟分散式快取策略。建立和使用Velocity十分的簡單,從標準的ASP.NET快取轉換至Velocity分散式快取也不會使您痛苦萬分。
同時我也會說明如何將Velocity作為會話狀態提供者(session state provider).Velocity允許您在MVC應用程式伺服器群組中使用ASP.NET會話狀態。您可以通過Velocity在分散式快取中儲存會話狀態。
Velocity的安裝和配置
當你看到這篇文章的時候,Velocity和ASP.NET MVC一樣還沒有正式釋出,仍然處於Preview的狀態。不過你現在就可以下載Velocity來一個提前體驗。
下面的地址中包括所有有關Velocity相關資訊。
您可以通過這個頁面的連結下載Velocity。
安裝Velocity十分簡單,您需要將它安裝在您想使用分散式快取的伺服器上(快取伺服器),快取會從這些伺服器上自動的組織起來。
在將Velocity安裝在快取伺服器上之前,您需要在您的網路中建立一個共享以便所有的快取伺服器都能夠訪問它。這個檔案共享將包括快取配置檔案(ClusterConfig.xml)。這個檔案是一個標準的XML檔案,它用來對分散式快取進行相關配置。
在Beta版中,您必須在這個檔案共享上給予Everyone帳號讀寫許可權。右鍵單擊資料夾,選擇屬性選單然後選擇安全選項單。點選編輯按鈕,選擇新增,輸入Everyone然後點選OK即可。這裡要確認Everyone帳號具有讀寫許可權。
當您執行Velocity(圖1)的安裝程式時,您將被要求填入如下資訊:
· Cluster Configuration Share – 這裡的路徑指向您剛剛建立的檔案共享.
· Cluster Name – 組名稱. 按照您的意願起個名字吧 (比如, MyCacheCluster).
· Cluster Size – 您期望在這個組中使用的快取伺服器的數量.
· Service Port Number – 應用程式和快取伺服器通訊的埠(注意如果您有防火牆,您需要在防火牆中解除對該埠的遮蔽)
· Cluster Port Number -- 快取伺服器之間通訊的埠。Velocity將使用這個埠號。(同樣需要在防火牆中解除遮蔽)
· Max Server Memory – 允許Velocity在這臺伺服器上使用的記憶體最大值。
圖 1 – 安裝 Velocity
您必須在每檯安裝Velocity後的伺服器上配置防火牆的例外規則,否則Velocity的通訊將被阻止。您可以為DsitributedCache.exe程序或者為每個埠號(22233埠,22234埠和22235埠等)建立一個防火牆例外規則。
使用 Velocity 管理工具
您可以通過Velocity Administration Tool命令列工具管理Velocity(圖2)
圖2 2 – Velocity 管理工具
Velocity管理工具支援如下命令(這些命令十分有用):
· start cluster – 為組中的每一臺快取伺服器啟動Velocity。
· stop cluster – 與上一條正相反。
· create cache – 建立並命名一個新快取。
· delete cache – 刪除一個已存在的快取。
· list host – 列出組中的所有快取伺服器
· list cache – 類出組中的所有快取配置。
· show hoststats <cache server>:<cache port>– 列出指定快取伺服器上的統計資訊。
安裝Velocity後您需要做的第一件事就是使用如下命令啟動快取組:
start cluster
在ASP.NET MVC應用程式中使用Velocity
完成Velocity的建立和啟動後,您可以建立一個使用Velocity快取的ASP.NET MVC應用程式。為了在專案中使用Velocity,您需要新增對如下程式集的引用:
· CacheBaseLibrary.dll
· ClientLibrary.dll
您可以在Program Files\Microsoft Distributed Cache資料夾或任意一臺安裝了Velocity的機器上找到這些dll.您也可以將這些dll從快取伺服器上拷貝到您的開發環境中。
同時,您需要修改您的ASP.NET MVC應用程式的web.config檔案。在<configSections>節點中新增如下子節點:
- <section name="dcacheClient"
- type="System.Configuration.IgnoreSectionHandler"
- allowLocation="true" allowDefinition="Everywhere"/>
接下來,在配置檔案的任意位置新增如下節點:
- <dcacheClient deployment="simple" localCache="false">
- <hosts>
- <!--List of hosts -->
- <host name="localhost"
- cachePort="22233"
- cacheHostName="DistributedCacheService" />
- </hosts>
- </dcacheClient>
在這裡您可能需要改動一下host節點下name為“localhost”的值。換句話說,MVC應用將在本地使用快取服務。如果快取伺服器不在您的本地環境中,您需要更改這個值,以使它指向正確的伺服器。
增加快取項及從快取中檢索指定項
分散式快取的使用方式和普通的ASP.NET快取使用方式十分相似。您可以使用如下的方法在分散式快取中增加,獲取和移除快取項:
· Add() – 向分散式快取中新增一項.如果此項的鍵已經存在,那麼將會丟擲一個異常。
· Get() – 按照指定的鍵從分散式快取中獲取快取項。
· Put () – 向分散式快取中新增一項.如果此項的鍵已經存在,那麼它將會被替換。
· Remove() – 從分散式快取中移除一個存在的快取項。
讓我們看看示例,程式碼段1中的controller使用分散式快取來快取影視資料庫中的記錄。
程式碼段 1 – HomeController.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using System.Data.Caching;
- using Tip39.Models;
- using System.Diagnostics;
- using System.Web.Configuration;
- using System.Web.Hosting;
- using System.Data.Linq.Mapping;
- using System.Data.Linq;
- namespace Tip39.Controllers
- {
- [HandleError]
- public class HomeController : Controller
- {
- private DataContext _dataContext;
- private Table<Movie> _table;
- public HomeController()
- {
- // Get connection string
- var conString = WebConfigurationManager.ConnectionStrings["Movies"].ConnectionString;
- // Get XML mapping source
- var url = HostingEnvironment.MapPath("~/Models/Movie.xml");
- var xmlMap = XmlMappingSource.FromUrl(url);
- // Create data context
- _dataContext = new DataContext(conString, xmlMap);
- _table = _dataContext.GetTable<Movie>();
- }
- public ActionResult Index()
- {
- // Try to get movies from cache
- var factory = new CacheFactory();
- var cache = factory.GetCache("default");
- var movies = (List<Movie>)cache.Get("movies");
- // If fail, get movies from db
- if (movies != null)
- {
- Debug.WriteLine("Got movies from cache");
- }
- else
- {
- movies = (from m in _table select m).ToList();
- cache.Put("movies", movies);
- Debug.WriteLine("Got movies from db");
- }
- // Display movies in view
- return View("Index", movies);
- }
- }
- }
Index()方法返回資料庫中所有的行。首先,這個方法試圖從快取中獲取資料,如果獲取失敗,則從資料庫中獲取資料並在快取中新增一個快取項。
Index()方法點用Debug.WriteLine()來向Visual Studio控制檯視窗顯示訊息。無論資料是從快取還是從資料庫取出的,控制檯視窗都會忠實的體現出來。(圖2)
圖 2 – 使用Visual Studio 控制檯跟蹤快取行為
您也可以使用Velocity管理工具監視分散式快取。執行如下命令來顯示分散式快取的統計資訊:
show hoststats server name:22233
將“server name”替換成您的快取伺服器的名稱(很可惜,在這裡不能使用“localhost”)。執行這條命令後,您將得到有關分散式快取非常全面的統計資訊,如快取項的數量,快取大小,快取被呼叫的次數等等(圖3)。
圖 3 – 快取統計
程式碼段1中的Index()方法首先例項化了一個CacheFactory類。這個類用來從分散式快取中提取特定的快取項。
Velocity可以管理不同名稱的快取。您可以將不同的資料通過不同的快取組織起來。想象一下,每個具有特定名字的快取就像一個分散式資料庫。如果您是第一次安裝Velocity,您會得到一個預設的叫做“default”的快取項。在程式碼段1中,CacheFactory就是用來從獲取這個被命名為“default”的快取項的。
接著,Cache.Get()方法用來從從快取中獲取電影資料庫中的記錄。當Index()方法第一次被執行時,Get()方法不會返回任何值。因為分散式快取中並不存在任何資料。
如果Get()方法從快取中獲取資料記錄失敗,則會真正的從資料庫中獲取記錄。然後這些記錄在Put()方法的幫助下新增到分散式快取中。
這裡要注意一下,利用快取儲存或者獲取的資料都是無型別的物件。在您使用這些物件之前,您必須將它們轉換為特定的型別。典型的情況是比如您將分散式快取應用於產品資訊,您需要建立一個強型別的產品資訊類。
另外您還需要注意的是,當Visual Studio專案重新啟動或編譯後分布式快取仍然有效。如果您需要在開發時隨時清除快取,請在Velocity管理工具中使用這些命令
stop cluster
start cluster
我們可以快取哪些資料?
您可以將任何可序列化的型別新增到快取中。也就是說您可以將所有標記了[Serializable]特性的型別新增到快取中去。(這個類所有依賴的型別也必須是可序列化的) 程式碼段1中的Home controller使用LINQ to SQL來從資料庫中獲取資料記錄。當在分散式快取中應用LINQ to SQL時您必須注意,取決於您建立LINQ to SQL類的方式,這列類有可能不允許被序列化。
如果您使用物件關係設計器建立您的LINQ to SQL類則將導致所有的型別不可以被序列化。為了解決這個問題,我選擇手動建立LINQ to SQL類。請看程式碼段2中的Movie.cs類。
程式碼段 2 – Models\Movie.cs
- using System;
- namespace Tip39.Models
- {
- [Serializable]
- public class Movie
- {
- public int Id { get; set; }
- public string Title { get; set; }
- public string Director { get; set; }
- public DateTime DateReleased { get; set; }
- }
- }
注意,Movie類被包含[Serializable]特性
程式碼段3中的XML mapping檔案被用於HomeController被構造時初始化LINQ to SQL資料上下文。這個XML mapping檔案將Movie類和它的屬性對映到Movies表和欄位。
程式碼段 3 – Models\Movie.xml
- <?xml version="1.0" encoding="utf-8" ?>
- <Database Name="MoviesDB" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
- <Table Name="Movies" Member="Tip39.Models.Movie">
- <Type Name="Tip39.Models.Movie">
- <Column Name="Id" Member="Id" IsPrimaryKey="true" IsDbGenerated="true"/>
- <Column Name="Title" Member="Title" />
- <Column Name="Director" Member="Director" />
- <Column Name="DateReleased" Member="DateReleased" />
- </Type>
- </Table<