/// <summary> /// Redis 帮助类文件 /// </summary> public class RedisHelper : IDisposable { /// <summary> /// 针对Log4net的实例 /// </summary> private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// <summary> /// The seconds time out. /// 默认缓存过期时间单位秒 /// </summary> private int secondsTimeOut = 24 * 60 * 60; /// <summary> /// 给某个键对应的数据设置过期时间 /// </summary> /// <param name="key">键</param> /// <param name="seconds">过期时间</param> public void Expire(string key, int seconds) { try { this.redis.Expire(key, seconds); } catch(Exception ex) { var message = string.Format("设置过期时间出错"); Logger.Error(message, ex); } } /// <summary> /// 释放资源 /// </summary> public void Dispose() { if(this.redis != null) { this.redis.Dispose(); this.redis = null; } GC.Collect(); } private IEnumerable<string> SplitString(string strSource, string split) { return strSource.Split(split.ToArray()); } /// <summary> /// 设置单个实体 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">缓存建</param> /// <param name="t">缓存值</param> /// <param name="timeout">过期时间,单位秒,-1:不过期,0:默认过期时间:一天</param> public bool Set<T>(string key, T t, int timeout = -1) { try { if(timeout >= 0) { if(timeout > 0) { this.secondsTimeOut = timeout; } var dtTimeOut = DateTime.Now.AddSeconds(this.secondsTimeOut); return this.redis.Set(key, t, dtTimeOut); } return this.redis.Set(key, t); } catch(Exception ex) { string message = string.Format("设置Redis缓存出错"); Logger.Error(message, ex); } } /// <summary> /// 获取单个实体 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键值</param> public T Get<T>(string key) { try { return this.redis.Get<T>(key); } catch(Exception ex) { string message = string.Format("获取Redis缓存出错"); Logger.Error(message, ex); } } /// <summary> /// 删除 /// </summary> /// <param name="key">键值</param> public bool Remove(string key) { try { return this.redis.Remove(key); } catch(Exception ex) { string message = string.Format("删除Redis缓存出错"); Logger.Error(message, ex); } } /// <summary> /// 删除所有 /// </summary> public void RemoveAll() { var keyList = this.redis.GetAllKeys(); this.redis.RemoveAll(keyList); } /// <summary> /// 获取Redis的所有key /// </summary> public List<string> ListKey() { return this.redis.GetAllKeys(); } /// <summary> /// 添加一个对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键</param> /// <param name="t"></param> /// <param name="timeout">过期时间(单位为秒) -1:不过期,0:默认过期时间 一天</param> public bool Add<T>(string key, T t, int timeout = -1) { try { if(timeout >= 0) { if(timeout > 0) { this.secondsTimeOut = timeout; } this.redis.Expire(key, this.secondsTimeOut); } return this.redis.Add(key, t); } catch(Exception ex) { string message = string.Format("添加Redis缓存出错"); Logger.Error(message, ex); } } /// <summary> /// 根据IEnumerable数据添加链表 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键</param> /// <param name="values">值</param> /// <param name="timeout">过期时间 -1:不过期,0:默认过期时间:一天</param> public void AddList<T>(string key, IEnumerable<T> values, int timeout = -1) { try { IRedisTypedClient<T> iredisClient = this.redis.As<T>(); IRedisList<T> redisList = iredisClient.Lists[key]; redisList.AddRange(values); if(timeout > 0) { if(timeout > 0) { this.secondsTimeOut = timeout; } this.redis.Expire(key, this.secondsTimeOut); } iredisClient.Save(); } catch(Exception ex) { string message = string.Format("添加链表出错"); Logger.Error(message, ex); } } /// <summary> /// 添加单个实体到链表中 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键</param> /// <param name="Item"></param> /// <param name="timeout">过期时间 -1:不过期,0:默认过期时间:一天</param> public void AddEntityToList<T>(string key, T Item, int timeout = -1) { try { IRedisTypedClient<T> iredisClient = redis.As<T>(); IRedisList<T> redisList = iredisClient.Lists[key]; redisList.Add(Item); iredisClient.Save(); if(timeout >= 0) { if(timeout > 0) { this.secondsTimeOut = timeout; } this.redis.Expire(key, this.secondsTimeOut); } } catch(Exception ex) { string message = string.Format("添加单个的实体到链表中出错"); Logger.Error(message, ex); } } /// <summary> /// 获取链表 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键</param> public IEnumerable<T> GetList<T>(string key) { try { IRedisTypedClient<T> iredisClient = redis.As<T>(); return iredisClient.Lists[key]; } catch(Exception ex) { string message = string.Format("获取链表出错"); Logger.Error(message, ex); } } /// <summary> /// 在链表中删除单个实体 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">键</param> public void RemoveEntityFromList<T>(string key, T t) { try { IRedisTypedClient<T> iredisClient = this.redis.As<T>(); IRedisList<T> redisList = iredisClient.Lists[key]; redisList.RemoveValue(t); iredisClient.Save(); } catch(Exception ex) { string message = string.Format("删除链表中的单个实体出错"); Logger.Error(message, ex); } } /// <summary> /// 根据key移除整个链表 /// </summary> /// <param name="key">键</param> public void RemoveAllList<T>(string key) { try { IRedisTypedClient<T> iredisClient = this.redis.As<T>(); IRedisList<T> redisList = iredisClient.Lists[key]; redisList.RemoveAll(); iredisClient.Save(); } catch(Exception ex) { string message = string.Format("删除链表集合"); Logger.Error(message, ex); } } }本文出自GitHub开源网站
=================================
1、这两天研究Redis搞分布式session问题,网上找的资料都是用ServiceStack.Redis来实现的,但是在做性能测试的时候 发现最新的v4版本有限制每小时候最多请求6000次,因为官网开始商业化要收费了,好坑爹的说,还好我前期弄了个性能测试列子,不然上线以后出问题那就 麻烦了。后面找了个NServiceKit.Redis(好像就是ServiceStack.Redis的v3版本)来替代v4的收费版。
2、解决方案是 Redis+cookie方式实现记录用户登录状态
cookie:存放用户的ID,这个ID是经过加密的,并且后台可以通过密钥解密。
Redis:key/value 方式存储,key存放比如:user_1。 value存放用户实体对象。
3、先安装一个Redis,windows的版本在本地进行测试,后期上线更换linux系统的Redis替换一下ip就可以了。
4、添加一个Session管理类
public class SessionHelper { private const int secondsTimeOut = 60 * 20; //默认过期时间20分钟 单位秒 public RedisHelper Redis = new RedisHelper(false); public LoginUserInfo this[string key] { get { string webCookie = WebHelper.GetCookie(key); if (webCookie == "") { return null; } key = key + "_" + SecureHelper.AESDecrypt(webCookie); //距离过期时间还有多少秒 long l = Redis.TTL(key); if (l >= 0) { Redis.Expire(key, secondsTimeOut); } return Redis.Get<LoginUserInfo>(key); } set { SetSession(key, value); } } public void SetSession(string key, LoginUserInfo value) { if (string.IsNullOrWhiteSpace(key)) { throw new Exception("Key is Null or Epmty"); } WebHelper.SetCookie(key, SecureHelper.AESEncrypt(value.ID.ToString())); key = key + "_" + value.ID; Redis.Set<LoginUserInfo>(key, value, secondsTimeOut); } /// <summary> /// 移除Session /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Remove(string key) { var rs = Redis.Remove(key + "_" + SecureHelper.AESDecrypt(WebHelper.GetCookie(key))); WebHelper.DeleteCookie(key); return rs; } }
5、Redis操作类
public class RedisHelper : IDisposable { private RedisClient Redis = new RedisClient("127.0.0.1", 6379); //缓存池 PooledRedisClientManager prcm = new PooledRedisClientManager(); //默认缓存过期时间单位秒 public int secondsTimeOut = 20 * 60; /// <summary> /// 缓冲池 /// </summary> /// <param name="readWriteHosts"></param> /// <param name="readOnlyHosts"></param> /// <returns></returns> public static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts) { return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig { MaxWritePoolSize = readWriteHosts.Length * 5, MaxReadPoolSize = readOnlyHosts.Length * 5, AutoStart = true, }); } /// <summary> /// 构造函数 /// </summary> /// <param name="OpenPooledRedis">是否开启缓冲池</param> public RedisHelper(bool OpenPooledRedis = false) { if (OpenPooledRedis) { prcm = CreateManager(new string[] { "127.0.0.1:6379" }, new string[] { "127.0.0.1:6379" }); Redis = prcm.GetClient() as RedisClient; } } /// <summary> /// 距离过期时间还有多少秒 /// </summary> /// <param name="key"></param> /// <returns></returns> public long TTL(string key) { return Redis.Ttl(key); } /// <summary> /// 设置过期时间 /// </summary> /// <param name="key"></param> /// <param name="timeout"></param> public void Expire(string key,int timeout = 0) { if (timeout >= 0) { if (timeout > 0) { secondsTimeOut = timeout; } Redis.Expire(key, secondsTimeOut); } } #region Key/Value存储 /// <summary> /// 设置缓存 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">缓存建</param> /// <param name="t">缓存值</param> /// <param name="timeout">过期时间,单位秒,-1:不过期,0:默认过期时间</param> /// <returns></returns> public bool Set<T>(string key, T t, int timeout = 0) { Redis.Set<T>(key, t); if (timeout >= 0) { if (timeout > 0) { secondsTimeOut = timeout; } Redis.Expire(key, secondsTimeOut); } return true; } /// <summary> /// 获取 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public T Get<T>(string key) { return Redis.Get<T>(key); } /// <summary> /// 删除 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Remove(string key) { return Redis.Remove(key); } #endregion //释放资源 public void Dispose() { if (Redis != null) { Redis.Dispose(); Redis = null; } GC.Collect(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ServiceStack.Redis; namespace TestRedis { class RedisHelper:IDisposable { /*copyright@2013 All Rights Reserved * Author:Mars * Date:2013.08.27 * QQ:258248340 * servicestack.redis为github中的开源项目 * redis是一个典型的k/v型数据库 * redis共支持五种类型的数据 string,list,hash,set,sortedset * * string是最简单的字符串类型 * * list是字符串列表,其内部是用双向链表实现的,因此在获取/设置数据时可以支持正负索引 * 也可以将其当做堆栈结构使用 * * hash类型是一种字典结构,也是最接近RDBMS的数据类型,其存储了字段和字段值的映射,但字段值只能是 * 字符串类型,散列类型适合存储对象,建议使用对象类别和ID构成键名,使用字段表示对象属性,字 * 段值存储属性值,例如:car:2 price 500 ,car:2 color black,用redis命令设置散列时,命令格式 * 如下:HSET key field value,即key,字段名,字段值 * * set是一种集合类型,redis中可以对集合进行交集,并集和互斥运算 * * sorted set是在集合的基础上为每个元素关联了一个“分数”,我们能够 * 获得分数最高的前N个元素,获得指定分数范围内的元素,元素是不同的,但是"分数"可以是相同的 * set是用散列表和跳跃表实现的,获取数据的速度平均为o(log(N)) * * 需要注意的是,redis所有数据类型都不支持嵌套 * redis中一般不区分插入和更新操作,只是命令的返回值不同 * 在插入key时,如果不存在,将会自动创建 * * 在实际生产环境中,由于多线程并发的关系,建议使用连接池,本类只是用于测试简单的数据类型 */ /* * 以下方法为基本的设置数据和取数据 */ private static RedisClient redisCli = null; /// <summary> /// 建立redis长连接 /// </summary> /// 将此处的IP换为自己的redis实例IP,如果设有密码,第三个参数为密码,string 类型 public static void CreateClient(string hostIP,int port,string keyword) { if (redisCli == null) { redisCli = new RedisClient(hostIP, port, keyword); } } public static void CreateClient(string hostIP, int port) { if (redisCli == null) { redisCli = new RedisClient(hostIP, port); } } //private static RedisClient redisCli = new RedisClient("192.168.101.165", 6379, "123456"); /// <summary> /// 获取key,返回string格式 /// </summary> /// <param name="key"></param> /// <returns></returns> public static string getValueString(string key) { string value = redisCli.GetValue(key); return value; } /// <summary> /// 获取key,返回byte[]格式 /// </summary> /// <param name="key"></param> /// <returns></returns> public static byte[] getValueByte(string key) { byte[] value = redisCli.Get(key); return value; } /// <summary> /// 获得某个hash型key下的所有字段 /// </summary> /// <param name="hashId"></param> /// <returns></returns> public static List<string> GetHashFields(string hashId) { List<string> hashFields = redisCli.GetHashKeys(hashId); return hashFields; } /// <summary> /// 获得某个hash型key下的所有值 /// </summary> /// <param name="hashId"></param> /// <returns></returns> public static List<string> GetHashValues(string hashId) { List<string> hashValues = redisCli.GetHashKeys(hashId); return hashValues; } /// <summary> /// 获得hash型key某个字段的值 /// </summary> /// <param name="key"></param> /// <param name="field"></param> public static string GetHashField(string key, string field) { string value = redisCli.GetValueFromHash(key, field); return value; } /// <summary> /// 设置hash型key某个字段的值 /// </summary> /// <param name="key"></param> /// <param name="field"></param> /// <param name="value"></param> public static void SetHashField(string key, string field, string value) { redisCli.SetEntryInHash(key, field, value); } /// <summary> ///使某个字段增加 /// </summary> /// <param name="key"></param> /// <param name="field"></param> /// <returns></returns> public static void SetHashIncr(string key, string field, long incre) { redisCli.IncrementValueInHash(key, field, incre); } /// <summary> /// 向list类型数据添加成员,向列表底部(右侧)添加 /// </summary> /// <param name="Item"></param> /// <param name="list"></param> public static void AddItemToListRight(string list, string item) { redisCli.AddItemToList(list, item); } /// <summary> /// 向list类型数据添加成员,向列表顶部(左侧)添加 /// </summary> /// <param name="list"></param> /// <param name="item"></param> public static void AddItemToListLeft(string list, string item) { redisCli.LPush(list, Encoding.Default.GetBytes(item)); } /// <summary> /// 从list类型数据读取所有成员 /// </summary> public static List<string> GetAllItems(string list) { List<string> listMembers = redisCli.GetAllItemsFromList(list); return listMembers; } /// <summary> /// 从list类型数据指定索引处获取数据,支持正索引和负索引 /// </summary> /// <param name="list"></param> /// <returns></returns> public static string GetItemFromList(string list, int index) { string item = redisCli.GetItemFromList(list, index); return item; } /// <summary> /// 向列表底部(右侧)批量添加数据 /// </summary> /// <param name="list"></param> /// <param name="values"></param> public static void GetRangeToList(string list, List<string> values) { redisCli.AddRangeToList(list, values); } /// <summary> /// 向集合中添加数据 /// </summary> /// <param name="item"></param> /// <param name="set"></param> public static void GetItemToSet(string item, string set) { redisCli.AddItemToSet(item, set); } /// <summary> /// 获得集合中所有数据 /// </summary> /// <param name="set"></param> /// <returns></returns> public static HashSet<string> GetAllItemsFromSet(string set) { HashSet<string> items = redisCli.GetAllItemsFromSet(set); return items; } /// <summary> /// 获取fromSet集合和其他集合不同的数据 /// </summary> /// <param name="fromSet"></param> /// <param name="toSet"></param> /// <returns></returns> public static HashSet<string> GetSetDiff(string fromSet, params string[] toSet) { HashSet<string> diff = redisCli.GetDifferencesFromSet(fromSet, toSet); return diff; } /// <summary> /// 获得所有集合的并集 /// </summary> /// <param name="set"></param> /// <returns></returns> public static HashSet<string> GetSetUnion(params string[] set) { HashSet<string> union = redisCli.GetUnionFromSets(set); return union; } /// <summary> /// 获得所有集合的交集 /// </summary> /// <param name="set"></param> /// <returns></returns> public static HashSet<string> GetSetInter(params string[] set) { HashSet<string> inter = redisCli.GetIntersectFromSets(set); return inter; } /// <summary> /// 向有序集合中添加元素 /// </summary> /// <param name="set"></param> /// <param name="value"></param> /// <param name="score"></param> public static void AddItemToSortedSet(string set,string value,long score) { redisCli.AddItemToSortedSet(set,value,score); } /// <summary> /// 获得某个值在有序集合中的排名,按分数的降序排列 /// </summary> /// <param name="set"></param> /// <param name="value"></param> /// <returns></returns> public static int GetItemIndexInSortedSetDesc(string set, string value) { int index = redisCli.GetItemIndexInSortedSetDesc(set, value); return index; } /// <summary> /// 获得某个值在有序集合中的排名,按分数的升序排列 /// </summary> /// <param name="set"></param> /// <param name="value"></param> /// <returns></returns> public static int GetItemIndexInSortedSet(string set, string value) { int index = redisCli.GetItemIndexInSortedSet(set, value); return index; } /// <summary> /// 获得有序集合中某个值得分数 /// </summary> /// <param name="set"></param> /// <param name="value"></param> /// <returns></returns> public static double GetItemScoreInSortedSet(string set, string value) { double score = redisCli.GetItemScoreInSortedSet(set, value); return score; } /// <summary> /// 获得有序集合中,某个排名范围的所有值 /// </summary> /// <param name="set"></param> /// <param name="beginRank"></param> /// <param name="endRank"></param> /// <returns></returns> public static List<string> GetRangeFromSortedSet(string set,int beginRank, int endRank) { List<string> valueList=redisCli.GetRangeFromSortedSet(set,beginRank,endRank); return valueList; } /// <summary> /// 获得有序集合中,某个分数范围内的所有值,升序 /// </summary> /// <param name="set"></param> /// <param name="beginScore"></param> /// <param name="endScore"></param> /// <returns></returns> public static List<string> GetRangeFromSortedSet(string set, double beginScore, double endScore) { List<string> valueList = redisCli.GetRangeFromSortedSetByHighestScore(set, beginScore, endScore); return valueList; } /// <summary> /// 获得有序集合中,某个分数范围内的所有值,降序 /// </summary> /// <param name="set"></param> /// <param name="beginScore"></param> /// <param name="endScore"></param> /// <returns></returns> public static List<string> GetRangeFromSortedSetDesc(string set, double beginScore, double endScore) { List<string> vlaueList=redisCli.GetRangeFromSortedSetByLowestScore(set,beginScore,endScore); return vlaueList; } public void Dispose() { redisCli.Dispose(); } } }
==========================================
Redis主从服务部署
Redis服务器及应用