zoukankan      html  css  js  c++  java
  • Redis群集实现Asp.net Mvc分布式Session

    Session的缺点

    众所周知Asp.net Session默认存储在IIS中,IIS的重启会导致Session丢失。

    如果你的网站使用了session,当网站并发过大时可能引起溢出。

    配置Redis 集群


    安装Redis

    创建一个文件,进入该文件夹

    下载Redis 地址:http://download.redis.io/releases/redis-3.0.4.tar.gz

    tar -xvf redis-3.0.4.tar.gz 解压文件

    cd redis-3.0.4 进入解压的文件

    make && make install 安装

    创建三个文件夹

    把redis.conf文件分别复制到这三个文件夹

    然后分别进入这三个文件夹修改配置文件和指定不同的端口

    1.daemonize yes  (开启后台运行)

    2.port 6379 (端口)

    3.pidfile /var/run/redis-6379.pid (Redis 以守护进程的方式运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid,你可以配置到其他地址。当运行多个 redis 服务时,需要指定不同的 pid 文件和端口)

    4.cluster-enabled yes (是否启用集群)

    5.cluster-config-file "nodes-6379.conf" (nodes 节点文件)

     

     安装ruby环境

    yum -y install zlib ruby rubygems

    gem install redis

    开启服务

    分别开启这三个实例

    查看是否开启

     创建集群

    首先,进入redis的安装包路径下

    cd /usr/local/src/redis/redis-3.0.1/src/

    执行命令:

    ./redis-trib.rb create --replicas 0 ./redis-trib.rb create --replicas 0 192.168.1.108:6379 192.168.1.108:6380 192.168.1.108:6381

    进入redis-cli -p 6379 -c

    Cluster nodes 查看集群信息

    配置完成

    使用 StackExchange.Redis驱动连接到redis


    代码是我从Asp.net vnext Caching 程序集中copy下来的

    配置类型

     public class RedisCacheOptions
            {
            /// <summary>
            /// 连接配置
            /// </summary>
            public string Configuration { get; set; }
           /// <summary>
           /// 实例名字
           /// </summary>
            public string InstanceName { get; set; }
    
    
            }
      static void Main(string[] args)
                {
    
    
                string key = "myKey";
                object state = null;
                string value1 = "yyyyyyyyyyyyyy";
                byte[] value = Encoding.Default.GetBytes(value1);
                Stream valueStream;
    
                Console.WriteLine("Connecting to cache");
                var cache = new RedisCache(new RedisCacheOptions
                    {
                    InstanceName = "sessionId",
                    Configuration = "192.168.1.108:6379,192.168.1.108:6380,192.168.1.108:6381"
                    });
                Console.WriteLine("Connected");
    
                Console.WriteLine("Setting");
                valueStream = cache.Set(key, state, context =>
                {
                    context.Data.Write(value, 0, value.Length);
                });

    RedisCache 集体实现

       public class RedisCache : IDistributedCache
            {
            //Lua 脚本
            private const string SetScript = (@" 
                    redis.call('HMSET', KEYS[1], 'absexp', ARGV[1], 'sldexp', ARGV[2], 'data', ARGV[4])
                    if ARGV[3] ~= '-1' then
                      redis.call('EXPIRE', KEYS[1], ARGV[3]) 
                    end
                    return 1");
            //key
            private const string AbsoluteExpirationKey = "absexp";
            //key
            private const string SlidingExpirationKey = "sldexp";
            //key
            private const string DataKey = "data";
            private const long NotPresent = -1;
            private ConnectionMultiplexer _connection;
            private IDatabase _cache;
            private readonly RedisCacheOptions _options;
            private readonly string _instance;
            /// <summary>
            /// 初始化配置
            /// </summary>
            /// <param name="optionsAccessor"></param>
            public RedisCache(RedisCacheOptions optionsAccessor)
                {
                _options = optionsAccessor;
                _instance = optionsAccessor.InstanceName;
                }
            public void Connect()
                {
                if (_connection == null)
                    {
                    _connection = ConnectionMultiplexer.Connect(_options.Configuration);
                    _cache = _connection.GetDatabase();
                    }
                }
    
    
            /// <summary>
            /// set到Redis中
            /// </summary>
            /// <param name="key"></param>
            /// <param name="state"></param>
            /// <param name="create"></param>
            /// <returns></returns>
            public Stream Set(string key, object state, Action<ICacheContext> create)
                {
                Connect();
    
                var context = new CacheContext(key) { State = state };
                //设置绝对过期时间
                //context.SetAbsoluteExpiration(DateTimeOffset.Now.AddMilliseconds(22222));
                //设置滑动过期时间
                context.SetSlidingExpiration(TimeSpan.FromSeconds(22222));
                create(context);
                var value = context.GetBytes();
                //Lua脚本赋值
                var result = _cache.ScriptEvaluate(SetScript, new RedisKey[] { _instance + key },
                    new RedisValue[]
                    {
                        context.AbsoluteExpiration?.Ticks ?? NotPresent,
                        context.SlidingExpiration?.Ticks ?? NotPresent,
                        context.GetExpirationInSeconds() ?? NotPresent,
                        value
                    });
                return new MemoryStream(value, writable: false);
                }
    
            public bool TryGetValue(string key, out Stream value)
                {
                value = GetAndRefresh(key, getData: true);
                return value != null;
                }
    
            public void Refresh(string key)
                {
                var ignored = GetAndRefresh(key, getData: false);
                }
    
            private Stream GetAndRefresh(string key, bool getData)
                {
                Connect();
    
    
                RedisValue[] results;
                if (getData)
                    {
                    results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey, DataKey);
                    }
                else
                    {
                    results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey);
                    }
    
                if (results.Length >= 2)
                    {
                    DateTimeOffset? absExpr;
                    TimeSpan? sldExpr;
                    MapMetadata(results, out absExpr, out sldExpr);
                    Refresh(key, absExpr, sldExpr);
                    }
                if (results.Length >= 3 && results[2].HasValue)
                    {
                    return new MemoryStream(results[2], writable: false);
                    }
                return null;
                }
            private void MapMetadata(RedisValue[] results, out DateTimeOffset? absoluteExpiration, out TimeSpan? slidingExpiration)
                {
                absoluteExpiration = null;
                slidingExpiration = null;
                var absoluteExpirationTicks = (long?)results[0];
                if (absoluteExpirationTicks.HasValue && absoluteExpirationTicks.Value != NotPresent)
                    {
                    absoluteExpiration = new DateTimeOffset(absoluteExpirationTicks.Value, TimeSpan.Zero);
                    }
                var slidingExpirationTicks = (long?)results[1];
                if (slidingExpirationTicks.HasValue && slidingExpirationTicks.Value != NotPresent)
                    {
                    slidingExpiration = new TimeSpan(slidingExpirationTicks.Value);
                    }
                }
    
            /// <summary>
            /// 刷新缓存过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <param name="absExpr"></param>
            /// <param name="sldExpr"></param>
            private void Refresh(string key, DateTimeOffset? absExpr, TimeSpan? sldExpr)
                {
                TimeSpan? expr = null;
                if (sldExpr.HasValue)
                    {
                    if (absExpr.HasValue)
                        {
                        var relExpr = absExpr.Value - DateTimeOffset.Now;
                        expr = relExpr <= sldExpr.Value ? relExpr : sldExpr;
                        }
                    else
                        {
                        expr = sldExpr;
                        }
                    _cache.KeyExpire(_instance + key, expr);
                    // TODO: Error handling
                    }
                }
            /// <summary>
            /// 移除指定key
            /// </summary>
            /// <param name="key"></param>
            public void Remove(string key)
                {
                Connect();
                _cache.KeyDelete(_instance + key);
    
                }
            }

    运行结果

    源码:http://pan.baidu.com/s/1gdm8F9h

  • 相关阅读:
    WF4.0 Beta1 自定义跟踪
    WF4.0 Beta1 流程设计器与Activity Designer
    新版本工作流平台的 (二) 权限算法(组织结构部分)
    WF4.0 Beta1 WorkflowInvoker
    WF4.0 基础篇 (十) Collection 集合操作
    WF4.0 基础篇 (十五) TransactionScope 事物容器
    WF4.0 基础篇 (六) 数据的传递 Arguments 参数
    WF4B1 的Procedural Activity 之InvokeMethod , InvokeMethod<T> 使用
    WF4.0 Beta1 异常处理
    WF4.0 Beta1 变量 Variables
  • 原文地址:https://www.cnblogs.com/liek/p/4878123.html
Copyright © 2011-2022 走看看