本地及远程二级缓存

本地及远程二级缓存

上周将本地缓存切换到远程缓存后,导致系统运行缓慢,经分析是一个页面反复读取缓存数据。Reveiw代码,发现是开发人员对缓存调用不够规范,导致循环调用缓存。

代码遍布整个项目,修复成本较高,只能从底层的缓存框架解决。

经构思,觉得在远程缓存基础上增加本地缓存,默认本地缓存超时6秒,这样基本解决一次请求,相同的缓存反复请求远程缓存问题,修改如下:

1、请求缓存的时候,先请求本地缓存,如没有请求远程,远程有数据的时候,再本地缓存一份备份

2、设置缓存的时候,同时设置本地和远程缓存

3、省略本地缓存和远程缓存同步(因本地缓存设置过期时间非常短,只为了减少并发请求远程缓存,一般3-5秒左右)

缓存接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// <summary>
/// 缓存接口
/// </summary>
public interface ICache
{
    /// <summary>
    /// 从缓存中取得指定键的值
    /// </summary>
    /// <param name="type">指定的类型</param>
    /// <param name="key">指定的键值</param>
    /// <returns></returns>
    object Get(Type type, string key);
    /// <summary>
    /// 从缓存中取得指定键的值
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="key">指定的键值</param>
    /// <returns>指定键值的值</returns>
    T Get<T>(string key);
 
    /// <summary>
    /// 从缓存中取出对象,如果没有缓存调用acquire方法
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="key">键值</param>
    /// <param name="acquire">如果缓存中没有对象的处理方法,处理方法</param>
    /// <param name="cacheTime">如果缓存中没有对象的处理方法设置缓存过期时间</param>
    /// <returns>指定键值的值</returns>
    T Get<T>(string key, Func<T> acquire, TimeSpan cacheTime);
 
    /// <summary>
    /// 从缓存中取出对象,如果没有缓存调用acquire方法
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="key">键值</param>
    /// <param name="acquire">如果缓存中没有对象的处理方法,处理方法</param>
    /// <param name="expiredTime">缓存绝对过期时间</param>
    /// <returns>指定键值的值</returns>
    T Get<T>(string key, Func<T> acquire, DateTime expiredTime);
 
    /// <summary>
    /// 从缓存中取出对象,如果没有缓存调用acquire方法
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="key">键值</param>
    /// <param name="acquire">如果缓存中没有对象的处理方法,处理方法</param>
    /// <param name="cacheExpiration">预先定义的缓存策略类型</param>
    /// <returns>指定键值的值</returns>
    T Get<T>(string key, Func<T> acquire, CacheExpirationTypes cacheExpiration);
 
    /// <summary>
    /// 添加一个对象到到缓存,使用缺省过期时间
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="data">存储到缓存中的对象</param>
    /// <param name="dependencyKeys">父键值</param>
    void Set(string key, object data, params string[] dependencyKeys);
 
    /// <summary>
    /// 添加一个对象到到缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="data">存储到缓存中的对象</param>
    /// <param name="slidingTime">缓存时间</param>
    /// <param name="dependencyKeys">父键值</param>
    void Set(string key, object data, TimeSpan slidingTime, params string[] dependencyKeys);
 
    /// <summary>
    /// 添加一个绝对过期时间的对象到缓存
    /// </summary>
    /// <param name="key">缓存键值</param>
    /// <param name="data">缓存对象</param>
    /// <param name="expiredTime">绝对过期时间</param>
    /// <param name="dependencyKeys">父键值</param>
    void Set(string key, object data, DateTime expiredTime, params string[] dependencyKeys);
 
    /// <summary>
    /// 添加一个对象到到缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="data">存储到缓存中的对象</param>
    /// <param name="cacheExpiration">缓存过期类型</param>
    /// <param name="dependencyKeys">父键值</param>
    void Set(string key, object data, CacheExpirationTypes cacheExpiration, params string[] dependencyKeys);
 
    /// <summary>
    /// 添加文件依赖对象到缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="value">存储到缓存中的对象</param>
    /// <param name="dependencyFiles">依赖文件项</param>
    void SetFile(string key, object value, params string[] dependencyFiles);
 
    /// <summary>
    /// 添加文件依赖对象到缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="value">存储到缓存中的对象</param>
    /// <param name="expiredTime">绝对过期时间</param>
    /// <param name="dependencyFiles">依赖文件项</param>
    void SetFile(string key, object value, DateTime expiredTime, params string[] dependencyFiles);
 
    /// <summary>
    /// 添加文件依赖对象到缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <param name="value">存储到缓存中的对象</param>
    /// <param name="slidingTime">缓存持续时间</param>
    /// <param name="dependencyFiles">依赖文件项</param>
    void SetFile(string key, object value, TimeSpan slidingTime, params string[] dependencyFiles);
 
    /// <summary>
    /// 判断是否已经缓存
    /// </summary>
    /// <param name="key">键值</param>
    /// <returns>是否存在</returns>
    bool IsSet(string key);
 
    /// <summary>
    /// 移除缓存
    /// </summary>
    /// <param name="key">键值</param>
    void Remove(string key);
 
    /// <summary>
    /// 按模式移除缓存
    /// </summary>
    /// <param name="pattern">正则表达式模式</param>
    void RemoveByPattern(string pattern);
 
    /// <summary>
    /// 清空缓存
    /// </summary>
    void Clear();
}

修改的Redis缓存Get方法

 View Code

/// <summary>
/// 从缓存中取得指定键的值
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">指定的键值</param>
/// <returns>指定键值的值</returns>
public T Get<T>(string key)
{
key = GetKey(key);
if (_useLocal)
{
//先从本地获取缓存
var localValue = _localCache.Get(key);
if (localValue != null)
{
if (_debug)
Trace.WriteLine("Redis Cache Get from local:{0},Result:{1}".FormatWith(key, localValue.ToJson()));

return TypeConvert.ChangeType<T>(localValue);
}
}

Open();
var value = _connection.Strings.GetString(_dbNumber, key);
var jsonValue = _connection.Wait(value);
Trace.WriteLine("get:{0},result:{1}".FormatWith(key, jsonValue));
if (string.IsNullOrWhiteSpace(jsonValue))
{
RemoveKeyDependency(key);
return default(T);
}

var cachedValue = jsonValue.FromJson<T>();

if (_useLocal)
{
//设置本地缓存
_localCache.Set(key, cachedValue, DateTime.Now + TimeSpan.FromSeconds(_defaultLocalExpiredTime));
}

return cachedValue;
}


Set方法

 View Code

/// <summary>
/// 添加一个对象到到缓存
/// </summary>
/// <param name="key">键值</param>
/// <param name="data">存储到缓存中的对象</param>
/// <param name="slidingTime">缓存时间</param>
/// <param name="dependencyKeys"> </param>
public void Set(string key, object data, TimeSpan slidingTime, params string[] dependencyKeys)
{
key = GetKey(key);
if (data == null)
{
Remove(key);
return;
}

if (_useLocal)
{
//设置本地缓存
_localCache.Set(key, data,DateTime.Now + TimeSpan.FromSeconds(_defaultLocalExpiredTime));
}

Open();
_connection.Strings.Set(_dbNumber, key, data.ToJson(), (long)slidingTime.TotalSeconds);
Trace.WriteLine("Set:{0},value:{1}".FormatWith(key, data.ToJson()));
if (dependencyKeys != null && dependencyKeys.Length > 0)
AddKeyDependency(key, dependencyKeys);
}

  

 
 
 
标签: Cache
原文地址:https://www.cnblogs.com/Leo_wl/p/3334413.html