Redis 安装 & 配置
本测试环境将在 CentOS 7 x64 上安装最新版本的 Redis。
1. 运行以下命令安装 Redis
$ wget http://download.redis.io/releases/redis-3.2.6.tar.gz
$ tar xzf redis-3.2.6.tar.gz
$ cd redis-3.2.6
$ make install
如果 CentOS 上提示 wget 命令未找到,则先安装 net-tools。
yum install net-tools
2. Redis 配置文件
1)开启守护程序
修改 daemonize 节点为 yes。
2)运行外部IP访问
配置 bind 节点为 0.0.0.0
本次示例只使用 Redis 的缓存 所以配置暂时只修改这两处即可。
3. 设置 Redis 开机自动启动
1)在 Redis 的源码包中找到 utils 目录
2) 将 redis_init_script 文件复制到 /etc/init.d 目录下并重命名为 redisd
cp redis_init_script /etc/init.d/redisd
3) 打开 redisd 修改部分配置。
1 #!/bin/sh
2 # chkconfig: 2345 90 10
3 # Simple Redis init.d script conceived to work on Linux systems
4 # as it does use of the /proc filesystem.
5
6 REDISPORT=6379
7 EXEC=/usr/local/bin/redis-server
8 CLIEXEC=/usr/local/bin/redis-cli
9
10 PIDFILE=/var/run/redis_${REDISPORT}.pid
11 CONF="/etc/redis/redis_${REDISPORT}.conf"
其中第二行 # chkconfig: 2345 90 10 需要另行添加。
- REDISPORT Redis 运行端口号;
- EXEC Redis 服务器命令文件路径(根据实际情况修改);
- CLIEXEC Redis 客户端命令文件路径(亦根据实际情况修改);
- CONF Redis 配置文件。
4)设置开机启动 & 启动、停止服务
#设置为开机自启动服务器 chkconfig redisd on #打开服务 service redisd start #关闭服务 service redisd stop
主:如果外部机器还访问不到 Redis 服务器,请将 6379 端口号加防火墙例外即可。
代码实现:
Common 包 接口定义 & 分布式缓存实例获取和配置
- IDistributedCache 接口
1 using System;
2
3 namespace Wlitsoft.Framework.Common.Core
4 {
5 /// <summary>
6 /// 分布式缓存接口。
7 /// </summary>
8 public interface IDistributedCache
9 {
10 /// <summary>
11 /// 获取缓存。
12 /// </summary>
13 /// <typeparam name="T">缓存类型。</typeparam>
14 /// <param name="key">缓存键值。</param>
15 /// <returns>获取到的缓存。</returns>
16 T Get<T>(string key);
17
18 /// <summary>
19 /// 设置缓存。
20 /// </summary>
21 /// <typeparam name="T">缓存类型。</typeparam>
22 /// <param name="key">缓存键值。</param>
23 /// <param name="value">要缓存的对象。</param>
24 void Set<T>(string key, T value);
25
26 /// <summary>
27 /// 设置缓存。
28 /// </summary>
29 /// <typeparam name="T">缓存类型。</typeparam>
30 /// <param name="key">缓存键值。</param>
31 /// <param name="value">要缓存的对象。</param>
32 /// <param name="expiredTime">过期时间。</param>
33 void Set<T>(string key, T value, TimeSpan expiredTime);
34
35 /// <summary>
36 /// 判断指定键值的缓存是否存在。
37 /// </summary>
38 /// <param name="key">缓存键值。</param>
39 /// <returns>一个布尔值,表示缓存是否存在。</returns>
40 bool Exists(string key);
41
42 /// <summary>
43 /// 移除指定键值的缓存。
44 /// </summary>
45 /// <param name="key">缓存键值。</param>
46 bool Remove(string key);
47
48 /// <summary>
49 /// 获取 Hash 表中的缓存。
50 /// </summary>
51 /// <typeparam name="T">缓存类型。</typeparam>
52 /// <param name="key">缓存键值。</param>
53 /// <param name="hashField">要获取的 hash 字段。</param>
54 /// <returns>获取到的缓存。</returns>
55 T GetHash<T>(string key, string hashField);
56
57 /// <summary>
58 /// 设置 缓存到 Hash 表。
59 /// </summary>
60 /// <typeparam name="T">缓存类型。</typeparam>
61 /// <param name="key">缓存键值。</param>
62 /// <param name="hashField">要设置的 hash 字段。</param>
63 /// <param name="hashValue">要设置的 hash 值。</param>
64 void SetHash<T>(string key, string hashField, T hashValue);
65
66 /// <summary>
67 /// 判断指定键值的 Hash 缓存是否存在。
68 /// </summary>
69 /// <param name="key">缓存键值。</param>
70 /// <param name="hashField">hash 字段。</param>
71 /// <returns>一个布尔值,表示缓存是否存在。</returns>
72 bool ExistsHash(string key, string hashField);
73
74 /// <summary>
75 /// 删除 hash 表中的指定字段的缓存。
76 /// </summary>
77 /// <param name="key">缓存键值。</param>
78 /// <param name="hashField">hash 字段。</param>
79 /// <returns>一个布尔值,表示缓存是否删除成功。</returns>
80 bool DeleteHash(string key, string hashField);
81 }
82 }
- App 类
1 /// <summary>
2 /// 获取分布式缓存。
3 /// </summary>
4 public static IDistributedCache DistributedCache { get; internal set; }
- AppBuilder 类
1 namespace Wlitsoft.Framework.Common
2 {
3 /// <summary>
4 /// 应用 构造。
5 /// </summary>
6 public class AppBuilder
7 {
8 #region 添加序列化者
9
10 /// <summary>
11 /// 添加序列化者。
12 /// </summary>
13 /// <param name="type">序列化类型。</param>
14 /// <param name="serializer">序列化者接口。</param>
15 public void AddSerializer(SerializeType type, ISerializer serializer)
16 {
17 #region 参数校验
18
19 if (serializer == null)
20 throw new ObjectNullException(nameof(serializer));
21
22 #endregion
23
24 App.SerializerService.SetSerializer(type, serializer);
25 }
26
27 #endregion
28
29 #region 添加日志记录者
30
31 /// <summary>
32 /// 添加日志记录者。
33 /// </summary>
34 /// <param name="name">日志记录者名称。</param>
35 /// <param name="logger">日志接口。</param>
36 public void AddLogger(string name, ILog logger)
37 {
38 #region 参数校验
39
40 if (string.IsNullOrEmpty(name))
41 throw new StringNullOrEmptyException(nameof(name));
42
43 if (logger == null)
44 throw new ObjectNullException(nameof(logger));
45
46 #endregion
47
48 App.LoggerService.SetLogger(name, logger);
49 }
50
51 #endregion
52
53 #region 设置分布式缓存
54
55 /// <summary>
56 /// 设置分布式缓存。
57 /// </summary>
58 /// <param name="cache">分布式缓存实例。</param>
59 /// <returns></returns>
60 public AppBuilder SetDistributedCache(IDistributedCache cache)
61 {
62 #region 参数校验
63
64 if (cache == null)
65 throw new ObjectNullException(nameof(cache));
66
67 #endregion
68
69 App.DistributedCache = cache;
70 return this;
71 }
72
73 #endregion
74 }
75 }
分布式缓存 Redis 实现
- RedisCache 类
1 using System;
2 using System.Linq;
3 using System.Threading;
4 using StackExchange.Redis;
5 using Wlitsoft.Framework.Common.Core;
6 using Wlitsoft.Framework.Common.Extension;
7 using Wlitsoft.Framework.Common.Exception;
8
9 namespace Wlitsoft.Framework.Caching.Redis
10 {
11 /// <summary>
12 /// Redis 缓存。
13 /// </summary>
14 public class RedisCache : IDistributedCache
15 {
16 #region 私有属性
17
18 //redis 连接实例。
19 private volatile ConnectionMultiplexer _connection;
20
21 //redis 缓存数据库实例。
22 private IDatabase _database;
23
24 //连接实例锁。
25 private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(1, 1);
26
27 //Redis 配置。
28 internal static RedisCacheConfiguration RedisCacheConfiguration;
29
30 #endregion
31
32 #region IDistributedCache 成员
33
34 /// <summary>
35 /// 获取缓存。
36 /// </summary>
37 /// <typeparam name="T">缓存类型。</typeparam>
38 /// <param name="key">缓存键值。</param>
39 /// <returns>获取到的缓存。</returns>
40 public T Get<T>(string key)
41 {
42 #region 参数校验
43
44 if (string.IsNullOrEmpty(key))
45 throw new StringNullOrEmptyException(nameof(key));
46
47 #endregion
48
49 this.Connect();
50 string result = this._database.StringGet(key);
51 if (string.IsNullOrEmpty(result))
52 return default(T);
53 return result.ToJsonObject<T>();
54 }
55
56 /// <summary>
57 /// 设置缓存。
58 /// </summary>
59 /// <typeparam name="T">缓存类型。</typeparam>
60 /// <param name="key">缓存键值。</param>
61 /// <param name="value">要缓存的对象。</param>
62 public void Set<T>(string key, T value)
63 {
64 #region 参数校验
65
66 if (string.IsNullOrEmpty(key))
67 throw new StringNullOrEmptyException(nameof(key));
68
69 if (value == null)
70 throw new ObjectNullException(nameof(value));
71
72 #endregion
73
74 this.Connect();
75 this._database.StringSet(key, value.ToJsonString());
76 }
77
78 /// <summary>
79 /// 设置缓存。
80 /// </summary>
81 /// <typeparam name="T">缓存类型。</typeparam>
82 /// <param name="key">缓存键值。</param>
83 /// <param name="value">要缓存的对象。</param>
84 /// <param name="expiredTime">过期时间。</param>
85 public void Set<T>(string key, T value, TimeSpan expiredTime)
86 {
87 #region 参数校验
88
89 if (string.IsNullOrEmpty(key))
90 throw new StringNullOrEmptyException(nameof(key));
91
92 if (value == null)
93 throw new ObjectNullException(nameof(value));
94
95 #endregion
96
97 this.Connect();
98 this._database.StringSet(key, value.ToJsonString(), expiredTime);
99 }
100
101 /// <summary>
102 /// 判断指定键值的缓存是否存在。
103 /// </summary>
104 /// <param name="key">缓存键值。</param>
105 /// <returns>一个布尔值,表示缓存是否存在。</returns>
106 public bool Exists(string key)
107 {
108 #region 参数校验
109
110 if (string.IsNullOrEmpty(key))
111 throw new StringNullOrEmptyException(nameof(key));
112
113 #endregion
114
115 this.Connect();
116 return this._database.KeyExists(key);
117 }
118
119 /// <summary>
120 /// 移除指定键值的缓存。
121 /// </summary>
122 /// <param name="key">缓存键值。</param>
123 public bool Remove(string key)
124 {
125 #region 参数校验
126
127 if (string.IsNullOrEmpty(key))
128 throw new StringNullOrEmptyException(nameof(key));
129
130 #endregion
131
132 this.Connect();
133 return this._database.KeyDelete(key);
134 }
135
136 /// <summary>
137 /// 获取 Hash 表中的缓存。
138 /// </summary>
139 /// <typeparam name="T">缓存类型。</typeparam>
140 /// <param name="key">缓存键值。</param>
141 /// <param name="hashField">要获取的 hash 字段。</param>
142 /// <returns>获取到的缓存。</returns>
143 public T GetHash<T>(string key, string hashField)
144 {
145 #region 参数校验
146
147 if (string.IsNullOrEmpty(key))
148 throw new StringNullOrEmptyException(nameof(key));
149
150 if (string.IsNullOrEmpty(hashField))
151 throw new StringNullOrEmptyException(nameof(hashField));
152
153 #endregion
154
155 this.Connect();
156 string value = this._database.HashGet(key, hashField);
157 if (string.IsNullOrEmpty(value))
158 return default(T);
159 return value.ToJsonObject<T>();
160 }
161
162 /// <summary>
163 /// 设置 缓存到 Hash 表。
164 /// </summary>
165 /// <typeparam name="T">缓存类型。</typeparam>
166 /// <param name="key">缓存键值。</param>
167 /// <param name="hashField">要设置的 hash 字段。</param>
168 /// <param name="hashValue">要设置的 hash 值。</param>
169 public void SetHash<T>(string key, string hashField, T hashValue)
170 {
171 #region 参数校验
172
173 if (string.IsNullOrEmpty(key))
174 throw new StringNullOrEmptyException(nameof(key));
175
176 if (string.IsNullOrEmpty(hashField))
177 throw new StringNullOrEmptyException(nameof(hashField));
178
179 if (hashValue == null)
180 throw new ObjectNullException(nameof(hashValue));
181
182 #endregion
183
184 this.Connect();
185 this._database.HashSet(key, hashField, hashValue.ToJsonString());
186 }
187
188 /// <summary>
189 /// 判断指定键值的 Hash 缓存是否存在。
190 /// </summary>
191 /// <param name="key">缓存键值。</param>
192 /// <param name="hashField">hash 字段。</param>
193 /// <returns>一个布尔值,表示缓存是否存在。</returns>
194 public bool ExistsHash(string key, string hashField)
195 {
196 #region 参数校验
197
198 if (string.IsNullOrEmpty(key))
199 throw new StringNullOrEmptyException(nameof(key));
200
201 if (string.IsNullOrEmpty(hashField))
202 throw new StringNullOrEmptyException(nameof(hashField));
203
204 #endregion
205
206 this.Connect();
207 return this._database.HashExists(key, hashField);
208 }
209
210 /// <summary>
211 /// 删除 hash 表中的指定字段的缓存。
212 /// </summary>
213 /// <param name="key">缓存键值。</param>
214 /// <param name="hashField">hash 字段。</param>
215 /// <returns>一个布尔值,表示缓存是否删除成功。</returns>
216 public bool DeleteHash(string key, string hashField)
217 {
218 #region 参数校验
219
220 if (string.IsNullOrEmpty(key))
221 throw new StringNullOrEmptyException(nameof(key));
222
223 if (string.IsNullOrEmpty(hashField))
224 throw new StringNullOrEmptyException(nameof(hashField));
225
226 #endregion
227
228 this.Connect();
229 return this._database.HashDelete(key, hashField);
230 }
231
232 #endregion
233
234 #region 私有方法
235
236 /// <summary>
237 /// 连接。
238 /// </summary>
239 private void Connect()
240 {
241 if (this._connection != null)
242 return;
243
244 this._connectionLock.Wait();
245 try
246 {
247 if (this._connection == null)
248 {
249 this._connection = ConnectionMultiplexer.Connect(this.GetConfigurationOptions());
250 this._database = this._connection.GetDatabase();
251 }
252 }
253 finally
254 {
255 this._connectionLock.Release();
256 }
257 }
258
259 private ConfigurationOptions GetConfigurationOptions()
260 {
261 #region 校验
262
263 if (RedisCacheConfiguration == null)
264 throw new ObjectNullException(nameof(RedisCacheConfiguration));
265
266 if (!RedisCacheConfiguration.HostAndPoints.Any())
267 throw new Exception("RedisCahce 的 HostAndPoints 不能为空");
268
269 #endregion
270
271 ConfigurationOptions options = new ConfigurationOptions();
272
273 foreach (string item in RedisCacheConfiguration.HostAndPoints)
274 options.EndPoints.Add(item);
275
276 options.ConnectRetry = RedisCacheConfiguration.ConnectRetry;
277 options.ConnectTimeout = RedisCacheConfiguration.ConnectTimeout;
278
279 return options;
280 }
281
282 #endregion
283
284 #region 析构函数
285
286 /// <summary>
287 /// 析构 <see cref="RedisCache"/> 类型的对象。
288 /// </summary>
289 ~RedisCache()
290 {
291 _connection?.Close();
292 }
293
294 #endregion
295 }
296 }