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