對于目前的網站來說,為了滿足高可用,高并發,高負載,一臺WEB服務器已經遠遠不夠用了,以后的WEB應用服務器應該是一種集群的環境,它們之間使用一些工具進行數據的同步,在由1臺變成多臺服務器時,有一個問題是我們必須要考慮的,Session機制,我們都知道Session被用來存儲用戶的一些憑證信息,持久化到服務器上,這在安全性方面得到了保證(比存儲到客戶端的cookies),而當你的WEB應用服務器是多臺時(多臺之間做了負載均衡),這種Session機制就有問題了,因為你無法實現從一臺服務器到別一臺服務器的內存(緩存)共享,這也是不安全的,所以,在出現緩存中間件出現之后,就有了一種新的技術也跟著出現了,即Session中間件,比較成熟的組件是StackExchange.Redis+RedisSessionStateProvider,即使用Redis實現的Session機制,它將session數據存儲到了一臺(可以是redis集群)redis服務器上,這時,多臺WEB應用服務器之間的數據就是唯一的了,不需要進行同步了。
下面介紹實現步驟
1 使用nuget安裝redis緩存 StackExchange.Redis
2 使用nuget安裝RedisSession服務 RedisSessionStateProvider
3 從nuget添加RedisSession之后,它會在你的config文件中寫入以下內容,主要是對session進行持久化設置的
<sessionState mode="Custom" customProvider="MySessionStateStore"> <providers> <!-- Either use 'connectionString' and provide all parameters as string OR use 'host','port','accessKey','ssl','connectionTimeoutInMilliseconds' and 'operationTimeoutInMilliseconds'. --> <!-- 'throwOnError','retryTimeoutInMilliseconds','databaseId' and 'applicationName' can be used with both options. --> <!-- <add name="MySessionStateStore" host = "127.0.0.1" [String] port = "" [number] accessKey = "" [String] ssl = "false" [true|false] throwOnError = "true" [true|false] retryTimeoutInMilliseconds = "5000" [number] databaseId = "0" [number] applicationName = "" [String] connectionTimeoutInMilliseconds = "5000" [number] operationTimeoutInMilliseconds = "1000" [number] connectionString = "<Valid StackExchange.Redis connection string>" [String] loggingClassName = "<Assembly qualified class name that contains logging method specified below>" [String] loggingMethodName = "<Logging method should be defined in loggingClass. It should be public, static, does not take any parameters and should have a return type of System.IO.TextWriter.>" [String] /> --> <add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false" /> </providers> </sessionState>
4 下載是新版本的redis服務端,可以是windows版的,我用的是2.6.13,低版本的redis會出現Eval命令無法識別的問題
5 處理完成,可以測試你的session了,默認過期時間為1200秒
前臺使用Session時和原來沒有任何分別
public ActionResult TestSession() { Session["username"] = "zzl"; Session["test"] = "hello world!"; return Content("完成..." + Session["test"]); }
這種不修改以有代碼就可以實現不同功能策略的方式就是我們的IoC,控制反轉技術(也是依賴注入DI的范疇),這也是編程語言發展到一定階段的必然產物,即解決復雜的業務的應對之道!
下面是網友對rediscache進行的擴展,讓它支持復雜類型,默認支持簡單類型,如果希望支持復雜類型,需要為類型添加“可序列化”的特性,因為我們在redis里存儲時,都是以二進制字節數組的形式存儲的。
/// <summary> /// 對RedisCache的擴展,讓它支持復雜類型、 /// RedisValue 類型可以直接使用字節數組,因此, /// 調用 Get 幫助程序方法時,它會將對象序列化為字節流,然后再緩存該對象。 /// 檢索項目時,項目會重新序列化為對象,然后返回給調用程序。 /// </summary> public static class SampleStackExchangeRedisExtensions { public static T Get<T>(this IDatabase cache, string key) { return Deserialize<T>(cache.StringGet(key)); } public static object Get(this IDatabase cache, string key) { return Deserialize<object>(cache.StringGet(key)); } public static void Set(this IDatabase cache, string key, object value) { cache.StringSet(key, Serialize(value)); } static byte[] Serialize(object o) { if (o == null) { return null; } BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream()) { binaryFormatter.Serialize(memoryStream, o); byte[] objectDataAsStream = memoryStream.ToArray(); return objectDataAsStream; } } static T Deserialize<T>(byte[] stream) { if (stream == null) { return default(T); } BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream(stream)) { T result = (T)binaryFormatter.Deserialize(memoryStream); return result; } } }
對復雜類型進行存儲和讀取的方法如下
cache.Set("zzlList", new List<TestCache> { new TestCache { ID = 1, Name = "占占", AddTime = DateTime.Now } }); var o = cache.Get("zzlList");
文章列表