上周将本地缓存切换到远程缓存后,导致系统运行缓慢,经分析是一个页面反复读取缓存数据。Reveiw代码,发现是开发人员对缓存调用不够规范,导致循环调用缓存。
代码遍布整个项目,修复成本较高,只能从底层的缓存框架解决。
经构思,觉得在远程缓存基础上增加本地缓存,默认本地缓存超时6秒,这样基本解决一次请求,相同的缓存反复请求远程缓存问题,修改如下:
1、请求缓存的时候,先请求本地缓存,如没有请求远程,远程有数据的时候,再本地缓存一份备份
2、设置缓存的时候,同时设置本地和远程缓存
3、省略本地缓存和远程缓存同步(因本地缓存设置过期时间非常短,只为了减少并发请求远程缓存,一般3-5秒左右)
缓存接口:
////// 缓存接口 /// public interface ICache { ////// 从缓存中取得指定键的值 /// /// 指定的类型 /// 指定的键值 ///object Get(Type type, string key); /// /// 从缓存中取得指定键的值 /// ///类型 /// 指定的键值 ///指定键值的值 T Get(string key); /// /// 从缓存中取出对象,如果没有缓存调用acquire方法 /// ///对象类型 /// 键值 /// 如果缓存中没有对象的处理方法,处理方法 /// 如果缓存中没有对象的处理方法设置缓存过期时间 ///指定键值的值 T Get(string key, Func acquire, TimeSpan cacheTime); /// /// 从缓存中取出对象,如果没有缓存调用acquire方法 /// ///对象类型 /// 键值 /// 如果缓存中没有对象的处理方法,处理方法 /// 缓存绝对过期时间 ///指定键值的值 T Get(string key, Func acquire, DateTime expiredTime); /// /// 从缓存中取出对象,如果没有缓存调用acquire方法 /// ///对象类型 /// 键值 /// 如果缓存中没有对象的处理方法,处理方法 /// 预先定义的缓存策略类型 ///指定键值的值 T Get(string key, Func acquire, CacheExpirationTypes cacheExpiration); /// /// 添加一个对象到到缓存,使用缺省过期时间 /// /// 键值 /// 存储到缓存中的对象 /// 父键值 void Set(string key, object data, params string[] dependencyKeys); ////// 添加一个对象到到缓存 /// /// 键值 /// 存储到缓存中的对象 /// 缓存时间 /// 父键值 void Set(string key, object data, TimeSpan slidingTime, params string[] dependencyKeys); ////// 添加一个绝对过期时间的对象到缓存 /// /// 缓存键值 /// 缓存对象 /// 绝对过期时间 /// 父键值 void Set(string key, object data, DateTime expiredTime, params string[] dependencyKeys); ////// 添加一个对象到到缓存 /// /// 键值 /// 存储到缓存中的对象 /// 缓存过期类型 /// 父键值 void Set(string key, object data, CacheExpirationTypes cacheExpiration, params string[] dependencyKeys); ////// 添加文件依赖对象到缓存 /// /// 键值 /// 存储到缓存中的对象 /// 依赖文件项 void SetFile(string key, object value, params string[] dependencyFiles); ////// 添加文件依赖对象到缓存 /// /// 键值 /// 存储到缓存中的对象 /// 绝对过期时间 /// 依赖文件项 void SetFile(string key, object value, DateTime expiredTime, params string[] dependencyFiles); ////// 添加文件依赖对象到缓存 /// /// 键值 /// 存储到缓存中的对象 /// 缓存持续时间 /// 依赖文件项 void SetFile(string key, object value, TimeSpan slidingTime, params string[] dependencyFiles); ////// 判断是否已经缓存 /// /// 键值 ///是否存在 bool IsSet(string key); ////// 移除缓存 /// /// 键值 void Remove(string key); ////// 按模式移除缓存 /// /// 正则表达式模式 void RemoveByPattern(string pattern); ////// 清空缓存 /// void Clear(); }
修改的Redis缓存Get方法
1 ///2 /// 从缓存中取得指定键的值 3 /// 4 ///类型 5 /// 指定的键值 6 ///指定键值的值 7 public T Get(string key) 8 { 9 key = GetKey(key);10 if (_useLocal)11 {12 //先从本地获取缓存13 var localValue = _localCache.Get(key);14 if (localValue != null)15 {16 if (_debug)17 Trace.WriteLine("Redis Cache Get from local:{0},Result:{1}".FormatWith(key, localValue.ToJson()));18 19 return TypeConvert.ChangeType (localValue);20 }21 }22 23 Open();24 var value = _connection.Strings.GetString(_dbNumber, key);25 var jsonValue = _connection.Wait(value);26 Trace.WriteLine("get:{0},result:{1}".FormatWith(key, jsonValue));27 if (string.IsNullOrWhiteSpace(jsonValue))28 {29 RemoveKeyDependency(key);30 return default(T);31 }32 33 var cachedValue = jsonValue.FromJson ();34 35 if (_useLocal)36 {37 //设置本地缓存38 _localCache.Set(key, cachedValue, DateTime.Now + TimeSpan.FromSeconds(_defaultLocalExpiredTime));39 }40 41 return cachedValue;42 }
1 ///2 /// 添加一个对象到到缓存 3 /// 4 /// 键值 5 /// 存储到缓存中的对象 6 /// 缓存时间 7 /// 8 public void Set(string key, object data, TimeSpan slidingTime, params string[] dependencyKeys) 9 {10 key = GetKey(key);11 if (data == null)12 {13 Remove(key);14 return;15 }16 17 if (_useLocal)18 {19 //设置本地缓存20 _localCache.Set(key, data,DateTime.Now + TimeSpan.FromSeconds(_defaultLocalExpiredTime));21 }22 23 Open();24 _connection.Strings.Set(_dbNumber, key, data.ToJson(), (long)slidingTime.TotalSeconds);25 Trace.WriteLine("Set:{0},value:{1}".FormatWith(key, data.ToJson()));26 if (dependencyKeys != null && dependencyKeys.Length > 0)27 AddKeyDependency(key, dependencyKeys);28 }