天天看點

我心中的核心元件(可插拔的AOP)~分布式Session元件

回到目錄

對于目前的網站來說,為了滿足高可用,高并發,高負載,一台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");      

 回到目錄

作者:倉儲大叔,張占嶺,

榮譽:微軟MVP

QQ:853066980

支付寶掃一掃,為大叔打賞!

我心中的核心元件(可插拔的AOP)~分布式Session元件