菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
466
0

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

原创
05/13 14:22
阅读数 11984

回到目录

对于目前的网站来说,为了满足高可用,高并发,高负载,一台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");

 回到目录

发表评论

0/200
466 点赞
0 评论
收藏