Redis羣集實現Asp.net Mvc分佈式Session

Session的缺點node

衆所周知Asp.net Session默認存儲在IIS中,IIS的重啓會致使Session丟失。redis

若是你的網站使用了session,當網站併發過大時可能引發溢出。緩存

 

配置Redis 集羣ruby

 


安裝Redissession

建立一個文件,進入該文件夾併發

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

tar -xvf redis-3.0.4.tar.gz 解壓文件lua

cd redis-3.0.4 進入解壓的文件spa

make && make install 安裝.net

建立三個文件夾

把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

相關文章
相關標籤/搜索